diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..78e124c52 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +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. + +**Desktop (please complete the following information):** + - OS: [e.g. Windows 10] + - Version [e.g. v2.06] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..11fc491ef --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore index c4f5de8c7..bac8fe436 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ src/*.o src/*.exe src/*.res +src/NUL diff --git a/README.md b/README.md index b6a360ade..c825e0c57 100644 --- a/README.md +++ b/README.md @@ -10,66 +10,67 @@ information, see the `LICENSE` file. The project maintainer is OBattler. +If you need a configuration manager for 86Box, use the [86Box Manager](https://github.com/86Box/86BoxManager), our +officially endorsed 86Box configuration manager, developed by Overdoze (daviunic). + Community --------- We operate an IRC channel and a Discord server for discussing anything related to retro computing and, of course, 86Box. We look forward to hearing from you! -[![Visit our IRC channel](https://kiwiirc.com/buttons/irc.rol.im/softhistory.png)](https://kiwiirc.com/client/irc.rol.im/?nick=86box|?#softhistory) +[![Visit our IRC channel](https://kiwiirc.com/buttons/irc.ringoflightning.net/softhistory.png)](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#softhistory) -[![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](https://discord.gg/Es3TnUH) +[![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](https://discord.gg/QXK9XTv) + +Getting started +--------------- +See [this](https://86box.github.io/gettingstarted) page on our website for a quick guide that should help you get started with the emulator. Building -------- In order to compile 86Box from this repository, please follow this step-by-step guide: -1. Download the development environment from http://tinyurl.com/de86box. - Afterwards, extract it to your desired location. Of course, also clone - the repository in your desired location. Downloading ZIPs is not recommended, - as it makes it more inconvenient to keep the code up-to-date. To avoid - issues, make sure neither path has spaces in it. -2. In the extracted environment folder, you will find a script called - `mingw32_shell.bat`. Launch it. There are other shell launching scripts - in there, but you should not use them. -3. Once launched, run `pacman -Syuu` in order to update the environment. - Depending on the state of the downloaded DE, you may need to run it twice - (once initially, and then again after re-entering the environment). Make sure - to keep the enviroment up-to-date by re-running the command periodically. -4. Once the environment is fully updated, `cd` into your cloned `86box\src` +1. Install the [MSYS2](https://www.msys2.org/) environment. The rest of the guide will refer to the directory that you install it to (C:\msys32 or C:\msys64 by default) as the MSYS2 root. +2. Launch your MSYS2 environment using the `MSYS2 MinGW 32-bit` shortcut. +3. Once launched, run `pacman -Syu` in order to update the environment. You may need to do this twice, just follow the on-screen instructions. Make sure you re-run `pacman -Syu` periodically to keep the environment up-to-date. +4. Run the following command to install all of the dependencies: `pacman -S gdb make git mingw-w64-i686-toolchain mingw-w64-i686-openal mingw-w64-i686-freetype mingw-w64-i686-SDL2 mingw-w64-i686-zlib mingw-w64-i686-libpng mingw-w64-i686-ghostscript`. Additionally, you will need to download the developer's pack of WinPcap [from here](https://www.winpcap.org/devel.htm), and extract it into `\mingw32\`. +5. Once the environment is fully updated and all dependencies are installed, `cd` into your cloned `86box\src` directory. -5. Run `make -jN -fmakefile.mingw` to start the actual compilation process. +6. Run `make -jN -f win/makefile.mingw` to start the actual compilation process. Substitute `N` with the number of threads you want to use for the compilation process. The optimal number depends entirely on your processor, and it is up to you to determine the optimal number. A good starting point is the total number of threads (AKA Logical Processors) you have available. -6. If the compilation succeeded (which it almost always should), you will find +7. If the compilation succeeded (which it almost always should), you will find `86Box.exe` in the src directory. -7. In order to test your fresh build, replace the `86Box.exe` in your current +8. In order to test your fresh build, replace the `86Box.exe` in your current 86Box enviroment with your freshly built one. If you do not have a pre-existing 86Box environment, download the latest successful build from - http://ci.86box.net, and the ROM set from http://tinyurl.com/rs20180320. -8. Enjoy using and testing the emulator! :) + http://ci.86box.net, and the ROM set from https://tinyurl.com/rs20191022. +9. Enjoy using and testing the emulator! :) If you encounter issues at any step or have additional questions, please join -the IRC channel and wait patiently for someone to help you. +the IRC channel or the appropriate channel on our Discord server and wait patiently for someone to help you. Nightly builds -------------- For your convenience, we compile a number of 86Box builds per revision on our Jenkins instance. -| Regular | Optimized | Experimental | -|:-------:|:---------:|:------------:| -|[![Build Status](http://ci.86box.net/job/86Box/badge/icon)](http://ci.86box.net/job/86Box)|[![Build Status](http://ci.86box.net/job/86Box-Optimized/badge/icon)](http://ci.86box.net/job/86Box-Optimized)|[![Build Status](http://ci.86box.net/job/86Box-Dev/badge/icon)](http://ci.86box.net/job/86Box-Dev) +| Regular | Debug | Optimized | Experimental | +|:-------:|:-----:|:---------:|:------------:| +|[![Build Status](http://ci.86box.net/job/86Box/badge/icon)](http://ci.86box.net/job/86Box)|[![Build Status](http://ci.86box.net/job/86Box-Debug/badge/icon)](http://ci.86box.net/job/86Box-Debug)|[![Build Status](http://ci.86box.net/job/86Box-Optimized/badge/icon)](http://ci.86box.net/job/86Box-Optimized)|[![Build Status](http://ci.86box.net/job/86Box-Dev/badge/icon)](http://ci.86box.net/job/86Box-Dev) ### Legend * **Regular** builds are compiled using the settings in the building guide above. Use these if you don't know which build to use. +* **Debug** builds are same as regular builds but include debug symbols. + If you don't need them, you don't need to use this build. * **Optimized** builds have the same feature set as regular builds, but are optimized for every modern Intel and AMD processor architecture, which might improve the emulator's performance in certain scenarios. * **Experimental (Dev)** builds are similar to regular builds but are compiled - certain unfinished features enabled. These builds are not optimized. + with certain unfinished features enabled. These builds are not optimized for maximum performance. Donations --------- diff --git a/nvr/430vx.nvr b/nvr/430vx.nvr deleted file mode 100644 index 0c9299c04..000000000 Binary files a/nvr/430vx.nvr and /dev/null differ diff --git a/nvr/440fx.nvr b/nvr/440fx.nvr deleted file mode 100644 index 7e93886f4..000000000 Binary files a/nvr/440fx.nvr and /dev/null differ diff --git a/nvr/586mc1.nvr b/nvr/586mc1.nvr deleted file mode 100644 index 8f66a8a3d..000000000 Binary files a/nvr/586mc1.nvr and /dev/null differ diff --git a/nvr/acer386.nvr b/nvr/acer386.nvr deleted file mode 100644 index 22bff6c1d..000000000 Binary files a/nvr/acer386.nvr and /dev/null differ diff --git a/nvr/acerm3a.nvr b/nvr/acerm3a.nvr deleted file mode 100644 index 4bd806175..000000000 Binary files a/nvr/acerm3a.nvr and /dev/null differ diff --git a/nvr/acerv35n.nvr b/nvr/acerv35n.nvr deleted file mode 100644 index 99f4431c8..000000000 Binary files a/nvr/acerv35n.nvr and /dev/null differ diff --git a/nvr/adgold.bin b/nvr/adgold.bin deleted file mode 100644 index 566bffc4a..000000000 Binary files a/nvr/adgold.bin and /dev/null differ diff --git a/nvr/ami286.nvr b/nvr/ami286.nvr deleted file mode 100644 index bfb993f2f..000000000 Binary files a/nvr/ami286.nvr and /dev/null differ diff --git a/nvr/ami386.nvr b/nvr/ami386.nvr deleted file mode 100644 index 225630115..000000000 Binary files a/nvr/ami386.nvr and /dev/null differ diff --git a/nvr/ami386dx_opti495.nvr b/nvr/ami386dx_opti495.nvr deleted file mode 100644 index dca4bd269..000000000 Binary files a/nvr/ami386dx_opti495.nvr and /dev/null differ diff --git a/nvr/ami486.nvr b/nvr/ami486.nvr deleted file mode 100644 index 705527986..000000000 Binary files a/nvr/ami486.nvr and /dev/null differ diff --git a/nvr/at.nvr b/nvr/at.nvr deleted file mode 100644 index b5c94c19f..000000000 Binary files a/nvr/at.nvr and /dev/null differ diff --git a/nvr/award286.nvr b/nvr/award286.nvr deleted file mode 100644 index 4a714c6cb..000000000 Binary files a/nvr/award286.nvr and /dev/null differ diff --git a/nvr/cmdpc30.nvr b/nvr/cmdpc30.nvr deleted file mode 100644 index 3e6551836..000000000 Binary files a/nvr/cmdpc30.nvr and /dev/null differ diff --git a/nvr/dell200.nvr b/nvr/dell200.nvr deleted file mode 100644 index b16f18490..000000000 Binary files a/nvr/dell200.nvr and /dev/null differ diff --git a/nvr/deskpro386.nvr b/nvr/deskpro386.nvr deleted file mode 100644 index 95ab63b2d..000000000 Binary files a/nvr/deskpro386.nvr and /dev/null differ diff --git a/nvr/dtk386.nvr b/nvr/dtk386.nvr deleted file mode 100644 index c8450f5ab..000000000 Binary files a/nvr/dtk386.nvr and /dev/null differ diff --git a/nvr/dtk486.nvr b/nvr/dtk486.nvr deleted file mode 100644 index 8b0adf564..000000000 Binary files a/nvr/dtk486.nvr and /dev/null differ diff --git a/nvr/endeavor.nvr b/nvr/endeavor.nvr deleted file mode 100644 index dfbb0f260..000000000 Binary files a/nvr/endeavor.nvr and /dev/null differ diff --git a/nvr/europc.nvr b/nvr/europc.nvr deleted file mode 100644 index 6757695ca..000000000 Binary files a/nvr/europc.nvr and /dev/null differ diff --git a/nvr/hot-433.nvr b/nvr/hot-433.nvr deleted file mode 100644 index 104e7113c..000000000 Binary files a/nvr/hot-433.nvr and /dev/null differ diff --git a/nvr/ibmps1_2011.nvr b/nvr/ibmps1_2011.nvr deleted file mode 100644 index 2029c7bf3..000000000 Binary files a/nvr/ibmps1_2011.nvr and /dev/null differ diff --git a/nvr/ibmps1_2121.nvr b/nvr/ibmps1_2121.nvr deleted file mode 100644 index 0501a368e..000000000 Binary files a/nvr/ibmps1_2121.nvr and /dev/null differ diff --git a/nvr/kn97.nvr b/nvr/kn97.nvr deleted file mode 100644 index 11001c513..000000000 Binary files a/nvr/kn97.nvr and /dev/null differ diff --git a/nvr/mb500n.nvr b/nvr/mb500n.nvr deleted file mode 100644 index d56f1378b..000000000 Binary files a/nvr/mb500n.nvr and /dev/null differ diff --git a/nvr/megapc.nvr b/nvr/megapc.nvr deleted file mode 100644 index 389276174..000000000 Binary files a/nvr/megapc.nvr and /dev/null differ diff --git a/nvr/mr386dx_opti495.nvr b/nvr/mr386dx_opti495.nvr deleted file mode 100644 index 9146987cb..000000000 Binary files a/nvr/mr386dx_opti495.nvr and /dev/null differ diff --git a/nvr/p54tp4xe.nvr b/nvr/p54tp4xe.nvr deleted file mode 100644 index 001a1cabc..000000000 Binary files a/nvr/p54tp4xe.nvr and /dev/null differ diff --git a/nvr/p55t2p4.nvr b/nvr/p55t2p4.nvr deleted file mode 100644 index 2361f6871..000000000 Binary files a/nvr/p55t2p4.nvr and /dev/null differ diff --git a/nvr/p55tp4n.nvr b/nvr/p55tp4n.nvr deleted file mode 100644 index 0c7ab65fc..000000000 Binary files a/nvr/p55tp4n.nvr and /dev/null differ diff --git a/nvr/p55tp4xe.nvr b/nvr/p55tp4xe.nvr deleted file mode 100644 index 8f8a83106..000000000 Binary files a/nvr/p55tp4xe.nvr and /dev/null differ diff --git a/nvr/p55tvp4.nvr b/nvr/p55tvp4.nvr deleted file mode 100644 index 922d78644..000000000 Binary files a/nvr/p55tvp4.nvr and /dev/null differ diff --git a/nvr/p55va.nvr b/nvr/p55va.nvr deleted file mode 100644 index c168d258b..000000000 Binary files a/nvr/p55va.nvr and /dev/null differ diff --git a/nvr/p5sp4.nvr b/nvr/p5sp4.nvr deleted file mode 100644 index e1d2c3a9b..000000000 Binary files a/nvr/p5sp4.nvr and /dev/null differ diff --git a/nvr/pc1512.nvr b/nvr/pc1512.nvr deleted file mode 100644 index b1f758b3e..000000000 Binary files a/nvr/pc1512.nvr and /dev/null differ diff --git a/nvr/pc1640.nvr b/nvr/pc1640.nvr deleted file mode 100644 index 7171e74fc..000000000 Binary files a/nvr/pc1640.nvr and /dev/null differ diff --git a/nvr/pc200.nvr b/nvr/pc200.nvr deleted file mode 100644 index 367d633e9..000000000 --- a/nvr/pc200.nvr +++ /dev/null @@ -1 +0,0 @@ -ÿ#ÿÿ!ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file diff --git a/nvr/pc200.nvr.bak b/nvr/pc200.nvr.bak deleted file mode 100644 index 5279898e2..000000000 Binary files a/nvr/pc200.nvr.bak and /dev/null differ diff --git a/nvr/pc2086.nvr b/nvr/pc2086.nvr deleted file mode 100644 index 40f563600..000000000 Binary files a/nvr/pc2086.nvr and /dev/null differ diff --git a/nvr/pc3086.nvr b/nvr/pc3086.nvr deleted file mode 100644 index f340d66ae..000000000 Binary files a/nvr/pc3086.nvr and /dev/null differ diff --git a/nvr/plato.nvr b/nvr/plato.nvr deleted file mode 100644 index 521d8198c..000000000 Binary files a/nvr/plato.nvr and /dev/null differ diff --git a/nvr/px386.nvr b/nvr/px386.nvr deleted file mode 100644 index c33bb9714..000000000 Binary files a/nvr/px386.nvr and /dev/null differ diff --git a/nvr/r418.nvr b/nvr/r418.nvr deleted file mode 100644 index 6b625e340..000000000 Binary files a/nvr/r418.nvr and /dev/null differ diff --git a/nvr/revenge.nvr b/nvr/revenge.nvr deleted file mode 100644 index 7592cfc6a..000000000 Binary files a/nvr/revenge.nvr and /dev/null differ diff --git a/nvr/sis496.nvr b/nvr/sis496.nvr deleted file mode 100644 index 90264989f..000000000 Binary files a/nvr/sis496.nvr and /dev/null differ diff --git a/nvr/tandy1000hx.bin b/nvr/tandy1000hx.bin deleted file mode 100644 index e69de4f70..000000000 Binary files a/nvr/tandy1000hx.bin and /dev/null differ diff --git a/nvr/tandy1000sl2.bin b/nvr/tandy1000sl2.bin deleted file mode 100644 index e69de4f70..000000000 Binary files a/nvr/tandy1000sl2.bin and /dev/null differ diff --git a/nvr/thor.nvr b/nvr/thor.nvr deleted file mode 100644 index 78eb4f242..000000000 Binary files a/nvr/thor.nvr and /dev/null differ diff --git a/nvr/vli486sv2g.nvr b/nvr/vli486sv2g.nvr deleted file mode 100644 index 36437f7c5..000000000 Binary files a/nvr/vli486sv2g.nvr and /dev/null differ diff --git a/nvr/win486.nvr b/nvr/win486.nvr deleted file mode 100644 index 97221385a..000000000 Binary files a/nvr/win486.nvr and /dev/null differ diff --git a/src/86box.h b/src/86box.h index eaac682d3..477051461 100644 --- a/src/86box.h +++ b/src/86box.h @@ -8,13 +8,13 @@ * * Main include file for the application. * - * Version: @(#)86box.h 1.0.23 2018/05/25 + * Version: @(#)86box.h 1.0.36 2019/12/05 * * Authors: Miran Grca, - * Fred N. van Kempen, + *f Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_86BOX_H # define EMU_86BOX_H @@ -29,8 +29,13 @@ /* Version info. */ #define EMU_NAME "86Box" #define EMU_NAME_W L"86Box" -#define EMU_VERSION "2.00" -#define EMU_VERSION_W L"2.00" +#ifdef RELEASE_BUILD +#define EMU_VERSION "2.07" +#define EMU_VERSION_W L"2.07" +#else +#define EMU_VERSION "2.10" +#define EMU_VERSION_W L"2.10" +#endif /* Filename and pathname info. */ #define CONFIG_FILE L"86box.cfg" @@ -92,11 +97,12 @@ extern int vid_cga_contrast, /* (C) video */ force_43, /* (C) video */ gfxcard; /* (C) graphics/video card */ extern int serial_enabled[], /* (C) enable serial ports */ - lpt_enabled, /* (C) enable LPT ports */ - bugger_enabled; /* (C) enable ISAbugger */ + bugger_enabled, /* (C) enable ISAbugger */ + isamem_type[], /* (C) enable ISA mem cards */ + isartc_type; /* (C) enable ISA RTC card */ extern int sound_is_float, /* (C) sound uses FP values */ GAMEBLASTER, /* (C) sound option */ - GUS, /* (C) sound option */ + GUS, GUSMAX, /* (C) sound option */ SSI2001, /* (C) sound option */ voodoo_enabled; /* (C) video option */ extern uint32_t mem_size; /* (C) memory size */ @@ -104,10 +110,17 @@ extern int cpu_manufacturer, /* (C) cpu manufacturer */ cpu, /* (C) cpu type */ cpu_use_dynarec, /* (C) cpu uses/needs Dyna */ enable_external_fpu; /* (C) enable external FPU */ -extern int enable_sync; /* (C) enable time sync */ +extern int time_sync; /* (C) enable time sync */ extern int network_type; /* (C) net provider type */ extern int network_card; /* (C) net interface num */ -extern char network_host[512]; /* (C) host network intf */ +extern char network_host[522]; /* (C) host network intf */ +extern int hdd_format_type; /* (C) hard disk file format */ +#ifdef USE_DISCORD +extern int enable_discord; /* (C) enable Discord integration */ +#endif + +extern int is_pentium; /* TODO: Move back to cpu/cpu.h when it's figured out, + how to remove that hack from the ET4000/W32p. */ #ifdef ENABLE_LOG_TOGGLES @@ -123,7 +136,9 @@ extern int nic_do_log; extern wchar_t exe_path[1024]; /* path (dir) of executable */ extern wchar_t usr_path[1024]; /* path (dir) of user data */ extern wchar_t cfg_path[1024]; /* full path of config file */ +#ifndef USE_NEW_DYNAREC extern FILE *stdlog; /* file to log output to */ +#endif extern int scrnsz_x, /* current screen size, X */ scrnsz_y; /* current screen size, Y */ extern int efscrnsz_y; @@ -158,6 +173,16 @@ extern void pc_thread(void *param); extern void pc_start(void); extern void pc_onesec(void); +extern uint16_t get_last_addr(void); + +/* This is for external subtraction of cycles; + should be in cpu.c but I put it here to avoid + having to include cpu.c everywhere. */ +extern void sub_cycles(int c); + +extern double isa_timing; +extern int io_delay; + #ifdef __cplusplus } #endif diff --git a/src/Makefile.local b/src/Makefile.local index 6ac2b5f97..9774208a7 100644 --- a/src/Makefile.local +++ b/src/Makefile.local @@ -10,7 +10,7 @@ # settings, so we can avoid changing the main one for all of # our local setups. # -# Version: @(#)Makefile.local 1.0.15 2018/07/19 +# Version: @(#)Makefile.local 1.0.22 2019/10/20 # # Author: Fred N. van Kempen, # @@ -35,13 +35,15 @@ STUFF := # -DENABLE_VRAM_DUMP enables Video Ram dumping. # -DENABLE_LOG_BREAKPOINT enables extra logging. # Root logging: +# -DENABLE_APM_LOG=N sets logging level at N. # -DENABLE_BUGGER_LOG=N sets logging level at N. # -DENABLE_CONFIG_LOG=N sets logging level at N. # -DENABLE_DEVICE_LOG=N sets logging level at N. -# -DENABLE_KEYBOARD_AMSTRAD_LOG=N sets logging level at N. -# -DENABLE_KEYBOARD_AT_LOG=N sets logging level at N. -# -DENABLE_KEYBOARD_LOG=N sets logging level at N. # -DENABLE_IO_LOG=N sets logging level at N. +# -DENABLE_PIIX_LOG=N sets logging level at N. +# -DENABLE_ISAMEM_LOG=N sets logging level at N. +# -DENABLE_ISARTC_LOG=N sets logging level at N. +# -DENABLE_KEYBOARD_AT_LOG=N sets logging level at N. # -DENABLE_MEM_LOG=N sets logging level at N. # -DENABLE_MOUSE_LOG=N sets logging level at N. # -DENABLE_MOUSE_BUS_LOG=N sets logging level at N. @@ -51,26 +53,33 @@ STUFF := # -DENABLE_PC_LOG=N sets logging level at N. # -DENABLE_PCI_LOG=N sets logging level at N. # -DENABLE_PIC_LOG=N sets logging level at N. -# -DENABLE_PIIX_LOG=N sets logging level at N. # -DENABLE_ROM_LOG=N sets logging level at N. # -DENABLE_SERIAL_LOG=N sets logging level at N. # -DENABLE_VNC_LOG=N sets logging level at N. +# -DENABLE_VNC_KEYMAP_LOG=N sets logging level at N. # cdrom/ logging: # -DENABLE_CDROM_LOG=N sets logging level at N. +# -DENABLE_CDROM_DOSBOX_LOG=N sets logging level at N. # -DENABLE_CDROM_IMAGE_LOG=N sets logging level at N. # cpu/ logging: # -DENABLE_386_LOG=N sets logging level at N. # -DENABLE_386_DYNAREC_LOG=N sets logging level at N. # -DENABLE_808X_LOG=N sets logging level at N. +# -DENABLE_FPU_LOG=N sets logging level at N. # -DENABLE_X86SEG_LOG=N sets logging level at N. +# cpu_new/ logging: +# -DENABLE_386_COMMON_LOG=N sets logging level at N. +# chipset/ logging: +# -DENABLE_NEAT_LOG=N sets logging level at N. # disk/ logging: # -DENABLE_ESDI_AT_LOG=N sets logging level at N. # -DENABLE_ESDI_MCA_LOG=N sets logging level at N. # -DENABLE_HDC_LOG=N sets logging level at N. # -DENABLE_HDD_IMAGE_LOG=N sets logging level at N. # -DENABLE_IDE_LOG=N sets logging level at N. -# -DENABLE_MFM_AT_LOG=N sets logging level at N. -# -DENABLE_MFM_XT_LOG=N sets logging level at N. +# -DENABLE_SFF_LOG=N sets logging level at N. +# -DENABLE_ST506_AT_LOG=N sets logging level at N. +# -DENABLE_ST506_XT_LOG=N sets logging level at N. # -DENABLE_XTA_LOG=N sets logging level at N. # -DENABLE_ZIP_LOG=N sets logging level at N. # floppy/ logging: @@ -82,29 +91,33 @@ STUFF := # -DENABLE_IMD_LOG=N sets logging level at N. # -DENABLE_IMG_LOG=N sets logging level at N. # -DENABLE_JSON_LOG=N sets logging level at N. +# -DENABLE_MFM_LOG=N sets logging level at N. # -DENABLE_TD0_LOG=N sets logging level at N. # machine/ logging: # -DENABLE_AMSTRAD_LOG=N sets logging level at N. # -DENABLE_EUROPC_LOG=N sets logging level at N. +# -DENABLE_M24VID_LOG=N sets logging level at N. # -DENABLE_MACHINE_LOG=N sets logging level at N. # -DENABLE_PS1_HDC_LOG=N sets logging level at N. # -DENABLE_PS2_MCA_LOG=N sets logging level at N. +# -DENABLE_TANDY_LOG=N sets logging level at N. # -DENABLE_T1000_LOG=N sets logging level at N. # -DENABLE_T3100E_LOG=N sets logging level at N. -# -DENABLE_TANDY_LOG=N sets logging level at N. # network/ logging: +# -DENABLE_3COM503_LOG=N sets logging level at N. +# -DENABLE_DP8390_LOG=N sets logging level at N. # -DENABLE_NETWORK_LOG=N sets logging level at N. # -DENABLE_NIC_LOG=N sets logging level at N. # -DENABLE_PCAP_LOG=N sets logging level at N. # -DENABLE_SLIRP_LOG=N sets logging level at N. +# -DENABLE_WD_LOG=N sets logging level at N. # scsi/ logging: # -DENABLE_AHA154X_LOG=N sets logging level at N. # -DENABLE_BUSLOGIC_LOG=N sets logging level at N. -# -DENABLE_NCR5380_LOG=N sets logging level at N. -# -DENABLE_NCR53C810_LOG=N sets logging level at N. -# -DENABLE_SCSI_LOG=N sets logging level at N. -# -DENABLE_SCSI_BUS_LOG=N sets logging level at N. +# -DENABLE_SCSI_CDROM_LOG=N sets logging level at N. # -DENABLE_SCSI_DISK_LOG=N sets logging level at N. +# -DENABLE_NCR5380_LOG=N sets logging level at N. +# -DENABLE_NCR53C8XX_LOG=N sets logging level at N. # -DENABLE_X54X_LOG=N sets logging level at N. # sound/ logging: # -DENABLE_ADLIB_LOG=N sets logging level at N. @@ -118,20 +131,26 @@ STUFF := # video/ logging: # -DENABLE_ATI28800_LOG=N sets logging level at N. # -DENABLE_MACH64_LOG=N sets logging level at N. +# -DENABLE_COMPAQ_CGA_LOG=N sets logging level at N. # -DENABLE_ET4000W32_LOG=N sets logging level at N. -# -DENABLE_NV_RIVA_LOG=N sets logging level at N. -# -DENABLE_NVIDIA_LOG=N sets logging level at N. +# -DENABLE_HT216_LOG=N sets logging level at N. +# -DENABLE_ICD2061_LOG=N sets logging level at N. +# -DENABLE_IM1024_LOG=N sets logging level at N. +# -DENABLE_PGC_LOG=N sets logging level at N. # -DENABLE_S3_VIRGE_LOG=N sets logging level at N. # -DENABLE_VID_TABLE_LOG=N sets logging level at N. # -DENABLE_VOODOO_LOG=N sets logging level at N. # -DENABLE_VRAM_DUMP=N sets logging level at N. # win/ logging: +# -DENABLE_WIN_LOG=N sets logging level at N. # -DENABLE_D2D_LOG=N sets logging level at N. # -DENABLE_DDRAW_LOG=N sets logging level at N. # -DENABLE_DYNLD_LOG=N sets logging level at N. # -DENABLE_JOYSTICK_LOG=N sets logging level at N. +# -DENABLE_LOG_BREAKPOINT=N sets logging level at N. +# -DENABLE_LOG_TOGGLES=N sets logging level at N. # -DENABLE_SDL_LOG=N sets logging level at N. -# -DENABLE_WIN_LOG=N sets logging level at N. +# -DENABLE_SETTINGS_LOG=N sets logging level at N. EXTRAS := diff --git a/src/apm.c b/src/apm.c new file mode 100644 index 000000000..1ec2fb6de --- /dev/null +++ b/src/apm.c @@ -0,0 +1,149 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Advanced Power Management emulation. + * + * Version: @(#)apm.c 1.0.0 2019/05/12 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "device.h" +#include "io.h" + + +typedef struct +{ + uint8_t cmd, + stat; +} apm_t; + + +#ifdef ENABLE_APM_LOG +int apm_do_log = ENABLE_APM_LOG; + + +static void +apm_log(const char *fmt, ...) +{ + va_list ap; + + if (apm_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define apm_log(fmt, ...) +#endif + + +static void +apm_out(uint16_t port, uint8_t val, void *p) +{ + apm_t *apm = (apm_t *) p; + + apm_log("[%04X:%08X] APM write: %04X = %02X (BX = %04X, CX = %04X)\n", CS, cpu_state.pc, port, val, BX, CX); + + port &= 0x0001; + + if (port == 0x0000) { + apm->cmd = val; + + switch (apm->cmd) { + case 0x07: /* Set Power State */ + if (CH == 0x00) switch (CX) { + case 0x0000: +#ifdef ENABLE_APM_LOG + apm_log("APM Set Power State: APM Enabled\n"); +#endif + break; + case 0x0001: +#ifdef ENABLE_APM_LOG + apm_log("APM Set Power State: Standby\n"); +#endif + break; + case 0x0002: +#ifdef ENABLE_APM_LOG + apm_log("APM Set Power State: Suspend\n"); +#endif + break; + case 0x0003: /* Off */ +#ifdef ENABLE_APM_LOG + apm_log("APM Set Power State: Off\n"); +#endif + exit(-1); + break; + } + break; + } + } else + apm->stat = val; +} + + +static uint8_t +apm_in(uint16_t port, void *p) +{ + apm_t *apm = (apm_t *) p; + + apm_log("[%04X:%08X] APM read: %04X = FF\n", CS, cpu_state.pc, port); + + port &= 0x0001; + + if (port == 0x0000) + return apm->cmd; + else + return apm->stat; +} + + +static void +apm_close(void *p) +{ + apm_t *dev = (apm_t *)p; + + free(dev); +} + + +static void +*apm_init(const device_t *info) +{ + apm_t *apm = (apm_t *) malloc(sizeof(apm_t)); + memset(apm, 0, sizeof(apm_t)); + + io_sethandler(0x00b2, 0x0002, apm_in, NULL, NULL, apm_out, NULL, NULL, apm); + + return apm; +} + + +const device_t apm_device = +{ + "Advanced Power Management", + 0, + 0, + apm_init, + apm_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/apm.h b/src/apm.h new file mode 100644 index 000000000..3f0e34780 --- /dev/null +++ b/src/apm.h @@ -0,0 +1,43 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ISA Bus (de)Bugger expansion card + * sold as a DIY kit in the late 1980's in The Netherlands. + * This card was a assemble-yourself 8bit ISA addon card for + * PC and AT systems that had several tools to aid in low- + * level debugging (mostly for faulty BIOSes, bootloaders + * and system kernels...) + * + * Definitions for the Advanced Power Management emulation. + * + * Version: @(#)apm.h 1.0.0 2019/05/12 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#ifndef APM_H +# define APM_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables. */ +extern const device_t apm_device; + + +/* Functions. */ + +#ifdef __cplusplus +} +#endif + + +#endif /*APM_H*/ diff --git a/src/apm_new.c b/src/apm_new.c new file mode 100644 index 000000000..a0963cade --- /dev/null +++ b/src/apm_new.c @@ -0,0 +1,121 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Advanced Power Management emulation. + * + * Version: @(#)apm.c 1.0.0 2019/05/12 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu_new/cpu.h" +#include "device.h" +#include "io.h" + + +typedef struct +{ + uint8_t cmd, + stat; +} apm_t; + + +#ifdef ENABLE_APM_LOG +int apm_do_log = ENABLE_APM_LOG; + + +static void +apm_log(const char *fmt, ...) +{ + va_list ap; + + if (apm_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define apm_log(fmt, ...) +#endif + + +static void +apm_out(uint16_t port, uint8_t val, void *p) +{ + apm_t *apm = (apm_t *) p; + + apm_log("[%04X:%08X] APM write: %04X = %02X (BX = %04X, CX = %04X)\n", CS, cpu_state.pc, port, val, BX, CX); + + port &= 0x0001; + + if (port == 0x0000) apm->cmd = val; + else apm->stat = val; + + smi_line = 1; +} + + +static uint8_t +apm_in(uint16_t port, void *p) +{ + apm_t *apm = (apm_t *) p; + + apm_log("[%04X:%08X] APM read: %04X = FF\n", CS, cpu_state.pc, port); + + port &= 0x0001; + + if (port == 0x0000) + return apm->cmd; + else + return apm->stat; +} + + +static void +apm_close(void *p) +{ + apm_t *dev = (apm_t *)p; + + free(dev); +} + + +static void +*apm_init(const device_t *info) +{ + apm_t *apm = (apm_t *) malloc(sizeof(apm_t)); + memset(apm, 0, sizeof(apm_t)); + + io_sethandler(0x00b2, 0x0002, apm_in, NULL, NULL, apm_out, NULL, NULL, apm); + + return apm; +} + + +const device_t apm_device = +{ + "Advanced Power Management", + 0, + 0, + apm_init, + apm_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/bugger.c b/src/bugger.c index 0619a0bb0..cd2d843d9 100644 --- a/src/bugger.c +++ b/src/bugger.c @@ -44,7 +44,7 @@ * configuration register (CTRL_SPCFG bit set) but have to * remember that stuff first... * - * Version: @(#)bugger.c 1.0.12 2018/04/29 + * Version: @(#)bugger.c 1.0.13 2018/10/17 * * Author: Fred N. van Kempen, * Copyright 1989-2018 Fred N. van Kempen. @@ -93,22 +93,22 @@ extern void ui_sb_bugui(char *__str); #ifdef ENABLE_BUGGER_LOG int bugger_do_log = ENABLE_BUGGER_LOG; -#endif static void -bugger_log(const char *format, ...) +bugger_log(const char *fmt, ...) { -#ifdef ENABLE_BUGGER_LOG va_list ap; if (bugger_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define bugger_log(fmt, ...) +#endif /* Update the system's UI with the actual Bugger status. */ diff --git a/src/cassette/cassette.c b/src/cassette/cassette.c new file mode 100644 index 000000000..b9ba8a7ca --- /dev/null +++ b/src/cassette/cassette.c @@ -0,0 +1,203 @@ +/************************************************************************ + + 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 +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../ppi.h" +#include "../ui.h" +#include "../plat.h" +#include "pzx.h" +#include "cassette.h" + +typedef struct cassette_t +{ + uint8_t motor; /* Motor status */ + pzxfile_t pzx; + int cycles_last; /* Cycle count at last cassette poll */ + +} cassette_t; + +wchar_t cassettefn[256]; + +static cassette_t *st_cas; + + +#ifdef ENABLE_CASSETTE_LOG +int cassette_do_log = ENABLE_CASSETTE_LOG; + + +static void +cassette_log(const char *fmt, ...) +{ + va_list ap; + + if (cassette_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cassette_log(fmt, ...) +#endif + + +/* 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(wchar_t *fn) +{ + FILE *fp; + unsigned char magic[8]; + + if (!fn) + return; + + fp = plat_fopen(fn, L"rb"); + if (!fp) { + /* Warn user? */ + cassette_log("Failed to open cassette input %s\n", fn); + 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)) { + wchar_t *result; + + result = pzx_open(&st_cas->pzx, fp); + + if (result) { + cassette_log("Failed to open %s as PZX: %s\n", + fn, result); + fclose(fp); + return; + } + wcscpy(cassettefn, fn); + } +} + + +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 + (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed / 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) { + cassette_log("Start cassette motor\n"); + st_cas->cycles_last = -1; + } + if (st_cas->motor && !on) { + cassette_log("Stop cassette motor\n"); + st_cas->cycles_last = -1; + } + st_cas->motor = on; +} + + +static void +*cassette_init(const device_t *info) +{ + cassette_t *cas = (cassette_t *)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); +} + + +const device_t cassette_device = { + "IBM PC 5150 Cassette", + 0, + 0, + cassette_init, + cassette_close, + NULL, + NULL, + NULL, + NULL +}; + diff --git a/src/cassette/cassette.h b/src/cassette/cassette.h new file mode 100644 index 000000000..cf7712811 --- /dev/null +++ b/src/cassette/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 wchar_t cassettefn[256]; + +extern const device_t cassette_device; + +uint8_t cassette_input(void); +void cassette_set_motor(uint8_t on); +void cassette_eject(void); +void cassette_load(wchar_t *filename); diff --git a/src/cassette/pzx.c b/src/cassette/pzx.c new file mode 100644 index 000000000..c7d16d36e --- /dev/null +++ b/src/cassette/pzx.c @@ -0,0 +1,414 @@ +/************************************************************************ + + 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 +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../ui.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. */ + + +#ifdef ENABLE_PZX_LOG +int pzx_do_log = ENABLE_PZX_LOG; + + +static void +pzx_log(const char *fmt, ...) +{ + va_list ap; + + if (pzx_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pzx_log(fmt, ...) +#endif + +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 wchar_t +*pzx_check_version(FILE *fp) +{ + uint8_t *block; + static wchar_t message[80]; + + rewind(fp); + while ((block = pzx_load_block(fp))) { + if (!memcmp(block, "PZXT", 4)) { + pzx_log("PZX version %d.%d\n", block[8], block[9]); + if (block[8] != 1) { + swprintf(message, 80, L"Unsupported PZX version %d.%d\n", block[8], block[9]); + free(block); + return message; + } + } + free(block); + } + rewind(fp); + return NULL; +} + + +wchar_t +*pzx_open(pzxfile_t *pzx, FILE *fp) +{ + wchar_t *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; + pzx_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; + pzx_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; + pzx_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; + } + } + return pzx->level; +} + + + diff --git a/src/cassette/pzx.h b/src/cassette/pzx.h new file mode 100644 index 000000000..a642a0688 --- /dev/null +++ b/src/cassette/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 */ +wchar_t *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/cdrom/cdrom.c b/src/cdrom/cdrom.c index 4ab96d37a..6c19233a7 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -6,14 +6,13 @@ * * This file is part of the 86Box distribution. * - * Implementation of the CD-ROM drive with SCSI(-like) - * commands, for both ATAPI and SCSI usage. + * Generic CD-ROM drive core. * - * Version: @(#)cdrom.c 1.0.48 2018/05/28 + * Version: @(#)cdrom.c 1.0.9 2019/12/13 * * Author: Miran Grca, * - * Copyright 2016-2018 Miran Grca. + * Copyright 2018,2019 Miran Grca. */ #include #include @@ -25,742 +24,114 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../config.h" -#include "../timer.h" -#include "../device.h" -#include "../piix.h" -#include "../scsi/scsi.h" -#include "../nvr.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" -#include "../plat.h" -#include "../sound/sound.h" -#include "../ui.h" #include "cdrom.h" #include "cdrom_image.h" -#include "cdrom_null.h" +#include "../plat.h" +#include "../sound/sound.h" -/* Bits of 'status' */ -#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 +/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: + there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start + of the audio while audio still plays. With an absolute conversion, the counter is fine. */ +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) -/* Bits of 'error' */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* Media change request */ +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 #define MIN_SEEK 2000 #define MAX_SEEK 333333 -#define cdbufferb dev->buffer - - -cdrom_t *cdrom[CDROM_NUM]; -cdrom_image_t cdrom_image[CDROM_NUM]; -cdrom_drive_t cdrom_drives[CDROM_NUM]; -uint8_t atapi_cdrom_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -uint8_t scsi_cdrom_drives[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - #pragma pack(push,1) -static struct -{ - uint8_t opcode; - uint8_t polled; - uint8_t reserved2[2]; - uint8_t class; - uint8_t reserved3[2]; - uint16_t len; - uint8_t control; -} *gesn_cdb; -#pragma pack(pop) +typedef struct { + uint8_t user_data[2048], + ecc[288]; +} m1_data_t; -#pragma pack(push,1) -static struct -{ - uint16_t len; - uint8_t notification_class; - uint8_t supported_events; -} *gesn_event_header; +typedef struct { + uint8_t sub_header[8], + user_data[2328]; +} m2_data_t; + +typedef union { + m1_data_t m1_data; + m2_data_t m2_data; + uint8_t raw_data[2336]; +} sector_data_t; + +typedef struct { + uint8_t sync[12]; + uint8_t header[4]; + sector_data_t data; +} sector_raw_data_t; + +typedef union { + sector_raw_data_t sector_data; + uint8_t raw_data[2352]; +} sector_t; + +typedef struct { + sector_t sector; + uint8_t c2[296]; + uint8_t subchannel_raw[96]; + uint8_t subchannel_q[16]; + uint8_t subchannel_rw[96]; +} cdrom_sector_t; + +typedef union { + cdrom_sector_t cdrom_sector; + uint8_t buffer[2856]; +} sector_buffer_t; #pragma pack(pop) -/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ -const uint8_t cdrom_command_flags[0x100] = -{ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ - IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ - 0, /* 0x02 */ - IMPLEMENTED | ALLOW_UA, /* 0x03 */ - 0, 0, 0, 0, /* 0x04-0x07 */ - IMPLEMENTED | CHECK_READY, /* 0x08 */ - 0, 0, /* 0x09-0x0A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ - 0, 0, 0, 0, 0, 0, /* 0x0C-0x11 */ - IMPLEMENTED | ALLOW_UA, /* 0x12 */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ - 0, /* 0x14 */ - IMPLEMENTED, /* 0x15 */ - 0, 0, 0, 0, /* 0x16-0x19 */ - IMPLEMENTED, /* 0x1A */ - IMPLEMENTED | CHECK_READY, /* 0x1B */ - 0, 0, /* 0x1C-0x1D */ - IMPLEMENTED | CHECK_READY, /* 0x1E */ - 0, 0, 0, 0, 0, 0, /* 0x1F-0x24 */ - IMPLEMENTED | CHECK_READY, /* 0x25 */ - 0, 0, /* 0x26-0x27 */ - IMPLEMENTED | CHECK_READY, /* 0x28 */ - 0, 0, /* 0x29-0x2A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ - 0, 0, 0, /* 0x2C-0x2E */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F */ - 0, 0, /* 0x40-0x41 */ - IMPLEMENTED | CHECK_READY, /* 0x42 */ - IMPLEMENTED | CHECK_READY, /* 0x43 - Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS - NOTE: The ATAPI reference says otherwise, but I think this is a question of - interpreting things right - the UNIT ATTENTION condition we have here - is a tradition from not ready to ready, by definition the drive - eventually becomes ready, make the condition go away. */ - IMPLEMENTED | CHECK_READY, /* 0x44 */ - IMPLEMENTED | CHECK_READY, /* 0x45 */ - IMPLEMENTED | ALLOW_UA, /* 0x46 */ - IMPLEMENTED | CHECK_READY, /* 0x47 */ - IMPLEMENTED | CHECK_READY, /* 0x48 */ - 0, /* 0x49 */ - IMPLEMENTED | ALLOW_UA, /* 0x4A */ - IMPLEMENTED | CHECK_READY, /* 0x4B */ - 0, 0, /* 0x4C-0x4D */ - IMPLEMENTED | CHECK_READY, /* 0x4E */ - 0, 0, /* 0x4F-0x50 */ - IMPLEMENTED | CHECK_READY, /* 0x51 */ - IMPLEMENTED | CHECK_READY, /* 0x52 */ - 0, 0, /* 0x53-0x54 */ - IMPLEMENTED, /* 0x55 */ - 0, 0, 0, 0, /* 0x56-0x59 */ - IMPLEMENTED, /* 0x5A */ - 0, 0, 0, 0, 0, /* 0x5B-0x5F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x6F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9F */ - 0, 0, 0, 0, 0, /* 0xA0-0xA4 */ - IMPLEMENTED | CHECK_READY, /* 0xA5 */ - 0, 0, /* 0xA6-0xA7 */ - IMPLEMENTED | CHECK_READY, /* 0xA8 */ - 0, 0, 0, 0, /* 0xA9-0xAC */ - IMPLEMENTED | CHECK_READY, /* 0xAD */ - 0, /* 0xAE */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ - 0, 0, 0, 0, /* 0xB0-0xB3 */ - IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB4 */ - 0, 0, 0, /* 0xB5-0xB7 */ - IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB8 */ - IMPLEMENTED | CHECK_READY, /* 0xB9 */ - IMPLEMENTED | CHECK_READY, /* 0xBA */ - IMPLEMENTED, /* 0xBB */ - IMPLEMENTED | CHECK_READY, /* 0xBC */ - IMPLEMENTED, /* 0xBD */ - IMPLEMENTED | CHECK_READY, /* 0xBE */ - IMPLEMENTED | CHECK_READY, /* 0xBF */ - 0, 0, /* 0xC0-0xC1 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC3-0xCC */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCD */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCE-0xD9 */ - IMPLEMENTED | SCSI_ONLY, /* 0xDA */ - 0, 0, 0, 0, 0, /* 0xDB-0xDF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0-0xEF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF0-0xFF */ -}; - -static uint64_t cdrom_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | - GPMODEP_CDROM_PAGE | - GPMODEP_CDROM_AUDIO_PAGE | - GPMODEP_CAPABILITIES_PAGE | - GPMODEP_ALL_PAGES); +static int cdrom_sector_size; +static uint8_t raw_buffer[2856]; /* Needs to be the same size as sector_buffer_t in the structs. */ +static uint8_t extra_buffer[296]; -static const mode_sense_pages_t cdrom_mode_sense_pages_default = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } -} }; - -static const mode_sense_pages_t cdrom_mode_sense_pages_default_scsi = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } -} }; - -static const mode_sense_pages_t cdrom_mode_sense_pages_changeable = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } -} }; - -uint8_t cdrom_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - - -static void cdrom_command_complete(cdrom_t *dev); - -static void cdrom_mode_sense_load(cdrom_t *dev); - -static void cdrom_init(cdrom_t *dev); -void cdrom_phase_callback(cdrom_t *dev); +cdrom_t cdrom[CDROM_NUM]; #ifdef ENABLE_CDROM_LOG -int cdrom_do_log = ENABLE_CDROM_LOG; -#endif +int cdrom_do_log = ENABLE_CDROM_LOG; -static void -cdrom_log(const char *format, ...) +void +cdrom_log(const char *fmt, ...) { -#ifdef ENABLE_CDROM_LOG va_list ap; if (cdrom_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define cdrom_log(fmt, ...) #endif -} - - -int -find_cdrom_for_channel(uint8_t channel) -{ - uint8_t i = 0; - - for (i = 0; i < CDROM_NUM; i++) { - if ((cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) && (cdrom_drives[i].ide_channel == channel)) - return i; - } - return 0xff; -} - - -void -build_atapi_cdrom_map() -{ - uint8_t i = 0; - - memset(atapi_cdrom_drives, 0xff, 8); - - for (i = 0; i < 8; i++) - atapi_cdrom_drives[i] = find_cdrom_for_channel(i); -} - - -int -find_cdrom_for_scsi_id(uint8_t scsi_id) -{ - uint8_t i = 0; - - for (i = 0; i < CDROM_NUM; i++) { - if ((cdrom_drives[i].bus_type == CDROM_BUS_SCSI) && (cdrom_drives[i].scsi_device_id == scsi_id)) - return i; - } - return 0xff; -} - - -void -build_scsi_cdrom_map() -{ - uint8_t i = 0; - - memset(scsi_cdrom_drives, 0xff, 16); - - for (i = 0; i < 16; i++) - scsi_cdrom_drives[i] = find_cdrom_for_scsi_id(i); -} - - -static void -cdrom_set_callback(cdrom_t *dev) -{ - if (dev && dev->drv && (dev->drv->bus_type != CDROM_BUS_SCSI)) - ide_set_callback(dev->drv->ide_channel >> 1, dev->callback); -} - - -void -cdrom_set_signature(cdrom_t *dev) -{ - if (!dev) - return; - dev->phase = 1; - dev->request_length = 0xEB14; -} - - -static void -cdrom_init(cdrom_t *dev) -{ - if (!dev) - return; - - /* Tell the cdrom_t struct what cdrom_drives element corresponds to it. */ - dev->drv = &(cdrom_drives[dev->id]); - - /* Do a reset (which will also rezero it). */ - cdrom_reset(dev); - - /* Configure the drive. */ - dev->requested_blocks = 1; - - dev->drv->bus_mode = 0; - if (dev->drv->bus_type >= CDROM_BUS_ATAPI) - dev->drv->bus_mode |= 2; - if (dev->drv->bus_type < CDROM_BUS_SCSI) - dev->drv->bus_mode |= 1; - cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); - dev->cdb_len = 12; - - dev->sense[0] = 0xf0; - dev->sense[7] = 10; - dev->status = READY_STAT | DSC_STAT; - dev->pos = 0; - dev->packet_status = 0xff; - cdrom_sense_key = cdrom_asc = cdrom_ascq = dev->unit_attention = 0; - dev->cur_speed = dev->drv->speed; - cdrom_mode_sense_load(dev); -} - - -static int -cdrom_supports_pio(cdrom_t *dev) -{ - return (dev->drv->bus_mode & 1); -} - - -static int -cdrom_supports_dma(cdrom_t *dev) -{ - return (dev->drv->bus_mode & 2); -} - - -/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ -static int -cdrom_current_mode(cdrom_t *dev) -{ - if (!cdrom_supports_pio(dev) && !cdrom_supports_dma(dev)) - return 0; - if (cdrom_supports_pio(dev) && !cdrom_supports_dma(dev)) { - cdrom_log("CD-ROM %i: Drive does not support DMA, setting to PIO\n", dev->id); - return 1; - } - if (!cdrom_supports_pio(dev) && cdrom_supports_dma(dev)) - return 2; - if (cdrom_supports_pio(dev) && cdrom_supports_dma(dev)) { - cdrom_log("CD-ROM %i: Drive supports both, setting to %s\n", dev->id, - (dev->features & 1) ? "DMA" : "PIO", - dev->id); - return (dev->features & 1) ? 2 : 1; - } - - return 0; -} - - -/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int -cdrom_CDROM_PHASE_to_scsi(cdrom_t *dev) -{ - if (dev->status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; -} - - -/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ -int -cdrom_atapi_phase_to_scsi(cdrom_t *dev) -{ - if (dev->status & 8) { - switch (dev->phase & 3) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - case 3: - return 7; - } - } else { - if ((dev->phase & 3) == 3) - return 3; - else - return 4; - } - - return 0; -} int cdrom_lba_to_msf_accurate(int lba) { - int temp_pos; + int pos; int m, s, f; - temp_pos = lba + 150; - f = temp_pos % 75; - temp_pos -= f; - temp_pos /= 75; - s = temp_pos % 60; - temp_pos -= s; - temp_pos /= 60; - m = temp_pos; + pos = lba + 150; + f = pos % 75; + pos -= f; + pos /= 75; + s = pos % 60; + pos -= s; + pos /= 60; + m = pos; return ((m << 16) | (s << 8) | f); } -uint32_t -cdrom_mode_sense_get_channel(cdrom_t *dev, int channel) -{ - return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; -} - - -uint32_t -cdrom_mode_sense_get_volume(cdrom_t *dev, int channel) -{ - return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; -} - - -static void -cdrom_mode_sense_load(cdrom_t *dev) -{ - FILE *f; - wchar_t file_name[512]; - int i; - - memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (cdrom_mode_sense_pages_default.pages[i][1] != 0) { - if (dev->drv->bus_type == CDROM_BUS_SCSI) - memcpy(dev->ms_pages_saved.pages[i], - cdrom_mode_sense_pages_default_scsi.pages[i], - cdrom_mode_sense_pages_default_scsi.pages[i][1] + 2); - else - memcpy(dev->ms_pages_saved.pages[i], - cdrom_mode_sense_pages_default.pages[i], - cdrom_mode_sense_pages_default.pages[i][1] + 2); - } - } - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); - else - swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"rb"); - if (f) { - fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); - fclose(f); - } -} - - -static void -cdrom_mode_sense_save(cdrom_t *dev) -{ - FILE *f; - wchar_t file_name[512]; - - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); - else - swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"wb"); - if (f) { - fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); - fclose(f); - } -} - - -int -cdrom_read_capacity(cdrom_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - int size = 0; - - size = dev->handler->size(dev->id) - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 8; /* 2048 = 0x0800 */ - *len = 8; - - return 1; -} - - -/*SCSI Mode Sense 6/10*/ -static uint8_t -cdrom_mode_sense_read(cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) -{ - switch (page_control) { - case 0: - case 3: - return dev->ms_pages_saved.pages[page][pos]; - break; - case 1: - return cdrom_mode_sense_pages_changeable.pages[page][pos]; - break; - case 2: - if (dev->drv->bus_type == CDROM_BUS_SCSI) - return cdrom_mode_sense_pages_default_scsi.pages[page][pos]; - else - return cdrom_mode_sense_pages_default.pages[page][pos]; - break; - } - - return 0; -} - - -static uint32_t -cdrom_mode_sense(cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) -{ - uint8_t page_control = (type >> 6) & 3; - int i = 0, j = 0; - - uint8_t msplen; - - type &= 0x3f; - - if (block_descriptor_len) { - buf[pos++] = 1; /* Density code. */ - buf[pos++] = 0; /* Number of blocks (0 = all). */ - buf[pos++] = 0; - buf[pos++] = 0; - buf[pos++] = 0; /* Reserved. */ - buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ - buf[pos++] = 8; - buf[pos++] = 0; - } - - for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (cdrom_mode_sense_page_flags & (1LL << dev->current_page_code)) { - buf[pos++] = cdrom_mode_sense_read(dev, page_control, i, 0); - msplen = cdrom_mode_sense_read(dev, page_control, i, 1); - buf[pos++] = msplen; - cdrom_log("CD-ROM %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); - for (j = 0; j < msplen; j++) { - if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { - if (j & 1) - buf[pos++] = ((dev->drv->speed * 176) & 0xff); - else - buf[pos++] = ((dev->drv->speed * 176) >> 8); - } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && (j <= 13)) { - if (j & 1) - buf[pos++] = ((dev->cur_speed * 176) & 0xff); - else - buf[pos++] = ((dev->cur_speed * 176) >> 8); - } else - buf[pos++] = cdrom_mode_sense_read(dev, page_control, i, 2 + j); - } - } - } - } - - return pos; -} - - -static void -cdrom_update_request_length(cdrom_t *dev, int len, int block_len) -{ - int32_t bt, min_len = 0; - - dev->max_transfer_len = dev->request_length; - - /* For media access commands, make sure the requested DRQ length matches the block length. */ - switch (dev->current_cdb[0]) { - case 0x08: - case 0x28: - case 0xa8: - case 0xb9: - case 0xbe: - /* Make sure total length is not bigger than sum of the lengths of - all the requested blocks. */ - bt = (dev->requested_blocks * block_len); - if (len > bt) - len = bt; - - min_len = block_len; - - if (len <= block_len) { - /* Total length is less or equal to block length. */ - if (dev->max_transfer_len < block_len) { - /* Transfer a minimum of (block size) bytes. */ - dev->max_transfer_len = block_len; - dev->packet_len = block_len; - break; - } - } - default: - dev->packet_len = len; - break; - } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ - if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) - dev->max_transfer_len &= 0xfffe; - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ - if (!dev->max_transfer_len) - dev->max_transfer_len = 65534; - - if ((len <= dev->max_transfer_len) && (len >= min_len)) - dev->request_length = dev->max_transfer_len = len; - else if (len > dev->max_transfer_len) - dev->request_length = dev->max_transfer_len; - - return; -} - - static double cdrom_get_short_seek(cdrom_t *dev) { @@ -825,7 +196,7 @@ cdrom_get_long_seek(cdrom_t *dev) } -static double +double cdrom_seek_time(cdrom_t *dev) { uint32_t diff = dev->seek_diff; @@ -842,2334 +213,758 @@ cdrom_seek_time(cdrom_t *dev) } -static double -cdrom_bus_speed(cdrom_t *dev) +void +cdrom_stop(cdrom_t *dev) { - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ - return 0.0; - } else { - if (cdrom_current_mode(dev) == 2) - return 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ - else - return 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ - } -} - - -static void -cdrom_command_bus(cdrom_t *dev) -{ - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 1LL * CDROM_TIME; - cdrom_set_callback(dev); -} - - -static void -cdrom_command_common(cdrom_t *dev) -{ - double bytes_per_second, period; - double dusec; - - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 0LL; - - cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->cur_speed); - - if (dev->packet_status == CDROM_PHASE_COMPLETE) { - cdrom_phase_callback(dev); - dev->callback = 0LL; - } else { - switch(dev->current_cdb[0]) { - case GPCMD_REZERO_UNIT: - case 0x0b: - case 0x2b: - /* Seek time is in us. */ - period = cdrom_seek_time(dev); - cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", - dev->id, (int64_t) period); - period = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) period); - cdrom_set_callback(dev); - return; - case 0x08: - case 0x28: - case 0xa8: - /* Seek time is in us. */ - period = cdrom_seek_time(dev); - cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", - dev->id, (int64_t) period); - period = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) period); - case 0x25: - case 0x42: - case 0x43: - case 0x44: - case 0x51: - case 0x52: - case 0xad: - case 0xb8: - case 0xb9: - case 0xbe: - if (dev->current_cdb[0] == 0x42) - dev->callback += 200LL * CDROM_TIME; - /* Account for seek time. */ - bytes_per_second = 176.0 * 1024.0; - bytes_per_second *= (double) dev->cur_speed; - break; - default: - bytes_per_second = cdrom_bus_speed(dev); - if (bytes_per_second == 0.0) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ - return; - } - break; - } - - period = 1000000.0 / bytes_per_second; - cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); - period = period * (double) (dev->packet_len); - cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); - dusec = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) dusec); - } - cdrom_set_callback(dev); -} - - -static void -cdrom_command_complete(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_COMPLETE; - cdrom_command_common(dev); -} - - -static void -cdrom_command_read(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_DATA_IN; - cdrom_command_common(dev); - dev->total_read = 0; -} - - -static void -cdrom_command_read_dma(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_DATA_IN_DMA; - cdrom_command_common(dev); - dev->total_read = 0; -} - - -static void -cdrom_command_write(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_DATA_OUT; - cdrom_command_common(dev); -} - - -static void cdrom_command_write_dma(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_DATA_OUT_DMA; - cdrom_command_common(dev); -} - - -/* id = Current CD-ROM device ID; - len = Total transfer length; - block_len = Length of a single block (why does it matter?!); - alloc_len = Allocated transfer length; - direction = Transfer direction (0 = read from host, 1 = write to host). */ -static void cdrom_data_command_finish(cdrom_t *dev, int len, int block_len, int alloc_len, int direction) -{ - cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", - dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); - dev->pos = 0; - if (alloc_len >= 0) { - if (alloc_len < len) - len = alloc_len; - } - if ((len == 0) || (cdrom_current_mode(dev) == 0)) { - if (dev->drv->bus_type != CDROM_BUS_SCSI) - dev->packet_len = 0; - - cdrom_command_complete(dev); - } else { - if (cdrom_current_mode(dev) == 2) { - if (dev->drv->bus_type != CDROM_BUS_SCSI) - dev->packet_len = alloc_len; - - if (direction == 0) - cdrom_command_read_dma(dev); - else - cdrom_command_write_dma(dev); - } else { - cdrom_update_request_length(dev, len, block_len); - if (direction == 0) - cdrom_command_read(dev); - else - cdrom_command_write(dev); - } - } - - cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", - dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); -} - - -static void -cdrom_sense_clear(cdrom_t *dev, int command) -{ - dev->previous_command = command; - cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; -} - - -static void -cdrom_set_phase(cdrom_t *dev, uint8_t phase) -{ - uint8_t scsi_id = dev->drv->scsi_device_id; - - if (dev->drv->bus_type != CDROM_BUS_SCSI) - return; - - SCSIDevices[scsi_id].Phase = phase; -} - - -static void -cdrom_cmd_error(cdrom_t *dev) -{ - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = ((cdrom_sense_key & 0xf) << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; - dev->packet_status = 0x80; - dev->callback = 50LL * CDROM_TIME; - cdrom_set_callback(dev); - cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, cdrom_sense_key, cdrom_asc, cdrom_ascq); -} - - -static void -cdrom_unit_attention(cdrom_t *dev) -{ - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; - dev->packet_status = 0x80; - dev->callback = 50LL * CDROM_TIME; - cdrom_set_callback(dev); - cdrom_log("CD-ROM %i: UNIT ATTENTION\n", dev->id); -} - - -static void -cdrom_bus_master_error(cdrom_t *dev) -{ - cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_not_ready(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_NOT_READY; - cdrom_asc = ASC_MEDIUM_NOT_PRESENT; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_invalid_lun(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INV_LUN; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_illegal_opcode(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_ILLEGAL_OPCODE; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_lba_out_of_range(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_LBA_OUT_OF_RANGE; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_invalid_field(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; - cdrom_ascq = 0; - cdrom_cmd_error(dev); - dev->status = 0x53; -} - - -static void -cdrom_invalid_field_pl(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; - cdrom_ascq = 0; - cdrom_cmd_error(dev); - dev->status = 0x53; -} - - -static void -cdrom_illegal_mode(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_incompatible_format(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INCOMPATIBLE_FORMAT; - cdrom_ascq = 2; - cdrom_cmd_error(dev); -} - - -static void -cdrom_data_phase_error(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_DATA_PHASE_ERROR; - cdrom_ascq = 0; - cdrom_cmd_error(dev); + if (dev->cd_status > CD_STATUS_DATA_ONLY) + dev->cd_status = CD_STATUS_STOPPED; } void -cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) -{ - int temp = 0; - - switch(cdb[0]) { - case GPCMD_READ_6: - cdb[1] = (lba_pos >> 16) & 0xff; - cdb[2] = (lba_pos >> 8) & 0xff; - cdb[3] = lba_pos & 0xff; - break; - - case GPCMD_READ_10: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[7] = (number_of_blocks >> 8) & 0xff; - cdb[8] = number_of_blocks & 0xff; - break; - - case GPCMD_READ_12: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[6] = (number_of_blocks >> 24) & 0xff; - cdb[7] = (number_of_blocks >> 16) & 0xff; - cdb[8] = (number_of_blocks >> 8) & 0xff; - cdb[9] = number_of_blocks & 0xff; - break; - - case GPCMD_READ_CD_MSF: - temp = cdrom_lba_to_msf_accurate(lba_pos); - cdb[3] = (temp >> 16) & 0xff; - cdb[4] = (temp >> 8) & 0xff; - cdb[5] = temp & 0xff; - - temp = cdrom_lba_to_msf_accurate(lba_pos + number_of_blocks - 1); - cdb[6] = (temp >> 16) & 0xff; - cdb[7] = (temp >> 8) & 0xff; - cdb[8] = temp & 0xff; - break; - - case GPCMD_READ_CD: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[6] = (number_of_blocks >> 16) & 0xff; - cdb[7] = (number_of_blocks >> 8) & 0xff; - cdb[8] = number_of_blocks & 0xff; - break; - } -} - - -static int -cdrom_read_data(cdrom_t *dev, int msf, int type, int flags, int32_t *len) -{ - int ret = 0; - uint32_t cdsize = 0; - - int i = 0; - int temp_len = 0; - - cdsize = dev->handler->size(dev->id); - - if (dev->sector_pos >= cdsize) { - cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, - dev->sector_pos, cdsize); - cdrom_lba_out_of_range(dev); - return 0; - } - - if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { - cdrom_log("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", dev->id, - (dev->sector_pos + dev->sector_len - 1), cdsize); - cdrom_lba_out_of_range(dev); - return 0; - } - - dev->old_len = 0; - *len = 0; - - for (i = 0; i < dev->requested_blocks; i++) { - ret = dev->handler->readsector_raw(dev->id, cdbufferb + dev->data_pos, dev->sector_pos + i, - msf, type, flags, &temp_len); - - dev->data_pos += temp_len; - dev->old_len += temp_len; - - *len += temp_len; - - if (!ret) { - cdrom_illegal_mode(dev); - return 0; - } - } - - return 1; -} - - -static int -cdrom_read_blocks(cdrom_t *dev, int32_t *len, int first_batch) -{ - int ret = 0, msf = 0; - int type = 0, flags = 0; - - if (dev->current_cdb[0] == 0xb9) - msf = 1; - - if ((dev->current_cdb[0] == 0xb9) || (dev->current_cdb[0] == 0xbe)) { - type = (dev->current_cdb[1] >> 2) & 7; - flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); - } else { - type = 8; - flags = 0x10; - } - - dev->data_pos = 0; - - if (!dev->sector_len) { - cdrom_command_complete(dev); - return -1; - } - - cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); - - cdrom_update_cdb(dev->current_cdb, dev->sector_pos, dev->requested_blocks); - - ret = cdrom_read_data(dev, msf, type, flags, len); - - cdrom_log("Read %i bytes of blocks...\n", *len); - - if (!ret || ((dev->old_len != *len) && !first_batch)) { - if ((dev->old_len != *len) && !first_batch) - cdrom_illegal_mode(dev); - - return 0; - } - - dev->sector_pos += dev->requested_blocks; - dev->sector_len -= dev->requested_blocks; - - return 1; -} - - -/*SCSI Read DVD Structure*/ -static int -cdrom_read_dvd_structure(cdrom_t *dev, int format, const uint8_t *packet, uint8_t *buf) -{ - int layer = packet[6]; - uint64_t total_sectors; - - switch (format) { - case 0x00: /* Physical format information */ - total_sectors = (uint64_t) dev->handler->size(dev->id); - - if (layer != 0) { - cdrom_invalid_field(dev); - return 0; - } - - total_sectors >>= 2; - if (total_sectors == 0) { - /* return -ASC_MEDIUM_NOT_PRESENT; */ - cdrom_not_ready(dev); - return 0; - } - - buf[4] = 1; /* DVD-ROM, part version 1 */ - buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ - buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ - buf[7] = 0; /* default densities */ - - /* FIXME: 0x30000 per spec? */ - buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ - buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ - buf[13] = (total_sectors >> 16) & 0xff; - buf[14] = (total_sectors >> 8) & 0xff; - buf[15] = total_sectors & 0xff; - - buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ - buf[17] = (total_sectors >> 16) & 0xff; - buf[18] = (total_sectors >> 8) & 0xff; - buf[19] = total_sectors & 0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048 +2 ) >> 8) & 0xff; - buf[1] = (2048 + 2) & 0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0x01: /* DVD copyright information */ - buf[4] = 0; /* no copyright data */ - buf[5] = 0; /* no region restrictions */ - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((4 + 2) >> 8) & 0xff; - buf[1] = (4 + 2) & 0xff; - - /* 4 byte header + 4 byte data */ - return (4 + 4); - - case 0x03: /* BCA information - invalid field for no BCA info */ - cdrom_invalid_field(dev); - return 0; - - case 0x04: /* DVD disc manufacturing information */ - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048 + 2) >> 8) & 0xff; - buf[1] = (2048 + 2) & 0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0xff: - /* - * This lists all the command capabilities above. Add new ones - * in order and update the length and buffer return values. - */ - - buf[4] = 0x00; /* Physical format */ - buf[5] = 0x40; /* Not writable, is readable */ - buf[6] = ((2048 + 4) >> 8) & 0xff; - buf[7] = (2048 + 4) & 0xff; - - buf[8] = 0x01; /* Copyright info */ - buf[9] = 0x40; /* Not writable, is readable */ - buf[10] = ((4 + 4) >> 8) & 0xff; - buf[11] = (4 + 4) & 0xff; - - buf[12] = 0x03; /* BCA info */ - buf[13] = 0x40; /* Not writable, is readable */ - buf[14] = ((188 + 4) >> 8) & 0xff; - buf[15] = (188 + 4) & 0xff; - - buf[16] = 0x04; /* Manufacturing info */ - buf[17] = 0x40; /* Not writable, is readable */ - buf[18] = ((2048 + 4) >> 8) & 0xff; - buf[19] = (2048 + 4) & 0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[6] = ((16 + 2) >> 8) & 0xff; - buf[7] = (16 + 2) & 0xff; - - /* data written + 4 byte header */ - return (16 + 4); - - default: /* TODO: formats beyond DVD-ROM requires */ - cdrom_invalid_field(dev); - return 0; - } -} - - -void -cdrom_insert(cdrom_t *dev) -{ - dev->unit_attention = 1; - cdrom_log("CD-ROM %i: Media insert\n", dev->id); -} - - -/*SCSI Sense Initialization*/ -void -cdrom_sense_code_ok(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - cdrom_sense_key = SENSE_NONE; - cdrom_asc = 0; - cdrom_ascq = 0; -} - - -static int -cdrom_pre_execution_check(cdrom_t *dev, uint8_t *cdb) -{ - int ready = 0, status = 0; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { - cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", - dev->id, ((dev->request_length >> 5) & 7)); - cdrom_invalid_lun(dev); - return 0; - } - } - - if (!(cdrom_command_flags[cdb[0]] & IMPLEMENTED)) { - cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], - (dev->drv->bus_type == CDROM_BUS_SCSI) ? "SCSI" : "ATAPI"); - - cdrom_illegal_opcode(dev); - return 0; - } - - if ((dev->drv->bus_type < CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { - cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); - cdrom_illegal_opcode(dev); - return 0; - } - - if ((dev->drv->bus_type == CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { - cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); - cdrom_illegal_opcode(dev); - return 0; - } - - status = dev->handler->status(dev->id); - - if ((status == CD_STATUS_PLAYING) || (status == CD_STATUS_PAUSED)) { - ready = 1; - goto skip_ready_check; - } - - if (dev->handler->medium_changed(dev->id)) - cdrom_insert(dev); - - ready = dev->handler->ready(dev->id); - -skip_ready_check: - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - if (!ready && dev->unit_attention) - dev->unit_attention = 0; - - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (dev->unit_attention == 1) { - /* Only increment the unit attention phase if the command can not pass through it. */ - if (!(cdrom_command_flags[cdb[0]] & ALLOW_UA)) { - /* cdrom_log("CD-ROM %i: Unit attention now 2\n", dev->id); */ - dev->unit_attention++; - cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", - dev->id, cdb[0]); - cdrom_unit_attention(dev); - return 0; - } - } else if (dev->unit_attention == 2) { - if (cdb[0] != GPCMD_REQUEST_SENSE) { - /* cdrom_log("CD-ROM %i: Unit attention now 0\n", dev->id); */ - dev->unit_attention = 0; - } - } - - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ - if (cdb[0] != GPCMD_REQUEST_SENSE) - cdrom_sense_clear(dev, cdb[0]); - - /* Next it's time for NOT READY. */ - if (!ready) - dev->media_status = MEC_MEDIA_REMOVAL; - else - dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - - if ((cdrom_command_flags[cdb[0]] & CHECK_READY) && !ready) { - cdrom_log("CD-ROM %i: Not ready (%02X)\n", dev->id, cdb[0]); - cdrom_not_ready(dev); - return 0; - } - - cdrom_log("CD-ROM %i: Continuing with command %02X\n", dev->id, cdb[0]); - - return 1; -} - - -static void cdrom_seek(cdrom_t *dev, uint32_t pos) -{ - /* cdrom_log("CD-ROM %i: Seek %08X\n", dev->id, pos); */ - dev->seek_pos = pos; - if (dev->handler && dev->handler->stop) - dev->handler->stop(dev->id); -} - - -static void -cdrom_rezero(cdrom_t *dev) -{ - if (dev->handler && dev->handler->stop) - dev->handler->stop(dev->id); - dev->sector_pos = dev->sector_len = 0; - cdrom_seek(dev, 0); -} - - -void -cdrom_reset(cdrom_t *dev) { if (!dev) return; - cdrom_rezero(dev); - dev->status = 0; - dev->callback = 0LL; - cdrom_set_callback(dev); - dev->packet_status = 0xff; - dev->unit_attention = 0xff; + cdrom_log("CD-ROM %i: Seek to LBA %08X\n", dev->id, pos); + + dev->seek_pos = pos; + cdrom_stop(dev); } -static int -cdrom_playing_completed(cdrom_t *dev) +int +cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len) { - dev->prev_status = dev->cd_status; - dev->cd_status = dev->handler->status(dev->id); - if (((dev->prev_status == CD_STATUS_PLAYING) || (dev->prev_status == CD_STATUS_PAUSED)) && ((dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED))) - return 1; - else + int ret = 1; + + if (!dev->sound_on || (dev->cd_status != CD_STATUS_PLAYING)) { + cdrom_log("CD-ROM %i: Audio callback while not playing\n", dev->id); + if (dev->cd_status == CD_STATUS_PLAYING) + dev->seek_pos += (len >> 11); + memset(output, 0, len * 2); return 0; -} - - -static void -cdrom_request_sense(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) -{ - /*Will return 18 bytes of 0*/ - if (alloc_length != 0) { - memset(buffer, 0, alloc_length); - memcpy(buffer, dev->sense, alloc_length); } - buffer[0] = 0x70; - - if ((cdrom_sense_key > 0) && ((dev->cd_status < CD_STATUS_PLAYING) || - (dev->cd_status == CD_STATUS_STOPPED)) && cdrom_playing_completed(dev)) { - buffer[2]=SENSE_ILLEGAL_REQUEST; - buffer[12]=ASC_AUDIO_PLAY_OPERATION; - buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; - } else if ((cdrom_sense_key == 0) && (dev->cd_status >= CD_STATUS_PLAYING) && - (dev->cd_status != CD_STATUS_STOPPED)) { - buffer[2]=SENSE_ILLEGAL_REQUEST; - buffer[12]=ASC_AUDIO_PLAY_OPERATION; - buffer[13]=(dev->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; - } else { - if (dev->unit_attention && (cdrom_sense_key == 0)) { - buffer[2]=SENSE_UNIT_ATTENTION; - buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - buffer[13]=0; - } - } - - cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); - - if (buffer[2] == SENSE_UNIT_ATTENTION) { - /* If the last remaining sense is unit attention, clear - that condition. */ - dev->unit_attention = 0; - } - - /* Clear the sense stuff as per the spec. */ - cdrom_sense_clear(dev, GPCMD_REQUEST_SENSE); -} - - -void -cdrom_request_sense_for_scsi(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) -{ - int ready = 0; - - if (dev->handler->medium_changed(dev->id)) - cdrom_insert(dev); - - ready = dev->handler->ready(dev->id); - - if (!ready && dev->unit_attention) { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - dev->unit_attention = 0; - } - - /* Do *NOT* advance the unit attention phase. */ - cdrom_request_sense(dev, buffer, alloc_length); -} - - -static void -cdrom_set_buf_len(cdrom_t *dev, int32_t *BufLen, int32_t *src_len) -{ - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if (*BufLen == -1) - *BufLen = *src_len; - else { - *BufLen = MIN(*src_len, *BufLen); - *src_len = *BufLen; - } - cdrom_log("CD-ROM %i: Actual transfer length: %i\n", dev->id, *BufLen); - } -} - - -static void -cdrom_buf_alloc(cdrom_t *dev, uint32_t len) -{ - cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); - cdbufferb = (uint8_t *) malloc(len); -} - - -static void -cdrom_buf_free(cdrom_t *dev) -{ - if (cdbufferb) { - cdrom_log("CD-ROM %i: Freeing buffer...\n", dev->id); - free(cdbufferb); - cdbufferb = NULL; - } -} - - -void -cdrom_command(cdrom_t *dev, uint8_t *cdb) -{ - int len, max_len, used_len, alloc_length, msf; - int pos = 0, i= 0, size_idx, idx = 0; - uint32_t feature; - unsigned preamble_len; - int toc_format, block_desc = 0; - int ret, format = 0; - int real_pos, track = 0; - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; - char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; - int32_t blen = 0, *BufLen; - uint8_t *b; - uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; - dev->status &= ~ERR_STAT; - } else { - BufLen = &blen; - dev->error = 0; - } - - dev->packet_len = 0; - dev->request_pos = 0; - - device_identify[7] = dev->id + 0x30; - - device_identify_ex[7] = dev->id + 0x30; - device_identify_ex[10] = EMU_VERSION[0]; - device_identify_ex[12] = EMU_VERSION[2]; - device_identify_ex[13] = EMU_VERSION[3]; - - dev->data_pos = 0; - - memcpy(dev->current_cdb, cdb, dev->cdb_len); - - dev->cd_status = dev->handler->status(dev->id); - - if (cdb[0] != 0) { - cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", - dev->id, cdb[0], cdrom_sense_key, cdrom_asc, cdrom_ascq, dev->unit_attention); - cdrom_log("CD-ROM %i: Request length: %04X\n", dev->id, dev->request_length); - - cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, - cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], - cdb[8], cdb[9], cdb[10], cdb[11]); - } - - msf = cdb[1] & 2; - dev->sector_len = 0; - - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ - if (cdrom_pre_execution_check(dev, cdb) == 0) - return; - - switch (cdb[0]) { - case GPCMD_TEST_UNIT_READY: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - cdrom_command_complete(dev); - break; - - case GPCMD_REZERO_UNIT: - if (dev->handler->stop) - dev->handler->stop(dev->id); - dev->sector_pos = dev->sector_len = 0; - dev->seek_diff = dev->seek_pos; - cdrom_seek(dev, 0); - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - break; - - case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - max_len = cdb[4]; - cdrom_buf_alloc(dev, 256); - cdrom_set_buf_len(dev, BufLen, &max_len); - cdrom_request_sense(dev, cdbufferb, max_len); - cdrom_data_command_finish(dev, 18, 18, cdb[4], 0); - break; - - case GPCMD_SET_SPEED: - case GPCMD_SET_SPEED_ALT: - dev->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; - if (dev->cur_speed < 1) - dev->cur_speed = 1; - else if (dev->cur_speed > dev->drv->speed) - dev->cur_speed = dev->drv->speed; - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - cdrom_command_complete(dev); - break; - - case GPCMD_MECHANISM_STATUS: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - cdrom_buf_alloc(dev, 8); - - cdrom_set_buf_len(dev, BufLen, &len); - - memset(cdbufferb, 0, 8); - cdbufferb[5] = 1; - - cdrom_data_command_finish(dev, 8, 8, len, 0); - break; - - case GPCMD_READ_TOC_PMA_ATIP: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - - cdrom_buf_alloc(dev, 65536); - - toc_format = cdb[2] & 0xf; - - if (toc_format == 0) - toc_format = (cdb[9] >> 6) & 3; - - switch (toc_format) { - case 0: /*Normal*/ - len = dev->handler->readtoc(dev->id, cdbufferb, cdb[6], msf, max_len, - 0); - break; - case 1: /*Multi session*/ - len = dev->handler->readtoc_session(dev->id, cdbufferb, msf, max_len); - cdbufferb[0] = 0; cdbufferb[1] = 0xA; - break; - case 2: /*Raw*/ - len = dev->handler->readtoc_raw(dev->id, cdbufferb, max_len); - break; - default: - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - if (len > max_len) { - len = max_len; - - cdbufferb[0] = ((len - 2) >> 8) & 0xff; - cdbufferb[1] = (len - 2) & 0xff; - } - - cdrom_set_buf_len(dev, BufLen, &len); - - if (len >= 8) { - cdrom_log("CD-ROM %i: TOC: %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, - cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], - cdbufferb[4], cdbufferb[5], cdbufferb[6], cdbufferb[7]); - } - - if (len >= 16) { - cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", - cdbufferb[8], cdbufferb[9], cdbufferb[10], cdbufferb[11], - cdbufferb[12], cdbufferb[13], cdbufferb[14], cdbufferb[15]); - } - - if (len >= 24) { - cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", - cdbufferb[16], cdbufferb[17], cdbufferb[18], cdbufferb[19], - cdbufferb[20], cdbufferb[21], cdbufferb[22], cdbufferb[23]); - } - - if (len >= 32) { - cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", - cdbufferb[24], cdbufferb[25], cdbufferb[26], cdbufferb[27], - cdbufferb[28], cdbufferb[29], cdbufferb[30], cdbufferb[31]); - } - - if (len >= 36) { - cdrom_log(" %02X %02X %02X %02X\n", - cdbufferb[32], cdbufferb[33], cdbufferb[34], cdbufferb[35]); - } - - cdrom_data_command_finish(dev, len, len, len, 0); - /* cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", dev->id, - toc_format, ide->cylinder, cdbufferb[1]); */ - return; - - case GPCMD_READ_CD_OLD: - /* IMPORTANT: Convert the command to new read CD - for pass through purposes. */ - dev->current_cdb[0] = 0xbe; - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - case GPCMD_READ_CD: - case GPCMD_READ_CD_MSF: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - alloc_length = 2048; - - switch(cdb[0]) { - case GPCMD_READ_6: - dev->sector_len = cdb[4]; - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - msf = 0; - break; - case GPCMD_READ_10: - dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, - dev->sector_pos); - msf = 0; - break; - case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, - dev->sector_pos); - msf = 0; - break; - case GPCMD_READ_CD_MSF: - alloc_length = 2856; - dev->sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); - dev->sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); - - dev->sector_len -= dev->sector_pos; - dev->sector_len++; - msf = 1; - break; - case GPCMD_READ_CD_OLD: - case GPCMD_READ_CD: - alloc_length = 2856; - dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - - msf = 0; - break; - } - - dev->seek_diff = ABS((int) (pos - dev->seek_pos)); - dev->seek_pos = dev->sector_pos; - - if (!dev->sector_len) { - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - /* cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->callback = 20LL * CDROM_TIME; - cdrom_set_callback(dev); - break; - } - - max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - dev->packet_len = max_len * alloc_length; - cdrom_buf_alloc(dev, dev->packet_len); - - ret = cdrom_read_blocks(dev, &alloc_length, 1); - if (ret <= 0) { - cdrom_buf_free(dev); - return; - } - - dev->requested_blocks = max_len; - dev->packet_len = alloc_length; - - cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - cdrom_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, - alloc_length, 0); - - dev->all_blocks_total = dev->block_total; - if (dev->packet_status != CDROM_PHASE_COMPLETE) - ui_sb_update_icon(SB_CDROM | dev->id, 1); - else - ui_sb_update_icon(SB_CDROM | dev->id, 0); - return; - - case GPCMD_READ_HEADER: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - alloc_length = ((cdb[7] << 8) | cdb[8]); - cdrom_buf_alloc(dev, 8); - - dev->sector_len = 1; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4]<<8) | cdb[5]; - if (msf) - real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); - else - real_pos = dev->sector_pos; - cdbufferb[0] = 1; /*2048 bytes user data*/ - cdbufferb[1] = cdbufferb[2] = cdbufferb[3] = 0; - cdbufferb[4] = (real_pos >> 24); - cdbufferb[5] = ((real_pos >> 16) & 0xff); - cdbufferb[6] = ((real_pos >> 8) & 0xff); - cdbufferb[7] = real_pos & 0xff; - - len = 8; - len = MIN(len, alloc_length); - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, len, 0); - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - else - block_desc = 0; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = cdb[4]; - cdrom_buf_alloc(dev, 256); + while (dev->cd_buflen < len) { + if (dev->seek_pos < dev->cd_end) { + if (dev->ops->read_sector(dev, CD_READ_AUDIO, + (uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), + dev->seek_pos)) { + cdrom_log("CD-ROM %i: Read LBA %08X successful\n", dev->id, dev->seek_pos); + dev->seek_pos++; + dev->cd_buflen += (RAW_SECTOR_SIZE / 2); + ret = 1; } else { - len = (cdb[8] | (cdb[7] << 8)); - cdrom_buf_alloc(dev, 65536); - } - - dev->current_page_code = cdb[2] & 0x3F; - - if (!(cdrom_mode_sense_page_flags & (1LL << dev->current_page_code))) { - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - memset(cdbufferb, 0, len); - alloc_length = len; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = cdrom_mode_sense(dev, cdbufferb, 4, cdb[2], block_desc); - len = MIN(len, alloc_length); - cdbufferb[0] = len - 1; - cdbufferb[1] = dev->handler->media_type_id(dev->id); - if (block_desc) - cdbufferb[3] = 8; - } else { - len = cdrom_mode_sense(dev, cdbufferb, 8, cdb[2], block_desc); - len = MIN(len, alloc_length); - cdbufferb[0]=(len - 2) >> 8; - cdbufferb[1]=(len - 2) & 255; - cdbufferb[2] = dev->handler->media_type_id(dev->id); - if (block_desc) { - cdbufferb[6] = 0; - cdbufferb[7] = 8; - } - } - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", dev->id, cdb[2]); - - cdrom_data_command_finish(dev, len, len, alloc_length, 0); - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); - - if (cdb[0] == GPCMD_MODE_SELECT_6) { - len = cdb[4]; - cdrom_buf_alloc(dev, 256); - } else { - len = (cdb[7] << 8) | cdb[8]; - cdrom_buf_alloc(dev, 65536); - } - - cdrom_set_buf_len(dev, BufLen, &len); - - dev->total_length = len; - dev->do_page_save = cdb[1] & 1; - - dev->current_page_pos = 0; - - cdrom_data_command_finish(dev, len, len, len, 1); - return; - - case GPCMD_GET_CONFIGURATION: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - /* XXX: could result in alignment problems in some architectures */ - feature = (cdb[2] << 8) | cdb[3]; - max_len = (cdb[7] << 8) | cdb[8]; - - /* only feature 0 is supported */ - if ((cdb[2] != 0) || (cdb[3] > 2)) { - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - cdrom_buf_alloc(dev, 65536); - memset(cdbufferb, 0, max_len); - - alloc_length = 0; - b = cdbufferb; - - /* - * the number of sectors from the media tells us which profile - * to use as current. 0 means there is no media - */ - if (dev->handler->ready(dev->id)) { - len = dev->handler->size(dev->id); - if (len > CD_MAX_SECTORS) { - b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; - b[7] = MMC_PROFILE_DVD_ROM & 0xff; - ret = 1; - } else { - b[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; - b[7] = MMC_PROFILE_CD_ROM & 0xff; - ret = 0; - } - } else - ret = 2; - - alloc_length = 8; - b += 8; - - if ((feature == 0) || ((cdb[1] & 3) < 2)) { - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 8; - - alloc_length += 4; - b += 4; - - for (i = 0; i < 2; i++) { - b[0] = (profiles[i] >> 8) & 0xff; - b[1] = profiles[i] & 0xff; - - if (ret == i) - b[2] |= 1; - - alloc_length += 4; - b += 4; - } - } - if ((feature == 1) || ((cdb[1] & 3) < 2)) { - b[1] = 1; - b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 8; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - b[7] = 1; - else - b[7] = 2; - b[8] = 1; - - alloc_length += 12; - b += 12; - } - if ((feature == 2) || ((cdb[1] & 3) < 2)) { - b[1] = 2; - b[2] = (1 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 4; - - b[4] = 2; - - alloc_length += 8; - b += 8; - } - - cdbufferb[0] = ((alloc_length - 4) >> 24) & 0xff; - cdbufferb[1] = ((alloc_length - 4) >> 16) & 0xff; - cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; - cdbufferb[3] = (alloc_length - 4) & 0xff; - - alloc_length = MIN(alloc_length, max_len); - - cdrom_set_buf_len(dev, BufLen, &alloc_length); - - cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); - break; - - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - cdrom_buf_alloc(dev, 8 + sizeof(gesn_event_header)); - - gesn_cdb = (void *) cdb; - gesn_event_header = (void *) cdbufferb; - - /* 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. */ - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - /* - * 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; - - cdbufferb[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ - cdbufferb[5] = 1; /* Power Status (1 = Active) */ - cdbufferb[6] = 0; - cdbufferb[7] = 0; - used_len = 8; - } else { - gesn_event_header->notification_class = 0x80; /* No event available */ - used_len = sizeof(*gesn_event_header); - } - gesn_event_header->len = used_len - sizeof(*gesn_event_header); - - memcpy(cdbufferb, gesn_event_header, 4); - - cdrom_set_buf_len(dev, BufLen, &used_len); - - cdrom_data_command_finish(dev, used_len, used_len, used_len, 0); - break; - - case GPCMD_READ_DISC_INFORMATION: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - - cdrom_buf_alloc(dev, 65536); - - memset(cdbufferb, 0, 34); - memset(cdbufferb, 1, 9); - cdbufferb[0] = 0; - cdbufferb[1] = 32; - cdbufferb[2] = 0xe; /* last session complete, disc finalized */ - cdbufferb[7] = 0x20; /* unrestricted use */ - cdbufferb[8] = 0x00; /* CD-ROM */ - - len=34; - len = MIN(len, max_len); - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, len, 0); - break; - - case GPCMD_READ_TRACK_INFORMATION: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - - cdrom_buf_alloc(dev, 65536); - - track = ((uint32_t) cdb[2]) << 24; - track |= ((uint32_t) cdb[3]) << 16; - track |= ((uint32_t) cdb[4]) << 8; - track |= (uint32_t) cdb[5]; - - if (((cdb[1] & 0x03) != 1) || (track != 1)) { - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - len = 36; - - memset(cdbufferb, 0, 36); - cdbufferb[0] = 0; - cdbufferb[1] = 34; - cdbufferb[2] = 1; /* track number (LSB) */ - cdbufferb[3] = 1; /* session number (LSB) */ - cdbufferb[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ - cdbufferb[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ - cdbufferb[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ - cdbufferb[24] = (dev->handler->size(dev->id) >> 24) & 0xff; /* track size */ - cdbufferb[25] = (dev->handler->size(dev->id) >> 16) & 0xff; /* track size */ - cdbufferb[26] = (dev->handler->size(dev->id) >> 8) & 0xff; /* track size */ - cdbufferb[27] = dev->handler->size(dev->id) & 0xff; /* track size */ - - if (len > max_len) { - len = max_len; - cdbufferb[0] = ((max_len - 2) >> 8) & 0xff; - cdbufferb[1] = (max_len - 2) & 0xff; - } - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, max_len, 0); - break; - - case GPCMD_PLAY_AUDIO_10: - case GPCMD_PLAY_AUDIO_12: - case GPCMD_PLAY_AUDIO_MSF: - case GPCMD_PLAY_AUDIO_TRACK_INDEX: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - switch(cdb[0]) { - case GPCMD_PLAY_AUDIO_10: - msf = 0; - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - len = (cdb[7] << 8) | cdb[8]; - break; - case GPCMD_PLAY_AUDIO_12: - msf = 0; - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - break; - 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. */ - msf = 1; - pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - break; - case GPCMD_PLAY_AUDIO_TRACK_INDEX: - msf = 2; - pos = (cdb[4] << 8) | cdb[5]; - len = (cdb[7] << 8) | cdb[8]; - break; - } - - if ((dev->drv->host_drive < 1) || (dev->cd_status <= CD_STATUS_DATA_ONLY)) { - cdrom_illegal_mode(dev); - break; - } - - if (dev->handler->playaudio) - ret = dev->handler->playaudio(dev->id, pos, len, msf); - else + cdrom_log("CD-ROM %i: Read LBA %08X failed\n", dev->id, dev->seek_pos); + memset(&(dev->cd_buffer[dev->cd_buflen]), + 0x00, (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_status = CD_STATUS_STOPPED; + dev->cd_buflen = len; ret = 0; - - if (ret) - cdrom_command_complete(dev); - else - cdrom_illegal_mode(dev); - break; - - case GPCMD_READ_SUBCHANNEL: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - msf = (cdb[1] >> 1) & 1; - - cdrom_buf_alloc(dev, 32); - - cdrom_log("CD-ROM %i: Getting page %i (%s)\n", dev->id, cdb[3], msf ? "MSF" : "LBA"); - - if (cdb[3] > 3) { - /* cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", dev->id, - cdb[3]); */ - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; } - - switch(cdb[3]) { - case 0: - alloc_length = 4; - break; - case 1: - alloc_length = 16; - break; - default: - alloc_length = 24; - break; - } - - memset(cdbufferb, 0, 24); - pos = 0; - cdbufferb[pos++] = 0; - cdbufferb[pos++] = 0; /*Audio status*/ - cdbufferb[pos++] = 0; cdbufferb[pos++] = 0; /*Subchannel length*/ - cdbufferb[pos++] = cdb[3] & 3; /*Format code*/ - if (cdb[3] == 1) { - cdbufferb[1] = dev->handler->getcurrentsubchannel(dev->id, &cdbufferb[5], msf); - switch(dev->cd_status) { - case CD_STATUS_PLAYING: - cdbufferb[1] = 0x11; - break; - case CD_STATUS_PAUSED: - cdbufferb[1] = 0x12; - break; - case CD_STATUS_DATA_ONLY: - cdbufferb[1] = 0x15; - break; - default: - cdbufferb[1] = 0x13; - break; - } - } - - if (!(cdb[2] & 0x40) || (cdb[3] == 0)) - len = 4; - else - len = alloc_length; - - len = MIN(len, max_len); - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_log("CD-ROM %i: Read subchannel:", dev->id); - for (i = 0; i < 32; i += 8) { - cdrom_log("[%02X] %02X %02X %02X %02X %02X %02X %02X %02X\n", i, - cdbufferb[i], cdbufferb[i + 1], cdbufferb[i + 2], cdbufferb[i + 3], - cdbufferb[i + 4], cdbufferb[i + 5], cdbufferb[i + 6], cdbufferb[i + 7]); - } - - cdrom_data_command_finish(dev, len, len, len, 0); - break; - - case GPCMD_READ_DVD_STRUCTURE: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - alloc_length = (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - - cdrom_buf_alloc(dev, alloc_length); - - len = dev->handler->size(dev->id); - - if ((cdb[7] < 0xc0) && (len <= CD_MAX_SECTORS)) { - cdrom_incompatible_format(dev); - cdrom_buf_free(dev); - return; - } - - memset(cdbufferb, 0, alloc_length); - - if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { - if (cdb[1] == 0) { - ret = cdrom_read_dvd_structure(dev, format, cdb, cdbufferb); - if (ret) { - cdrom_set_buf_len(dev, BufLen, &alloc_length); - cdrom_data_command_finish(dev, alloc_length, alloc_length, - len, 0); - } else - cdrom_buf_free(dev); - return; - } - } else { - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - break; - - case GPCMD_START_STOP_UNIT: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - switch(cdb[4] & 3) { - case 0: /* Stop the disc. */ - if (dev->handler->stop) - dev->handler->stop(dev->id); - break; - case 1: /* Start the disc and read the TOC. */ - dev->handler->medium_changed(dev->id); /* This causes a TOC reload. */ - break; - case 2: /* Eject the disc if possible. */ - if (dev->handler->stop) - dev->handler->stop(dev->id); - cdrom_eject(dev->id); - break; - case 3: /* Load the disc (close tray). */ - cdrom_reload(dev->id); - break; - } - - cdrom_command_complete(dev); - break; - - case GPCMD_INQUIRY: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[3]; - max_len <<= 8; - max_len |= cdb[4]; - - cdrom_buf_alloc(dev, 65536); - - if (cdb[1] & 1) { - preamble_len = 4; - size_idx = 3; - - cdbufferb[idx++] = 05; - cdbufferb[idx++] = cdb[2]; - cdbufferb[idx++] = 0; - - idx++; - - switch (cdb[2]) { - case 0x00: - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 0x83; - break; - case 0x83: - if (idx + 24 > max_len) { - cdrom_data_phase_error(dev); - cdrom_buf_free(dev); - return; - } - - cdbufferb[idx++] = 0x02; - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 20; - ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Serial */ - idx += 20; - - if (idx + 72 > cdb[4]) - goto atapi_out; - cdbufferb[idx++] = 0x02; - cdbufferb[idx++] = 0x01; - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 68; - ide_padstr8(cdbufferb + idx, 8, EMU_NAME); /* Vendor */ - idx += 8; - ide_padstr8(cdbufferb + idx, 40, device_identify_ex); /* Product */ - idx += 40; - ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Product */ - idx += 20; - break; - default: - cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - } else { - preamble_len = 5; - size_idx = 4; - - memset(cdbufferb, 0, 8); - cdbufferb[0] = 5; /*CD-ROM*/ - cdbufferb[1] = 0x80; /*Removable*/ - cdbufferb[2] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - cdbufferb[3] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x12 : 0x21; - cdbufferb[4] = 31; - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - cdbufferb[6] = 1; /* 16-bit transfers supported */ - cdbufferb[7] = 0x20; /* Wide bus supported */ - } - - ide_padstr8(cdbufferb + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(cdbufferb + 16, 16, device_identify); /* Product */ - ide_padstr8(cdbufferb + 32, 4, EMU_VERSION); /* Revision */ - idx = 36; - - if (max_len == 96) { - cdbufferb[4] = 91; - idx = 96; - } - } - -atapi_out: - cdbufferb[size_idx] = idx - preamble_len; - len=idx; - - len = MIN(len, max_len); - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, max_len, 0); - break; - - case GPCMD_PREVENT_REMOVAL: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - cdrom_command_complete(dev); - break; - - case GPCMD_PAUSE_RESUME_ALT: - case GPCMD_PAUSE_RESUME: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - if (cdb[8] & 1) { - if (dev->handler->resume) - dev->handler->resume(dev->id); - else { - cdrom_illegal_mode(dev); - break; - } - } else { - if (dev->handler->pause) - dev->handler->pause(dev->id); - else { - cdrom_illegal_mode(dev); - break; - } - } - cdrom_command_complete(dev); - break; - - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - switch(cdb[0]) { - case GPCMD_SEEK_6: - pos = (cdb[2] << 8) | cdb[3]; - break; - case GPCMD_SEEK_10: - pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; - break; - } - dev->seek_diff = ABS((int) (pos - dev->seek_pos)); - cdrom_seek(dev, pos); - cdrom_command_complete(dev); - break; - - case GPCMD_READ_CDROM_CAPACITY: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - cdrom_buf_alloc(dev, 8); - - if (cdrom_read_capacity(dev, dev->current_cdb, cdbufferb, (uint32_t *) &len) == 0) { - cdrom_buf_free(dev); - return; - } - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, len, 0); - break; - - case GPCMD_STOP_PLAY_SCAN: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - if (dev->handler->stop) - dev->handler->stop(dev->id); - else { - cdrom_illegal_mode(dev); - break; - } - cdrom_command_complete(dev); - break; - - default: - cdrom_illegal_opcode(dev); - break; + } else { + cdrom_log("CD-ROM %i: Playing completed\n", dev->id); + memset(&dev->cd_buffer[dev->cd_buflen], + 0x00, (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_status = CD_STATUS_PLAYING_COMPLETED; + dev->cd_buflen = len; + ret = 0; + } } - /* cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ + memcpy(output, dev->cd_buffer, len * 2); + memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); + dev->cd_buflen -= len; - if (cdrom_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) - cdrom_buf_free(dev); + cdrom_log("CD-ROM %i: Audio callback returning %i\n", dev->id, ret); + return ret; } -/* The command second phase function, needed for Mode Select. */ -static uint8_t -cdrom_phase_data_out(cdrom_t *dev) +uint8_t +cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf) { - uint16_t block_desc_len, pos; - uint16_t i = 0; + track_info_t ti; + int m = 0, s = 0, f = 0; - uint8_t error = 0; - uint8_t page, page_len, hdr_len, val, old_val, ch; + if (dev->cd_status == CD_STATUS_DATA_ONLY) + return 0; - FILE *f; + cdrom_log("CD-ROM %i: Play audio - %08X %08X %i\n", dev->id, pos, len, ismsf); + if (ismsf & 0x100) { + /* Track-relative audio play. */ + dev->ops->get_track_info(dev, ismsf & 0xff, 0, &ti); + pos += MSFtoLBA(ti.m, ti.s, ti.f) - 150; + } else if (ismsf == 2) { + dev->ops->get_track_info(dev, pos, 0, &ti); + pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + /* We have to end at the *end* of the specified track, + not at the beginning. */ + dev->ops->get_track_info(dev, len, 1, &ti); + len = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + } else if (ismsf == 1) { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; - switch(dev->current_cdb[0]) { - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - f = nvr_fopen(L"modeselect.bin", L"wb"); - fwrite(cdbufferb, 1, dev->total_length, f); - fclose(f); + if (pos == 0xffffff) { + cdrom_log("CD-ROM %i: Playing from current position (MSF)\n", dev->id); + pos = dev->seek_pos; + } else + pos = MSFtoLBA(m, s, f) - 150; - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) - hdr_len = 8; - else - hdr_len = 4; + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f) - 150; - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = cdbufferb[2]; - block_desc_len <<= 8; - block_desc_len |= cdbufferb[3]; - } else { - block_desc_len = cdbufferb[6]; - block_desc_len <<= 8; - block_desc_len |= cdbufferb[7]; - } - } else - block_desc_len = 0; - - pos = hdr_len + block_desc_len; - - while(1) { - page = cdbufferb[pos] & 0x3F; - page_len = cdbufferb[pos + 1]; - - pos += 2; - - if (!(cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { - cdrom_log("Unimplemented page %02X\n", page); - error |= 1; - } else { - for (i = 0; i < page_len; i++) { - ch = cdrom_mode_sense_pages_changeable.pages[page][i + 2]; - val = cdbufferb[pos + i]; - old_val = dev->ms_pages_saved.pages[page][i + 2]; - if (val != old_val) { - if (ch) - dev->ms_pages_saved.pages[page][i + 2] = val; - else { - cdrom_log("Unchangeable value on position %02X on page %02X\n", i + 2, page); - error |= 1; - } - } - } - } - - pos += page_len; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - val = cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; - else - val = cdrom_mode_sense_pages_default.pages[page][0] & 0x80; - - if (dev->do_page_save && val) - cdrom_mode_sense_save(dev); - - if (pos >= dev->total_length) - break; - } - - if (error) { - cdrom_invalid_field_pl(dev); - return 0; - } - break; + cdrom_log("CD-ROM %i: MSF - pos = %08X len = %08X\n", dev->id, pos, len); + } else if (ismsf == 0) { + if (pos == 0xffffffff) { + cdrom_log("CD-ROM %i: Playing from current position\n", dev->id); + pos = dev->seek_pos; + } + len += pos; } + /* Do this at this point, since it's at this point that we know the + actual LBA position to start playing from. */ + if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { + cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); + cdrom_stop(dev); + return 0; + } + + dev->seek_pos = pos; + dev->cd_end = len; + dev->cd_status = CD_STATUS_PLAYING; + dev->cd_buflen = 0; + return 1; } -/* This is the general ATAPI PIO request function. */ -static void -cdrom_pio_request(cdrom_t *dev, uint8_t out) +void +cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume) { - int ret = 0; + if ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED)) + dev->cd_status = (dev->cd_status & 0xfe) | (resume & 0x01); +} - if (dev->drv->bus_type < CDROM_BUS_SCSI) { - cdrom_log("CD-ROM %i: Lowering IDE IRQ\n", dev->id); - ide_irq_lower(ide_drives[dev->drv->ide_channel]); + +uint8_t +cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) +{ + uint8_t ret; + subchannel_t subc; + int pos = 1; + + dev->ops->get_subchannel(dev, dev->seek_pos, &subc); + cdrom_log("CD-ROM %i: Returned subchannel at %02i:%02i.%02i\n", subc.abs_m, subc.abs_s, subc.abs_f); + + if (dev->cd_status == CD_STATUS_DATA_ONLY) + ret = 0x15; + else { + if (dev->cd_status == CD_STATUS_PLAYING) + ret = 0x11; + else if (dev->cd_status == CD_STATUS_PAUSED) + ret = 0x12; + else + ret = 0x13; } - dev->status = BUSY_STAT; - - if (dev->pos >= dev->packet_len) { - cdrom_log("CD-ROM %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read"); - - dev->pos = dev->request_pos = 0; - if (out) { - ret = cdrom_phase_data_out(dev); - /* If ret = 0 (phase 1 error), then we do not do anything else other than - free the buffer, as the phase and callback have already been set by the - error function. */ - if (ret) - cdrom_command_complete(dev); - } else - cdrom_command_complete(dev); - cdrom_buf_free(dev); - } else { - cdrom_log("CD-ROM %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos, - out ? "written" : "read", dev->packet_len - dev->pos); - - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ - if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) - dev->max_transfer_len = dev->packet_len - dev->pos; - cdrom_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, - dev->max_transfer_len); - - dev->packet_status = out ? CDROM_PHASE_DATA_OUT : CDROM_PHASE_DATA_IN; - - dev->status = BUSY_STAT; - dev->phase = 1; - cdrom_phase_callback(dev); - dev->callback = 0LL; - cdrom_set_callback(dev); - - dev->request_pos = 0; - } -} - - -static int -cdrom_read_from_ide_dma(uint8_t channel) -{ - cdrom_t *dev; - - uint8_t id = atapi_cdrom_drives[channel]; - int ret; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - if (ide_bus_master_write) { - ret = ide_bus_master_write(channel >> 1, - cdbufferb, dev->packet_len, - ide_bus_master_priv[channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - cdrom_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; - - return 0; -} - - -static int -cdrom_read_from_scsi_dma(uint8_t scsi_id) -{ - cdrom_t *dev; - - uint8_t id = scsi_cdrom_drives[scsi_id]; - int32_t *BufLen = &SCSIDevices[scsi_id].BufferLength; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(cdbufferb, SCSIDevices[scsi_id].CmdBuffer, *BufLen); - return 1; -} - - -static void -cdrom_irq_raise(cdrom_t *dev) -{ - if (dev->drv->bus_type < CDROM_BUS_SCSI) - ide_irq_raise(ide_drives[dev->drv->ide_channel]); -} - - -static int -cdrom_read_from_dma(cdrom_t *dev) -{ - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; - int ret = 0; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - ret = cdrom_read_from_scsi_dma(dev->drv->scsi_device_id); - else - ret = cdrom_read_from_ide_dma(dev->drv->ide_channel); - - if (ret != 1) + if (b[pos] > 1) return ret; - if (dev->drv->bus_type == CDROM_BUS_SCSI) - cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", dev->id, *BufLen); - else - cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len); + b[pos++] = subc.attr; + b[pos++] = subc.track; + b[pos++] = subc.index; - ret = cdrom_phase_data_out(dev); - - if (ret) - return 1; - else - return 0; -} - - -static int -cdrom_write_to_ide_dma(uint8_t channel) -{ - cdrom_t *dev; - - uint8_t id = atapi_cdrom_drives[channel]; - int ret; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - if (ide_bus_master_read) { - ret = ide_bus_master_read(channel >> 1, - cdbufferb, dev->packet_len, - ide_bus_master_priv[channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - cdrom_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; -} - - -static int -cdrom_write_to_scsi_dma(uint8_t scsi_id) -{ - cdrom_t *dev; - - uint8_t id = scsi_cdrom_drives[scsi_id]; - int32_t *BufLen = &SCSIDevices[scsi_id].BufferLength; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(SCSIDevices[scsi_id].CmdBuffer, cdbufferb, *BufLen); - cdrom_log("CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], cdbufferb[4], cdbufferb[5], - cdbufferb[6], cdbufferb[7]); - cdrom_log("CD-ROM %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - SCSIDevices[scsi_id].CmdBuffer[0], SCSIDevices[scsi_id].CmdBuffer[1], - SCSIDevices[scsi_id].CmdBuffer[2], SCSIDevices[scsi_id].CmdBuffer[3], - SCSIDevices[scsi_id].CmdBuffer[4], SCSIDevices[scsi_id].CmdBuffer[5], - SCSIDevices[scsi_id].CmdBuffer[6], SCSIDevices[scsi_id].CmdBuffer[7]); - return 1; -} - - -static int -cdrom_write_to_dma(cdrom_t *dev) -{ - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; - int ret = 0; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - cdrom_log("Write to SCSI DMA: (ID %02X)\n", dev->drv->scsi_device_id); - ret = cdrom_write_to_scsi_dma(dev->drv->scsi_device_id); - } else - ret = cdrom_write_to_ide_dma(dev->drv->ide_channel); - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - cdrom_log("CD-ROM %i: SCSI Output data length: %i\n", dev->id, *BufLen); - else - cdrom_log("CD-ROM %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len); + if (msf) { + b[pos] = 0; + b[pos + 1] = subc.abs_m; + b[pos + 2] = subc.abs_s; + b[pos + 3] = subc.abs_f; + pos += 4; + b[pos] = 0; + b[pos + 1] = subc.rel_m; + b[pos + 2] = subc.rel_s; + b[pos + 3] = subc.rel_f; + pos += 4; + } else { + uint32_t dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + dat = MSFtoLBA(subc.rel_m, subc.rel_s, subc.rel_f); + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + } return ret; } -void -cdrom_phase_callback(cdrom_t *dev) +static int +read_toc_normal(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf) { - int ret; + track_info_t ti; + int len = 4; + int c, d, first_track, last_track; + uint32_t temp; - switch(dev->packet_status) { - case CDROM_PHASE_IDLE: - cdrom_log("CD-ROM %i: CDROM_PHASE_IDLE\n", dev->id); - dev->pos = 0; - dev->phase = 1; - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - return; - case CDROM_PHASE_COMMAND: - cdrom_log("CD-ROM %i: CDROM_PHASE_COMMAND\n", dev->id); - dev->status = BUSY_STAT | (dev->status & ERR_STAT); - memcpy(dev->atapi_cdb, cdbufferb, dev->cdb_len); - cdrom_command(dev, dev->atapi_cdb); - return; - case CDROM_PHASE_COMPLETE: - cdrom_log("CD-ROM %i: CDROM_PHASE_COMPLETE\n", dev->id); - dev->status = READY_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; - ui_sb_update_icon(SB_CDROM | dev->id, 0); - cdrom_irq_raise(dev); - return; - case CDROM_PHASE_DATA_OUT: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 0; - cdrom_irq_raise(dev); - return; - case CDROM_PHASE_DATA_OUT_DMA: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT_DMA\n", dev->id); - ret = cdrom_read_from_dma(dev); + dev->ops->get_tracks(dev, &first_track, &last_track); - if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { - cdrom_log("CD-ROM %i: DMA data out phase done\n"); - cdrom_buf_free(dev); - cdrom_command_complete(dev); - } else if (ret == 2) { - cdrom_log("CD-ROM %i: DMA out not enabled, wait\n"); - cdrom_command_bus(dev); - } else { - cdrom_log("CD-ROM %i: DMA data out phase failure\n"); - cdrom_buf_free(dev); - } - return; - case CDROM_PHASE_DATA_IN: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 2; - cdrom_irq_raise(dev); - return; - case CDROM_PHASE_DATA_IN_DMA: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN_DMA\n", dev->id); - ret = cdrom_write_to_dma(dev); + b[2] = first_track; + b[3] = last_track; - if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { - cdrom_log("CD-ROM %i: DMA data in phase done\n", dev->id); - cdrom_buf_free(dev); - cdrom_command_complete(dev); - } else if (ret == 2) { - cdrom_log("CD-ROM %i: DMA in not enabled, wait\n", dev->id); - cdrom_command_bus(dev); - } else { - cdrom_log("CD-ROM %i: DMA data in phase failure\n", dev->id); - cdrom_buf_free(dev); - } - return; - case CDROM_PHASE_ERROR: - cdrom_log("CD-ROM %i: CDROM_PHASE_ERROR\n", dev->id); - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - cdrom_irq_raise(dev); - ui_sb_update_icon(SB_CDROM | dev->id, 0); - return; + d = 0; + for (c = 0; c <= last_track; c++) { + dev->ops->get_track_info(dev, c + 1, 0, &ti); + if (ti.number >= start_track) { + d = c; + break; + } } + + if (start_track != 0xAA) { + dev->ops->get_track_info(dev, c + 1, 0, &ti); + b[2] = ti.number; + } + + for (c = d; c <= last_track; c++) { + dev->ops->get_track_info(dev, c + 1, 0, &ti); + + b[len++] = 0; /* reserved */ + b[len++] = ti.attr; + b[len++] = ti.number; /* track number */ + b[len++] = 0; /* reserved */ + + if (msf) { + b[len++] = 0; + b[len++] = ti.m; + b[len++] = ti.s; + b[len++] = ti.f; + } else { + temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + } + + return len; } -uint32_t -cdrom_read(uint8_t channel, int length) +static int +read_toc_session(cdrom_t *dev, unsigned char *b, int msf) { - cdrom_t *dev; + track_info_t ti; + int len = 4; + uint32_t temp; - uint16_t *cdbufferw; - uint32_t *cdbufferl; + dev->ops->get_track_info(dev, 1, 0, &ti); - uint8_t id = atapi_cdrom_drives[channel]; + if (ti.number == 0) + ti.number = 1; - uint32_t temp = 0; + b[2] = b[3] = 1; + b[len++] = 0; /* reserved */ + b[len++] = ti.attr; + b[len++] = ti.number; /* track number */ + b[len++] = 0; /* reserved */ + if (msf) { + b[len++] = 0; + b[len++] = ti.m; + b[len++] = ti.s; + b[len++] = ti.f; + } else { + temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150; /* Do the - 150. */ + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } - if (id > CDROM_NUM) - return 0; + return len; +} - dev = cdrom[id]; - cdbufferw = (uint16_t *) cdbufferb; - cdbufferl = (uint32_t *) cdbufferb; +static int +read_toc_raw(cdrom_t *dev, unsigned char *b) +{ + track_info_t ti; + int first_track, last_track; + int track, len = 4; - if (!cdbufferb) - return 0; + dev->ops->get_tracks(dev, &first_track, &last_track); - /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, - which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 2048 bytes). */ - switch(length) { - case 1: - temp = (dev->pos < dev->packet_len) ? cdbufferb[dev->pos] : 0; - dev->pos++; - dev->request_pos++; + b[2] = first_track; + b[3] = last_track; + + for (track = first_track; track <= last_track; track++) { + dev->ops->get_track_info(dev, track, 0, &ti); + + b[len++] = track; + b[len++] = ti.attr; + b[len++] = 0; + b[len++] = 0; + b[len++] = 0; + b[len++] = 0; + b[len++] = 0; + b[len++] = 0; + b[len++] = ti.m; + b[len++] = ti.s; + b[len++] = ti.f; + } + + return len; +} + + +int +cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_track, int msf, int max_len) +{ + int len; + + switch(type) { + case CD_TOC_NORMAL: + len = read_toc_normal(dev, b, start_track, msf); break; - case 2: - temp = (dev->pos < dev->packet_len) ? cdbufferw[dev->pos >> 1] : 0; - dev->pos += 2; - dev->request_pos += 2; + case CD_TOC_SESSION: + len = read_toc_session(dev, b, msf); break; - case 4: - temp = (dev->pos < dev->packet_len) ? cdbufferl[dev->pos >> 2] : 0; - dev->pos += 4; - dev->request_pos += 4; + case CD_TOC_RAW: + len = read_toc_raw(dev, b); break; default: + cdrom_log("CD-ROM %i: Unknown TOC read type: %i\n", dev->id, type); return 0; } - if (dev->packet_status == CDROM_PHASE_DATA_IN) { - cdrom_log("CD-ROM %i: Returning: %04X (buffer position: %05i, request position: %05i)\n", - id, temp, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - cdrom_log("CD-ROM %i: Issuing read callback\n", id); - cdrom_pio_request(dev, 0); - } - return temp; - } else { - cdrom_log("CD-ROM %i: Returning: 0000 (buffer position: %05i, request position: %05i)\n", - id, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); + len = MIN(len, max_len); + + b[0] = (uint8_t) (((len - 2) >> 8) & 0xff); + b[1] = (uint8_t) ((len - 2) & 0xff); + + return len; +} + + +static int +track_type_is_valid(uint8_t id, int type, int flags, int audio, int mode2) +{ + if (!(flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ + cdrom_log("CD-ROM %i: [Any Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); return 0; } + + if ((type != 1) && !audio) { + if (!(flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ + cdrom_log("CD-ROM %i: [Any Data Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); + return 0; + } + + if ((flags & 0x06) == 0x06) { + cdrom_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id); + return 0; + } + + if (((flags & 0x700) == 0x300) || ((flags & 0x700) > 0x400)) { + cdrom_log("CD-ROM %i: [Any Data Mode] Invalid subchannel data flags (%02X)\n", id, flags & 0x700); + return 0; + } + + if ((flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */ + cdrom_log("CD-ROM %i: [Any Data Mode] EDC/ECC without user data is an illegal mode\n", id); + return 0; + } + + if (((flags & 0xf0) == 0x90) || ((flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */ + cdrom_log("CD-ROM %i: [Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n", id); + return 0; + } + + if (((type > 3) && (type != 8)) || (mode2 && (mode2 & 0x03))) { + if ((flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */ + cdrom_log("CD-ROM %i: [Any XA Mode 2] 0x30/0x38 are illegal modes\n", id); + return 0; + } + if (((flags & 0xf0) == 0xb0) || ((flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */ + cdrom_log("CD-ROM %i: [Any XA Mode 2] 0xBx and 0xDx are illegal modes\n", id); + return 0; + } + } + } + + return 1; +} + + +static void +read_sector_to_buffer(cdrom_t *dev, uint8_t *rbuf, uint32_t msf, uint32_t lba, int mode2, int len) +{ + uint8_t *bb = rbuf; + + dev->ops->read_sector(dev, CD_READ_DATA, rbuf + 16, lba); + + /* Sync bytes */ + bb[0] = 0; + memset(bb + 1, 0xff, 10); + bb[11] = 0; + bb += 12; + + /* Sector header */ + bb[0] = (msf >> 16) & 0xff; + bb[1] = (msf >> 8) & 0xff; + bb[2] = msf & 0xff; + + bb[3] = 1; /* mode 1 data */ + bb += mode2 ? 12 : 4; + bb += len; + if (mode2 && ((mode2 & 0x03) == 1)) + memset(bb, 0, 280); + else if (!mode2) + memset(bb, 0, 288); +} + + +static void +read_audio(cdrom_t *dev, uint32_t lba, uint8_t *b) +{ + dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + + memcpy(b, raw_buffer, 2352); + + cdrom_sector_size = 2352; +} + + +static void +read_mode1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2048)) + read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); + else + dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_log("CD-ROM %i: [Mode 1] Sync\n", dev->id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_log("CD-ROM %i: [Mode 1] Header\n", dev->id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + if (!(cdrom_sector_flags & 0x10)) { /* No user data */ + cdrom_log("CD-ROM %i: [Mode 1] Sub-header\n", dev->id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_log("CD-ROM %i: [Mode 1] User data\n", dev->id); + memcpy(b, raw_buffer + 16, 2048); + cdrom_sector_size += 2048; + b += 2048; + } + + if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ + cdrom_log("CD-ROM %i: [Mode 1] EDC/ECC\n", dev->id); + memcpy(b, raw_buffer + 2064, 288); + cdrom_sector_size += 288; + b += 288; + } } -void -cdrom_write(uint8_t channel, uint32_t val, int length) +static void +read_mode2_non_xa(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) { - cdrom_t *dev; + if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2336)) + read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2336); + else + dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); - uint16_t *cdbufferw; - uint32_t *cdbufferl; + cdrom_sector_size = 0; - uint8_t id = atapi_cdrom_drives[channel]; - - if (id > CDROM_NUM) - return; - - dev = cdrom[id]; - - if ((dev->packet_status == CDROM_PHASE_IDLE) && !cdbufferb) - cdrom_buf_alloc(dev, dev->cdb_len); - - cdbufferw = (uint16_t *) cdbufferb; - cdbufferl = (uint32_t *) cdbufferb; - - if (!cdbufferb) - return; - - switch(length) { - case 1: - cdbufferb[dev->pos] = val & 0xff; - dev->pos++; - dev->request_pos++; - break; - case 2: - cdbufferw[dev->pos >> 1] = val & 0xffff; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - cdbufferl[dev->pos >> 2] = val; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return; + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_log("CD-ROM %i: [Mode 2 Formless] Sync\n", dev->id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; } - if (dev->packet_status == CDROM_PHASE_DATA_OUT) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - cdrom_pio_request(dev, 1); - } - return; - } else if (dev->packet_status == CDROM_PHASE_IDLE) { - if (dev->pos >= dev->cdb_len) { - dev->pos = 0; - dev->status = BUSY_STAT; - dev->packet_status = CDROM_PHASE_COMMAND; - timer_process(); - cdrom_phase_callback(dev); - timer_update_outstanding(); - } - return; + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_log("CD-ROM %i: [Mode 2 Formless] Header\n", dev->id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; } + + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + cdrom_log("CD-ROM %i: [Mode 2 Formless] Sub-header\n", dev->id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_log("CD-ROM %i: [Mode 2 Formless] User data\n", dev->id); + memcpy(b, raw_buffer + 24, 2336); + cdrom_sector_size += 2336; + b += 2336; + } +} + + +static void +read_mode2_xa_form1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2048)) + read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); + else + dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", dev->id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", dev->id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", dev->id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", dev->id); + memcpy(b, raw_buffer + 24, 2048); + cdrom_sector_size += 2048; + b += 2048; + } + + if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", dev->id); + memcpy(b, raw_buffer + 2072, 280); + cdrom_sector_size += 280; + b += 280; + } +} + + +static void +read_mode2_xa_form2(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2324)) + read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2324); + else + dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sync\n", dev->id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Header\n", dev->id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sub-header\n", dev->id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] User data\n", dev->id); + memcpy(b, raw_buffer + 24, 2328); + cdrom_sector_size += 2328; + b += 2328; + } +} + + +int +cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, + int cdrom_sector_flags, int *len) +{ + uint8_t *b, *temp_b; + uint32_t msf, lba; + int audio = 0, mode2 = 0; + int m, s, f; + + if (dev->cd_status == CD_STATUS_EMPTY) + return 0; + + b = temp_b = buffer; + + *len = 0; + + if (ismsf) { + m = (sector >> 16) & 0xff; + s = (sector >> 8) & 0xff; + f = sector & 0xff; + lba = MSFtoLBA(m, s, f) - 150; + msf = sector; + } else { + lba = sector; + msf = cdrom_lba_to_msf_accurate(sector); + } + + if (dev->ops->track_type) + audio = dev->ops->track_type(dev, lba); + + mode2 = audio & ~CD_TRACK_AUDIO; + audio &= CD_TRACK_AUDIO; + + memset(raw_buffer, 0, 2448); + memset(extra_buffer, 0, 296); + + if (!(cdrom_sector_flags & 0xf0)) { /* 0x00 and 0x08 are illegal modes */ + cdrom_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", dev->id); + return 0; + } + + if (!track_type_is_valid(dev->id, cdrom_sector_type, cdrom_sector_flags, audio, mode2)) + return 0; + + if ((cdrom_sector_type > 5) && (cdrom_sector_type != 8)) { + cdrom_log("CD-ROM %i: Attempting to read an unrecognized sector type from an image\n", dev->id); + return 0; + } else if (cdrom_sector_type == 1) { + if (!audio || (dev->cd_status == CD_STATUS_DATA_ONLY)) { + cdrom_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", dev->id); + return 0; + } + + read_audio(dev, lba, temp_b); + } else if (cdrom_sector_type == 2) { + if (audio || mode2) { + cdrom_log("CD-ROM %i: [Mode 1] Attempting to read a sector of another type\n", dev->id); + return 0; + } + + read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 3) { + if (audio || !mode2 || (mode2 & 0x03)) { + cdrom_log("CD-ROM %i: [Mode 2 Formless] Attempting to read a sector of another type\n", dev->id); + return 0; + } + + read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 4) { + if (audio || !mode2 || ((mode2 & 0x03) != 1)) { + cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a sector of another type\n", dev->id); + return 0; + } + + read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 5) { + if (audio || !mode2 || ((mode2 & 0x03) != 2)) { + cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Attempting to read a sector of another type\n", dev->id); + return 0; + } + + read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 8) { + if (audio) { + cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", dev->id); + return 0; + } + + if (mode2 && ((mode2 & 0x03) == 1)) + read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + else if (!mode2) + read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + else { + cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size is not 2048 bytes\n", dev->id); + return 0; + } + } else { + if (mode2) { + if ((mode2 & 0x03) == 0x01) + read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + else if ((mode2 & 0x03) == 0x02) + read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + else + read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else { + if (audio) + read_audio(dev, lba, temp_b); + else + read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + } + } + + if ((cdrom_sector_flags & 0x06) == 0x02) { + /* Add error flags. */ + cdrom_log("CD-ROM %i: Error flags\n", dev->id); + memcpy(b + cdrom_sector_size, extra_buffer, 294); + cdrom_sector_size += 294; + } else if ((cdrom_sector_flags & 0x06) == 0x04) { + /* Add error flags. */ + cdrom_log("CD-ROM %i: Full error flags\n", dev->id); + memcpy(b + cdrom_sector_size, extra_buffer, 296); + cdrom_sector_size += 296; + } + + if ((cdrom_sector_flags & 0x700) == 0x100) { + cdrom_log("CD-ROM %i: Raw subchannel data\n", dev->id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); + cdrom_sector_size += 96; + } else if ((cdrom_sector_flags & 0x700) == 0x200) { + cdrom_log("CD-ROM %i: Q subchannel data\n", dev->id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16); + cdrom_sector_size += 16; + } else if ((cdrom_sector_flags & 0x700) == 0x400) { + cdrom_log("CD-ROM %i: R/W subchannel data\n", dev->id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); + cdrom_sector_size += 96; + } + + *len = cdrom_sector_size; + + return 1; } @@ -3179,77 +974,153 @@ cdrom_global_init(void) { /* Clear the global data. */ memset(cdrom, 0x00, sizeof(cdrom)); - memset(cdrom_drives, 0x00, sizeof(cdrom_drives)); +} + + +static void +cdrom_drive_reset(cdrom_t *dev) +{ + dev->priv = NULL; + dev->insert = NULL; + dev->close = NULL; + dev->get_volume = NULL; + dev->get_channel = NULL; } void cdrom_hard_reset(void) { - int c; cdrom_t *dev; + int i; - for (c = 0; c < CDROM_NUM; c++) { - if (cdrom_drives[c].bus_type) { - cdrom_log("CDROM hard_reset drive=%d\n", c); + for (i = 0; i < CDROM_NUM; i++) { + dev = &cdrom[i]; + if (dev->bus_type) { + cdrom_log("CD-ROM %i: Hard reset\n", i); - if (!cdrom[c]) { - cdrom[c] = (cdrom_t *) malloc(sizeof(cdrom_t)); - memset(cdrom[c], 0, sizeof(cdrom_t)); + dev->id = i; + + cdrom_drive_reset(dev); + + switch(dev->bus_type) { + case CDROM_BUS_ATAPI: + case CDROM_BUS_SCSI: + scsi_cdrom_drive_reset(i); + break; + + default: + break; } - dev = cdrom[c]; + dev->cd_status = CD_STATUS_EMPTY; - /* Set the numerical ID because of ->handler and logging. */ - dev->id = c; - - cdrom_init(dev); - - if (dev->drv->host_drive == 200) { - image_open(c, cdrom_image[c].image_path); - image_reset(c); - } else - cdrom_null_open(c); + if (dev->host_drive == 200) + cdrom_image_open(dev, dev->image_path); } } - build_atapi_cdrom_map(); - sound_cd_thread_reset(); } -void -cdrom_close_handler(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - switch (dev->drv->host_drive) { - case 200: - image_close(id); - break; - default: - null_close(id); - break; - } -} - - void cdrom_close(void) { cdrom_t *dev; - int c; + int i; - for (c = 0; c < CDROM_NUM; c++) { - dev = cdrom[c]; + for (i = 0; i < CDROM_NUM; i++) { + dev = &cdrom[i]; - if (dev) { - if (dev->drv && dev->handler) - cdrom_close_handler(c); + if (dev->close) + dev->close(dev->priv); - free(cdrom[c]); - cdrom[c] = NULL; - } + if (dev->ops && dev->ops->exit) + dev->ops->exit(dev); + + dev->ops = NULL; + dev->priv = NULL; + + cdrom_drive_reset(dev); } } + + +/* Signal disc change to the emulated machine. */ +void +cdrom_insert(uint8_t id) +{ + cdrom_t *dev = &cdrom[id]; + + if (dev->bus_type) { + if (dev->insert) + dev->insert(dev->priv); + } +} + + +/* The mechanics of ejecting a CD-ROM from a drive. */ +void +cdrom_eject(uint8_t id) +{ + cdrom_t *dev = &cdrom[id]; + + /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ + if (dev->host_drive == 0) { + /* Switch from empty to empty. Do nothing. */ + return; + } + + if (dev->host_drive == 200) + wcscpy(dev->prev_image_path, dev->image_path); + + dev->prev_host_drive = dev->host_drive; + dev->host_drive = 0; + + dev->ops->exit(dev); + dev->ops = NULL; + memset(dev->image_path, 0, sizeof(dev->image_path)); + + cdrom_insert(id); + + plat_cdrom_ui_update(id, 0); + + config_save(); +} + + +/* The mechanics of re-loading a CD-ROM drive. */ +void +cdrom_reload(uint8_t id) +{ + cdrom_t *dev = &cdrom[id]; + + if ((dev->host_drive == dev->prev_host_drive) || + (dev->prev_host_drive == 0) || (dev->host_drive != 0)) { + /* Switch from empty to empty. Do nothing. */ + return; + } + + if (dev->ops && dev->ops->exit) + dev->ops->exit(dev); + dev->ops = NULL; + memset(dev->image_path, 0, sizeof(dev->image_path)); + + if (dev->prev_host_drive == 200) { + /* Reload a previous image. */ + wcscpy(dev->image_path, dev->prev_image_path); + cdrom_image_open(dev, dev->image_path); + + cdrom_insert(id); + + if (wcslen(dev->image_path) == 0) + dev->host_drive = 0; + else + dev->host_drive = 200; + } + + plat_cdrom_ui_update(id, 1); + + config_save(); +} diff --git a/src/cdrom/cdrom.h b/src/cdrom/cdrom.h index 9f6f4d476..ec141a5f9 100644 --- a/src/cdrom/cdrom.h +++ b/src/cdrom/cdrom.h @@ -6,14 +6,13 @@ * * This file is part of the 86Box distribution. * - * Implementation of the CD-ROM drive with SCSI(-like) - * commands, for both ATAPI and SCSI usage. + * Generic CD-ROM drive core header. * - * Version: @(#)cdrom.h 1.0.13 2018/06/18 + * Version: @(#)cdrom.h 1.0.18 2019/09/26 * * Author: Miran Grca, * - * Copyright 2016,2017 Miran Grca. + * Copyright 2016-2019 Miran Grca. */ #ifndef EMU_CDROM_H #define EMU_CDROM_H @@ -23,26 +22,38 @@ #define CD_STATUS_EMPTY 0 #define CD_STATUS_DATA_ONLY 1 -#define CD_STATUS_PLAYING 2 -#define CD_STATUS_PAUSED 3 +#define CD_STATUS_PAUSED 2 +#define CD_STATUS_PLAYING 3 #define CD_STATUS_STOPPED 4 +#define CD_STATUS_PLAYING_COMPLETED 5 -#define CDROM_PHASE_IDLE 0x00 -#define CDROM_PHASE_COMMAND 0x01 -#define CDROM_PHASE_COMPLETE 0x02 -#define CDROM_PHASE_DATA_IN 0x03 -#define CDROM_PHASE_DATA_IN_DMA 0x04 -#define CDROM_PHASE_DATA_OUT 0x05 -#define CDROM_PHASE_DATA_OUT_DMA 0x06 -#define CDROM_PHASE_ERROR 0x80 +/* Medium changed flag. */ +#define CD_STATUS_MEDIUM_CHANGED 0x80 + +#define CD_TRACK_AUDIO 0x08 +#define CD_TRACK_MODE2 0x04 + +#define CD_READ_DATA 0 +#define CD_READ_AUDIO 1 +#define CD_READ_RAW 2 + +#define CD_TOC_NORMAL 0 +#define CD_TOC_SESSION 1 +#define CD_TOC_RAW 2 #define BUF_SIZE 32768 #define CDROM_IMAGE 200 -#define CDROM_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) +/* This is so that if/when this is changed to something else, + changing this one define will be enough. */ +#define CDROM_EMPTY !dev->host_drive +#ifdef __cplusplus +extern "C" { +#endif + enum { CDROM_BUS_DISABLED = 0, CDROM_BUS_ATAPI = 4, @@ -51,138 +62,105 @@ enum { }; -typedef struct { - int (*ready)(uint8_t id); - int (*medium_changed)(uint8_t id); - int (*media_type_id)(uint8_t id); +/* To shut up the GCC compilers. */ +struct cdrom; - int (*audio_callback)(uint8_t id, int16_t *output, int len); - void (*audio_stop)(uint8_t id); - int (*readtoc)(uint8_t id, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); - int (*readtoc_session)(uint8_t id, uint8_t *b, int msf, int maxlen); - int (*readtoc_raw)(uint8_t id, uint8_t *b, int maxlen); - uint8_t (*getcurrentsubchannel)(uint8_t id, uint8_t *b, int msf); - int (*readsector_raw)(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len); - uint8_t (*playaudio)(uint8_t id, uint32_t pos, uint32_t len, int ismsf); - void (*pause)(uint8_t id); - void (*resume)(uint8_t id); - uint32_t (*size)(uint8_t id); - int (*status)(uint8_t id); - void (*stop)(uint8_t id); - void (*exit)(uint8_t id); -} CDROM; typedef struct { - int host_drive; - int prev_host_drive; + uint8_t attr, track, + index, + abs_m, abs_s, abs_f, + rel_m, rel_s, rel_f; +} subchannel_t; - unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ +typedef struct { + int number; + uint8_t attr, m, s, f; +} track_info_t; - uint8_t speed, ide_channel, - bus_mode; /* Bit 0 = PIO suported; +/* Define the various CD-ROM drive operations (ops). */ +typedef struct { + void (*get_tracks)(struct cdrom *dev, int *first, int *last); + void (*get_track_info)(struct cdrom *dev, uint32_t track, int end, track_info_t *ti); + void (*get_subchannel)(struct cdrom *dev, uint32_t lba, subchannel_t *subc); + int (*sector_size)(struct cdrom *dev, uint32_t lba); + int (*read_sector)(struct cdrom *dev, int type, uint8_t *b, uint32_t lba); + int (*track_type)(struct cdrom *dev, uint32_t lba); + void (*exit)(struct cdrom *dev); +} cdrom_ops_t; + +typedef struct cdrom { + uint8_t id, + res, res0, /* Reserved for other ID's. */ + res1, + ide_channel, scsi_device_id, + bus_type, /* 0 = ATAPI, 1 = SCSI */ + bus_mode, /* Bit 0 = PIO suported; Bit 1 = DMA supportd. */ + cd_status, /* Struct variable reserved for + media status. */ + speed, cur_speed; - unsigned int scsi_device_id, sound_on; -} cdrom_drive_t; + FILE* img_fp; + void *priv; -typedef struct { - mode_sense_pages_t ms_pages_saved; + wchar_t image_path[1024], + prev_image_path[1024]; - CDROM *handler; - cdrom_drive_t *drv; + uint32_t sound_on, cdrom_capacity, + pad, seek_pos, + seek_diff, cd_end; - uint8_t previous_command, - error, features, - status, phase, - id, *buffer, - atapi_cdb[16], - current_cdb[16], - sense[256]; + int host_drive, prev_host_drive, + cd_buflen; + + const cdrom_ops_t *ops; + + void *image; + + void (*insert)(void *p); + void (*close)(void *p); + uint32_t (*get_volume)(void *p, int channel); + uint32_t (*get_channel)(void *p, int channel); - uint16_t request_length, max_transfer_len; int16_t cd_buffer[BUF_SIZE]; - - int media_status, is_dma, - packet_status, requested_blocks, - current_page_len, current_page_pos, - mode_select_phase, do_page_save, - total_length, written_length, - callback, data_pos, - cd_status, prev_status, - unit_attention, request_pos, - total_read, cur_speed, - block_total, all_blocks_total, - old_len, block_descriptor_len, - init_length, last_subchannel_pos, - cd_buflen, cd_state, - handler_inited, disc_changed; - - uint32_t sector_pos, sector_len, - seek_pos, seek_diff, - pos, packet_len, - cdb_len, cd_end, - cdrom_capacity; - - uint64_t current_page_code; } cdrom_t; -typedef struct { - int image_is_iso; - wchar_t image_path[1024], - *prev_image_path; - FILE* image; -} cdrom_image_t; - -extern cdrom_t *cdrom[CDROM_NUM]; -extern cdrom_drive_t cdrom_drives[CDROM_NUM]; -extern cdrom_image_t cdrom_image[CDROM_NUM]; -extern uint8_t atapi_cdrom_drives[8]; -extern uint8_t scsi_cdrom_drives[16]; - -#define cdrom_sense_error dev->sense[0] -#define cdrom_sense_key dev->sense[2] -#define cdrom_asc dev->sense[12] -#define cdrom_ascq dev->sense[13] -#define cdrom_drive cdrom_drives[id].host_drive - - -#ifdef __cplusplus -extern "C" { -#endif - -extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); -extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); -extern void (*ide_bus_master_set_irq)(int channel, void *priv); -extern void *ide_bus_master_priv[2]; - -extern uint32_t cdrom_mode_sense_get_channel(cdrom_t *dev, int channel); -extern uint32_t cdrom_mode_sense_get_volume(cdrom_t *dev, int channel); -extern void build_atapi_cdrom_map(void); -extern void build_scsi_cdrom_map(void); -extern int cdrom_CDROM_PHASE_to_scsi(cdrom_t *dev); -extern int cdrom_atapi_phase_to_scsi(cdrom_t *dev); -extern void cdrom_command(cdrom_t *dev, uint8_t *cdb); -extern void cdrom_phase_callback(cdrom_t *dev); -extern uint32_t cdrom_read(uint8_t channel, int length); -extern void cdrom_write(uint8_t channel, uint32_t val, int length); +extern cdrom_t cdrom[CDROM_NUM]; extern int cdrom_lba_to_msf_accurate(int lba); +extern double cdrom_seek_time(cdrom_t *dev); +extern void cdrom_stop(cdrom_t *dev); +extern int cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len); +extern uint8_t cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf); +extern void cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume); +extern uint8_t cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf); +extern int cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, + unsigned char start_track, int msf, int max_len); +extern int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, + int cdrom_sector_type, int cdrom_sector_flags, int *len); +extern void cdrom_seek(cdrom_t *dev, uint32_t pos); extern void cdrom_close_handler(uint8_t id); -extern void cdrom_close(void); -extern void cdrom_reset(cdrom_t *dev); -extern void cdrom_set_signature(cdrom_t *dev); -extern void cdrom_request_sense_for_scsi(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length); -extern void cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); -extern void cdrom_insert(cdrom_t *dev); +extern void cdrom_insert(uint8_t id); +extern void cdrom_eject(uint8_t id); +extern void cdrom_reload(uint8_t id); + +extern int cdrom_image_open(cdrom_t *dev, const wchar_t *fn); +extern void cdrom_image_close(cdrom_t *dev); +extern void cdrom_image_reset(cdrom_t *dev); + +extern void cdrom_update_cdb(uint8_t *cdb, int lba_pos, + int number_of_blocks); extern int find_cdrom_for_scsi_id(uint8_t scsi_id); -extern int cdrom_read_capacity(cdrom_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); +extern void cdrom_close(void); extern void cdrom_global_init(void); extern void cdrom_global_reset(void); extern void cdrom_hard_reset(void); +extern void scsi_cdrom_drive_reset(int c); #ifdef __cplusplus } diff --git a/src/cdrom/cdrom_dosbox.cpp b/src/cdrom/cdrom_dosbox.cpp deleted file mode 100644 index 0408be688..000000000 --- a/src/cdrom/cdrom_dosbox.cpp +++ /dev/null @@ -1,655 +0,0 @@ -/* - * 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 */ - -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#ifdef _WIN32 -//FIXME: should not be needed. */ -# define _GNU_SOURCE -#endif -#include -#include - -#include -#include -#include -#include -#include -#include -#include //GCC 2.95 -#include -#include -#include -#include "../plat.h" -#include "cdrom_dosbox.h" - -#ifndef _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) -{ - memset(fn, 0, sizeof(fn)); - strcpy(fn, filename); - file = fopen64(fn, "rb"); - if (file == NULL) - error = true; - else - error = false; -} - -CDROM_Interface_Image::BinaryFile::~BinaryFile() -{ - fclose(file); - file = NULL; - memset(fn, 0, sizeof(fn)); -} - -bool CDROM_Interface_Image::BinaryFile::read(Bit8u *buffer, uint64_t seek, uint64_t count) -{ - fseeko64(file, seek, SEEK_SET); - fread(buffer, 1, count, file); - return 1; -} - -uint64_t CDROM_Interface_Image::BinaryFile::getLength() -{ - fseeko64(file, 0, SEEK_END); - return ftello64(file); -} - -CDROM_Interface_Image::CDROM_Interface_Image() -{ - // printf("CDROM_Interface_Image constructor\n"); -} - -CDROM_Interface_Image::~CDROM_Interface_Image() -{ - // printf("CDROM_Interface_Image destructor\n"); - ClearTracks(); -} - -void CDROM_Interface_Image::InitNewMedia() -{ -} - -bool CDROM_Interface_Image::SetDevice(char* path, int forceCD) -{ - (void)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); */ - /* Note by Kotori: Yes, the absolute position should be adjusted by 150, but not the relative position. */ - FRAMES_TO_MSF(sector - tracks[track - 1].start, &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) -{ - (void)unload; - return true; -} - -int CDROM_Interface_Image::GetTrack(unsigned 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) -{ - uint64_t length; - - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - uint64_t s = (uint64_t) sector; - uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); - if (tracks[track].mode2) - length = (raw ? RAW_SECTOR_SIZE : 2336); - else - 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::ReadSectorSub(Bit8u *buffer, unsigned long sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - uint64_t s = (uint64_t) sector; - uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); - if (tracks[track].sectorSize != 2448) return false; - - return tracks[track].file->read(buffer, seek, 2448); -} - -int CDROM_Interface_Image::GetSectorSize(unsigned long sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return 0; - - return tracks[track].sectorSize; -} - -bool CDROM_Interface_Image::IsMode2(unsigned long sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - if (tracks[track].mode2) - { - return true; - } - else - { - return false; - } -} - -int CDROM_Interface_Image::GetMode2Form(unsigned long sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - return tracks[track].form; -} - -bool CDROM_Interface_Image::LoadIsoFile(char* filename) -{ - tracks.clear(); - - // data track - Track track = {0, 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;//IMPORTANT: This is needed. - track.attr = DATA_TRACK;//data - track.form = 0; - - // 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, 2324, true)) { - track.sectorSize = 2324; - track.form = 2; - track.mode2 = true; - } 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 { - /* Unknown mode: Assume regular 2048-byte sectors, this is needed so Apple Rhapsody ISO's can be mounted. */ - track.sectorSize = COOKED_SECTOR_SIZE; - track.mode2 = false; - } - - track.length = track.file->getLength() / track.sectorSize; - tracks.push_back(track); - - // leadout track - track.number = 2; - track.track_number = 0xAA; - track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ - track.start = track.length; - track.length = 0; - track.file = NULL; - tracks.push_back(track); - - return true; -} - -bool CDROM_Interface_Image::CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2) -{ - Bit8u pvd[COOKED_SECTOR_SIZE]; - uint64_t 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)); -} - -#ifdef _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, 0, false, NULL}; - tracks.clear(); - uint64_t shift = 0; - uint64_t currPregap = 0; - uint64_t totalPregap = 0; - uint64_t 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); - - track.form = 0; - - 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/2048") { - track.form = 1; - track.sectorSize = 2048; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "MODE2/2324") { - track.form = 2; - track.sectorSize = 2324; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "MODE2/2336") { - track.sectorSize = 2336; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "MODE2/2352") { - track.form = 1; /* Assume this is XA Mode 2 Form 1. */ - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "CDG/2448") { - track.sectorSize = 2448; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "CDI/2336") { - track.sectorSize = 2336; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "CDI/2352") { - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = true; - } else success = false; - - canAddTrack = true; - } - else if (command == "INDEX") { - uint64_t index; - line >> index; - uint64_t 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.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ - // track.attr = last_attr | 0x02; - 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, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap) -{ - // frames between index 0(prestart) and 1(curr.start) must be skipped - uint64_t 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 { - uint64_t tmp = prev.file->getLength() - ((uint64_t) prev.skip); - prev.length = tmp / ((uint64_t) 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 0 - /* curr.length is unsigned, so... --FvK */ - if (curr.length < 0) return false; -#endif - - 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(uint64_t &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/cdrom/cdrom_dosbox.h b/src/cdrom/cdrom_dosbox.h deleted file mode 100644 index f5dc4f346..000000000 --- a/src/cdrom/cdrom_dosbox.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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 -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, uint64_t seek, uint64_t count) = 0; - virtual uint64_t getLength() = 0; - virtual ~TrackFile() { }; - }; - - class BinaryFile : public TrackFile { - public: - BinaryFile(const char *filename, bool &error); - ~BinaryFile(); - bool read(Bit8u *buffer, uint64_t seek, uint64_t count); - uint64_t getLength(); - private: - BinaryFile(); - char fn[260]; - FILE *file; - }; - - struct Track { - int number; - int track_number; - int attr; - int form; - uint64_t start; - uint64_t length; - uint64_t skip; - uint64_t 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 ReadSectorSub (Bit8u *buffer, unsigned long sector); - int GetSectorSize (unsigned long sector); - bool IsMode2 (unsigned long sector); - int GetMode2Form (unsigned long sector); - bool HasDataTrack (void); - bool HasAudioTracks (void); - - int GetTrack (unsigned int sector); - -private: - // player -static void CDAudioCallBack(Bitu len); - - void ClearTracks(); - bool LoadIsoFile(char *filename); - bool CanReadPVD(TrackFile *file, uint64_t 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(uint64_t &frames, std::istream &in); - bool GetCueString(std::string &str, std::istream &in); - bool AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap); - - std::vector tracks; -typedef std::vector::iterator track_it; - std::string mcn; -}; - -void cdrom_image_log(const char *format, ...); - -#endif /* __CDROM_INTERFACE__ */ diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c new file mode 100644 index 000000000..34a2dcc29 --- /dev/null +++ b/src/cdrom/cdrom_image.c @@ -0,0 +1,295 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CD-ROM image support. + * + * Version: @(#)cdrom_image.c 1.0.11 2019/03/06 + * + * Author: RichardG867, + * Miran Grca, + * bit, + * + * Copyright 2015-2019 Richardg867. + * Copyright 2015-2019 Miran Grca. + * Copyright 2017-2019 bit. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../plat.h" +#include "../scsi/scsi_device.h" +#include "cdrom_image_backend.h" +#include "cdrom.h" +#include "cdrom_image.h" + + +#ifdef ENABLE_CDROM_IMAGE_LOG +int cdrom_image_do_log = ENABLE_CDROM_IMAGE_LOG; + + +void +cdrom_image_log(const char *fmt, ...) +{ + va_list ap; + + if (cdrom_image_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cdrom_image_log(fmt, ...) +#endif + + +/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: + there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start + of the audio while audio still plays. With an absolute conversion, the counter is fine. */ +#define MSFtoLBA(m,s,f) ((((m * 60) + s) * 75) + f) + + +static void +image_get_tracks(cdrom_t *dev, int *first, int *last) +{ + cd_img_t *img = (cd_img_t *)dev->image; + TMSF tmsf; + + cdi_get_audio_tracks(img, first, last, &tmsf); +} + + +static void +image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) +{ + cd_img_t *img = (cd_img_t *)dev->image; + TMSF tmsf; + + cdi_get_audio_track_info(img, end, track, &ti->number, &tmsf, &ti->attr); + + ti->m = tmsf.min; + ti->s = tmsf.sec; + ti->f = tmsf.fr; +} + + +static void +image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) +{ + cd_img_t *img = (cd_img_t *)dev->image; + TMSF rel_pos, abs_pos; + + cdi_get_audio_sub(img, lba, &subc->attr, &subc->track, &subc->index, + &rel_pos, &abs_pos); + + subc->abs_m = abs_pos.min; + subc->abs_s = abs_pos.sec; + subc->abs_f = abs_pos.fr; + + subc->rel_m = rel_pos.min; + subc->rel_s = rel_pos.sec; + subc->rel_f = rel_pos.fr; +} + + +static int +image_get_capacity(cdrom_t *dev) +{ + cd_img_t *img = (cd_img_t *)dev->image; + int first_track, last_track; + int number, c; + unsigned char attr; + TMSF tmsf; + uint32_t lb = 0; + uint32_t address; + + if (!img) + return 0; + + cdi_get_audio_tracks(img, &first_track, &last_track, &tmsf); + + for (c = 0; c <= last_track; c++) { + cdi_get_audio_track_info(img, 0, c + 1, &number, &tmsf, &attr); + address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */ + if (address > lb) + lb = address; + } + + return lb; +} + + +static int +image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) +{ + cd_img_t *img = (cd_img_t *)dev->image; + uint8_t attr; + TMSF tmsf; + int m, s, f; + int number; + + if (!img || (dev->cd_status == CD_STATUS_DATA_ONLY)) + return 0; + + if (ismsf) { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + pos = MSFtoLBA(m, s, f) - 150; + } + + /* GetTrack requires LBA. */ + cdi_get_audio_track_info(img, 0, cdi_get_track(img, pos), &number, &tmsf, &attr); + + return attr == AUDIO_TRACK; +} + + +static int +image_sector_size(struct cdrom *dev, uint32_t lba) +{ + cd_img_t *img = (cd_img_t *)dev->image; + + return cdi_get_sector_size(img, lba); +} + + +static int +image_read_sector(struct cdrom *dev, int type, uint8_t *b, uint32_t lba) +{ + cd_img_t *img = (cd_img_t *)dev->image; + + switch (type) { + case CD_READ_DATA: + return cdi_read_sector(img, b, 0, lba); + case CD_READ_AUDIO: + return cdi_read_sector(img, b, 1, lba); + case CD_READ_RAW: + if (cdi_get_sector_size(img, lba) == 2352) + return cdi_read_sector(img, b, 1, lba); + else + return cdi_read_sector_sub(img, b, lba); + default: + cdrom_image_log("CD-ROM %i: Unknown CD read type\n", dev->id); + return 0; + } +} + + +static int +image_track_type(cdrom_t *dev, uint32_t lba) +{ + cd_img_t *img = (cd_img_t *)dev->image; + + if (img) { + if (image_is_track_audio(dev, lba, 0)) + return CD_TRACK_AUDIO; + else { + if (cdi_is_mode2(img, lba)) + return CD_TRACK_MODE2 | cdi_get_mode2_form(img, lba); + } + } + + return 0; +} + + +static void +image_exit(cdrom_t *dev) +{ + cd_img_t *img = (cd_img_t *)dev->image; + +cdrom_image_log("CDROM: image_exit(%ls)\n", dev->image_path); + dev->cd_status = CD_STATUS_EMPTY; + + if (img) { + cdi_close(img); + dev->image = NULL; + } + + dev->ops = NULL; +} + + +static const cdrom_ops_t cdrom_image_ops = { + image_get_tracks, + image_get_track_info, + image_get_subchannel, + image_sector_size, + image_read_sector, + image_track_type, + image_exit +}; + + +static int +image_open_abort(cdrom_t *dev) +{ + cdrom_image_close(dev); + dev->ops = NULL; + dev->host_drive = 0; + return 1; +} + + +int +cdrom_image_open(cdrom_t *dev, const wchar_t *fn) +{ + cd_img_t *img; + + wcscpy(dev->image_path, fn); + + /* Create new instance of the CDROM_Image class. */ + img = (cd_img_t *) malloc(sizeof(cd_img_t)); + + /* This guarantees that if ops is not NULL, then + neither is the image pointer. */ + if (!img) + return image_open_abort(dev); + + memset(img, 0, sizeof(cd_img_t)); + dev->image = img; + + /* Open the image. */ + if (!cdi_set_device(img, fn)) + return image_open_abort(dev); + + /* All good, reset state. */ + if (! wcscasecmp(plat_get_extension((wchar_t *) fn), L"ISO")) + dev->cd_status = CD_STATUS_DATA_ONLY; + else + dev->cd_status = CD_STATUS_STOPPED; + dev->seek_pos = 0; + dev->cd_buflen = 0; + dev->cdrom_capacity = image_get_capacity(dev); + cdrom_image_log("CD-ROM capacity: %i sectors (%i bytes)\n", dev->cdrom_capacity, dev->cdrom_capacity << 11); + + /* Attach this handler to the drive. */ + dev->ops = &cdrom_image_ops; + + return 0; +} + + +void +cdrom_image_close(cdrom_t *dev) +{ + cdrom_image_log("CDROM: image_close(%ls)\n", dev->image_path); + + if (dev && dev->ops && dev->ops->exit) + dev->ops->exit(dev); +} diff --git a/src/cdrom/cdrom_image.cc b/src/cdrom/cdrom_image.cc deleted file mode 100644 index c1a301ba6..000000000 --- a/src/cdrom/cdrom_image.cc +++ /dev/null @@ -1,1107 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * CD-ROM image support. - * - * Version: @(#)cdrom_image.cc 1.0.0 2018/03/29 - * - * Author: RichardG867, - * Miran Grca, - * bit, - * - * Copyright 2015-2018 Richardg867. - * Copyright 2015-2018 Miran Grca. - * Copyright 2017,2018 bit. - */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#include -#include -#include -#include -#include -#include -#include "../config.h" -#include "../plat.h" -#include "../scsi/scsi.h" -#include "cdrom_dosbox.h" -#include "cdrom.h" -#include "cdrom_image.h" -#include "cdrom_null.h" - -#define CD_STATUS_EMPTY 0 -#define CD_STATUS_DATA_ONLY 1 -#define CD_STATUS_PLAYING 2 -#define CD_STATUS_PAUSED 3 -#define CD_STATUS_STOPPED 4 - -/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: - there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start - of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) - -extern CDROM image_cdrom; - -typedef struct __attribute__((__packed__)) -{ - uint8_t user_data[2048], - ecc[288]; -} m1_data_t; - -typedef struct __attribute__((__packed__)) -{ - uint8_t sub_header[8], - user_data[2328]; -} m2_data_t; - -typedef union __attribute__((__packed__)) -{ - m1_data_t m1_data; - m2_data_t m2_data; - uint8_t raw_data[2336]; -} sector_data_t; - -typedef struct __attribute__((__packed__)) -{ - uint8_t sync[12]; - uint8_t header[4]; - sector_data_t data; -} sector_raw_data_t; - -typedef union __attribute__((__packed__)) -{ - sector_raw_data_t sector_data; - uint8_t raw_data[2352]; -} sector_t; - -typedef struct __attribute__((__packed__)) -{ - sector_t sector; - uint8_t c2[296]; - uint8_t subchannel_raw[96]; - uint8_t subchannel_q[16]; - uint8_t subchannel_rw[96]; -} cdrom_sector_t; - -typedef union __attribute__((__packed__)) -{ - cdrom_sector_t cdrom_sector; - uint8_t buffer[2856]; -} sector_buffer_t; - -sector_buffer_t cdrom_sector_buffer; - -int cdrom_sector_size; -uint8_t raw_buffer[2448]; -uint8_t extra_buffer[296]; - -enum -{ - CD_STOPPED = 0, - CD_PLAYING, - CD_PAUSED -}; - - -#ifdef ENABLE_CDROM_IMAGE_LOG -int cdrom_image_do_log = ENABLE_CDROM_IMAGE_LOG; -#endif - - -static CDROM_Interface_Image* cdimg[CDROM_NUM] = { NULL, NULL, NULL, NULL }; -static char afn[1024]; - -void image_close(uint8_t id); - - -void -cdrom_image_log(const char *format, ...) -{ -#ifdef ENABLE_CDROM_IMAGE_LOG - if (cdrom_image_do_log) { - va_list ap; - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - fflush(stdout); - } -#endif -} - - -int -image_audio_callback(uint8_t id, int16_t *output, int len) -{ - cdrom_t *dev = cdrom[id]; - int ret = 1; - - if (!cdrom_drives[id].sound_on || (dev->cd_state != CD_PLAYING) || cdrom_image[id].image_is_iso) { - cdrom_image_log("image_audio_callback(i): Not playing\n", id); - if (dev->cd_state == CD_PLAYING) - dev->seek_pos += (len >> 11); - memset(output, 0, len * 2); - return 0; - } - while (dev->cd_buflen < len) { - if (dev->seek_pos < dev->cd_end) { - if (!cdimg[id]->ReadSector((unsigned char*)&dev->cd_buffer[dev->cd_buflen], true, - dev->seek_pos)) { - memset(&dev->cd_buffer[dev->cd_buflen], 0, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_state = CD_STOPPED; - dev->cd_buflen = len; - ret = 0; - } else { - dev->seek_pos++; - dev->cd_buflen += (RAW_SECTOR_SIZE / 2); - ret = 1; - } - } else { - memset(&dev->cd_buffer[dev->cd_buflen], 0, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_state = CD_STOPPED; - dev->cd_buflen = len; - ret = 0; - } - } - - memcpy(output, dev->cd_buffer, len * 2); - memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); - dev->cd_buflen -= len; - return ret; -} - - -void -image_audio_stop(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->cd_state = CD_STOPPED; -} - - -static uint8_t -image_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) -{ - cdrom_t *dev = cdrom[id]; - if (!cdimg[id]) - return 0; - int number; - unsigned char attr; - TMSF tmsf; - int m = 0, s = 0, f = 0; - cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); - if (attr == DATA_TRACK) { - cdrom_image_log("Can't play data track\n"); - dev->seek_pos = 0; - dev->cd_state = CD_STOPPED; - return 0; - } - cdrom_image_log("Play audio - %08X %08X %i\n", pos, len, ismsf); - if (ismsf == 2) { - cdimg[id]->GetAudioTrackInfo(pos, number, tmsf, attr); - pos = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; - cdimg[id]->GetAudioTrackInfo(len, number, tmsf, attr); - len = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; - } else if (ismsf == 1) { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - - if (pos == 0xffffff) { - cdrom_image_log("Playing from current position (MSF)\n"); - pos = dev->seek_pos; - } else - pos = MSFtoLBA(m, s, f) - 150; - - m = (len >> 16) & 0xff; - s = (len >> 8) & 0xff; - f = len & 0xff; - len = MSFtoLBA(m, s, f) - 150; - - cdrom_image_log("MSF - pos = %08X len = %08X\n", pos, len); - } else if (ismsf == 0) { - if (pos == 0xffffffff) { - cdrom_image_log("Playing from current position\n"); - pos = dev->seek_pos; - } - len += pos; - } - - dev->seek_pos = pos; - dev->cd_end = len; - dev->cd_state = CD_PLAYING; - dev->cd_buflen = 0; - - return 1; -} - - -static void -image_pause(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdimg[id] || cdrom_image[id].image_is_iso) return; - if (dev->cd_state == CD_PLAYING) - dev->cd_state = CD_PAUSED; -} - - -static void -image_resume(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdimg[id] || cdrom_image[id].image_is_iso) - return; - if (dev->cd_state == CD_PAUSED) - dev->cd_state = CD_PLAYING; -} - - -static void -image_stop(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdimg[id] || cdrom_image[id].image_is_iso) - return; - dev->cd_state = CD_STOPPED; -} - - -static int -image_ready(uint8_t id) -{ - if (!cdimg[id] || (wcslen(cdrom_image[id].image_path) == 0)) - return 0; - - return 1; -} - - -static int -image_get_last_block(uint8_t id) -{ - int first_track, last_track; - int number, c; - unsigned char attr; - TMSF tmsf; - uint32_t lb=0; - - if (!cdimg[id]) - return 0; - - cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); - - for (c = 0; c <= last_track; c++) { - uint32_t address; - cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); - address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */ - if (address > lb) - lb = address; - } - return lb; -} - - -static int -image_medium_changed(uint8_t id) -{ - /* There is no way to change the medium within an already mounted image. */ - return 0; -} - - -static uint8_t -image_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) -{ - cdrom_t *dev = cdrom[id]; - uint8_t ret; - int pos = 0; - uint32_t cdpos; - TMSF relPos, absPos; - unsigned char attr, track, index; - - cdpos = dev->seek_pos; - - if (!cdimg[id]) - return 0; - - cdimg[id]->GetAudioSub(cdpos, attr, track, index, relPos, absPos); - - if (cdrom_image[id].image_is_iso) - ret = 0x15; - else { - if (dev->cd_state == CD_PLAYING) - ret = 0x11; - else if (dev->cd_state == CD_PAUSED) - ret = 0x12; - else - ret = 0x13; - } - - b[pos++] = attr; - b[pos++] = track; - b[pos++] = index; - - if (msf) { - b[pos + 3] = (uint8_t) absPos.fr; - b[pos + 2] = (uint8_t) absPos.sec; - b[pos + 1] = (uint8_t) absPos.min; - b[pos] = 0; - pos += 4; - b[pos + 3] = (uint8_t) relPos.fr; - b[pos + 2] = (uint8_t) relPos.sec; - b[pos + 1] = (uint8_t) relPos.min; - b[pos] = 0; - pos += 4; - } else { - uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr) - 150; - 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 int -image_is_track_audio(uint8_t id, uint32_t pos, int ismsf) -{ - int m, s, f; - unsigned char attr; - TMSF tmsf; - int number; - - if (!cdimg[id] || cdrom_image[id].image_is_iso) - return 0; - - if (ismsf) { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - pos = MSFtoLBA(m, s, f) - 150; - } - - /* GetTrack requires LBA. */ - cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); - - return attr == AUDIO_TRACK; -} - - -static int -is_legal(int id, int cdrom_sector_type, int cdrom_sector_flags, int audio, int mode2) -{ - if (!(cdrom_sector_flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); - return 0; - } - - if ((cdrom_sector_type != 1) && !audio) { - if (!(cdrom_sector_flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any Data Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); - return 0; - } - - if ((cdrom_sector_flags & 0x06) == 0x06) { - cdrom_image_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id); - return 0; - } - - if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) { - cdrom_image_log("CD-ROM %i: [Any Data Mode] Invalid subchannel data flags (%02X)\n", id, cdrom_sector_flags & 0x700); - return 0; - } - - if ((cdrom_sector_flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */ - cdrom_image_log("CD-ROM %i: [Any Data Mode] EDC/ECC without user data is an illegal mode\n", id); - return 0; - } - - if (((cdrom_sector_flags & 0xf0) == 0x90) || ((cdrom_sector_flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n", id); - return 0; - } - - if (((cdrom_sector_type > 3) && (cdrom_sector_type != 8)) || (mode2 && (mode2 & 0x03))) { - if ((cdrom_sector_flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any XA Mode 2] 0x30/0x38 are illegal modes\n", id); - return 0; - } - if (((cdrom_sector_flags & 0xf0) == 0xb0) || ((cdrom_sector_flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any XA Mode 2] 0xBx and 0xDx are illegal modes\n", id); - return 0; - } - } - } - - return 1; -} - - -static void -read_sector_to_buffer(uint8_t id, uint8_t *raw_buffer, uint32_t msf, uint32_t lba, int mode2, int len) -{ - uint8_t *bb = raw_buffer; - - cdimg[id]->ReadSector(raw_buffer + 16, false, lba); - - /* Sync bytes */ - bb[0] = 0; - memset(bb + 1, 0xff, 10); - bb[11] = 0; - bb += 12; - - /* Sector header */ - bb[0] = (msf >> 16) & 0xff; - bb[1] = (msf >> 8) & 0xff; - bb[2] = msf & 0xff; - - bb[3] = 1; /* mode 1 data */ - bb += mode2 ? 12 : 4; - bb += len; - if (mode2 && ((mode2 & 0x03) == 1)) - memset(bb, 0, 280); - else if (!mode2) - memset(bb, 0, 288); -} - - -static void -read_audio(int id, uint32_t lba, uint8_t *b) -{ - if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - memcpy(b, raw_buffer, 2352); - cdrom_sector_size = 2352; -} - - -static void -read_mode1(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) -{ - if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2048)) - read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2048); - else if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_log("CD-ROM %i: [Mode 1] Sync\n", id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; - } - - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_image_log("CD-ROM %i: [Mode 1] Header\n", id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; - } - - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - if (!(cdrom_sector_flags & 0x10)) { /* No user data */ - cdrom_image_log("CD-ROM %i: [Mode 1] Sub-header\n", id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; - } - } - - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_image_log("CD-ROM %i: [Mode 1] User data\n", id); - memcpy(b, raw_buffer + 16, 2048); - cdrom_sector_size += 2048; - b += 2048; - } - - if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ - cdrom_image_log("CD-ROM %i: [Mode 1] EDC/ECC\n", id); - memcpy(b, raw_buffer + 2064, 288); - cdrom_sector_size += 288; - b += 288; - } -} - - -static void -read_mode2_non_xa(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) -{ - if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2336)) - read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2336); - else if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Sync\n", id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; - } - - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Header\n", id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; - } - - /* Mode 1 sector, expected type is 1 type. */ - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Sub-header\n", id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; - } - - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] User data\n", id); - memcpy(b, raw_buffer + 24, 2336); - cdrom_sector_size += 2336; - b += 2336; - } -} - - -static void -read_mode2_xa_form1(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) -{ - if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2048)) - read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2048); - else if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; - } - - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; - } - - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; - } - - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", id); - memcpy(b, raw_buffer + 24, 2048); - cdrom_sector_size += 2048; - b += 2048; - } - - if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", id); - memcpy(b, raw_buffer + 2072, 280); - cdrom_sector_size += 280; - b += 280; - } -} - - -static void -read_mode2_xa_form2(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) -{ - if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2324)) - read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2324); - else if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Sync\n", id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; - } - - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Header\n", id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; - } - - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Sub-header\n", id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; - } - - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] User data\n", id); - memcpy(b, raw_buffer + 24, 2328); - cdrom_sector_size += 2328; - b += 2328; - } -} - - -static int -image_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, - int cdrom_sector_flags, int *len) -{ - uint8_t *b, *temp_b; - uint32_t msf, lba; - int audio, mode2; - int m, s, f; - - if (!cdimg[id]) - return 0; - - if (!cdrom_drives[id].host_drive) - return 0; - - b = temp_b = buffer; - - *len = 0; - - if (ismsf) { - m = (sector >> 16) & 0xff; - s = (sector >> 8) & 0xff; - f = sector & 0xff; - lba = MSFtoLBA(m, s, f) - 150; - msf = sector; - } else { - lba = sector; - msf = cdrom_lba_to_msf_accurate(sector); - } - - if (cdrom_image[id].image_is_iso) { - audio = 0; - mode2 = cdimg[id]->IsMode2(lba) ? 1 : 0; - } else { - audio = image_is_track_audio(id, sector, ismsf); - mode2 = cdimg[id]->IsMode2(lba) ? 1 : 0; - } - mode2 <<= 2; - mode2 |= cdimg[id]->GetMode2Form(lba); - - memset(raw_buffer, 0, 2448); - memset(extra_buffer, 0, 296); - - if (!(cdrom_sector_flags & 0xf0)) { /* 0x00 and 0x08 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", id); - return 0; - } - - if (!is_legal(id, cdrom_sector_type, cdrom_sector_flags, audio, mode2)) - return 0; - - if ((cdrom_sector_type == 3) || ((cdrom_sector_type > 4) && (cdrom_sector_type != 8))) { - if (cdrom_sector_type == 3) - cdrom_image_log("CD-ROM %i: Attempting to read a Yellowbook Mode 2 data sector from an image\n", id); - if (cdrom_sector_type > 4) - cdrom_image_log("CD-ROM %i: Attempting to read a XA Mode 2 Form 2 data sector from an image\n", id); - return 0; - } else if (cdrom_sector_type == 1) { - if (!audio || cdrom_image[id].image_is_iso) { - cdrom_image_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", id); - return 0; - } - - read_audio(id, lba, temp_b); - } else if (cdrom_sector_type == 2) { - if (audio || mode2) { - cdrom_image_log("CD-ROM %i: [Mode 1] Attempting to read a sector of another type\n", id); - return 0; - } - - read_mode1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - } else if (cdrom_sector_type == 3) { - if (audio || !mode2 || (mode2 & 0x03)) { - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Attempting to read a sector of another type\n", id); - return 0; - } - - read_mode2_non_xa(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - } else if (cdrom_sector_type == 4) { - if (audio || !mode2 || ((mode2 & 0x03) != 1)) { - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a sector of another type\n", id); - return 0; - } - - read_mode2_xa_form1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - } else if (cdrom_sector_type == 5) { - if (audio || !mode2 || ((mode2 & 0x03) != 2)) { - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Attempting to read a sector of another type\n", id); - return 0; - } - - read_mode2_xa_form2(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - } else if (cdrom_sector_type == 8) { - if (audio) { - cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", id); - return 0; - } - - if (mode2 && ((mode2 & 0x03) == 1)) - read_mode2_xa_form1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - else if (!mode2) - read_mode1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - else { - cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size is not 2048 bytes\n", id); - return 0; - } - } else { - if (mode2) { - if ((mode2 & 0x03) == 0x01) - read_mode2_xa_form1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - else if ((mode2 & 0x03) == 0x02) - read_mode2_xa_form2(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - else - read_mode2_non_xa(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - } else { - if (audio) - read_audio(id, lba, temp_b); - else - read_mode1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); - } - } - - if ((cdrom_sector_flags & 0x06) == 0x02) { - /* Add error flags. */ - cdrom_image_log("CD-ROM %i: Error flags\n", id); - memcpy(b + cdrom_sector_size, extra_buffer, 294); - cdrom_sector_size += 294; - } else if ((cdrom_sector_flags & 0x06) == 0x04) { - /* Add error flags. */ - cdrom_image_log("CD-ROM %i: Full error flags\n", id); - memcpy(b + cdrom_sector_size, extra_buffer, 296); - cdrom_sector_size += 296; - } - - if ((cdrom_sector_flags & 0x700) == 0x100) { - cdrom_image_log("CD-ROM %i: Raw subchannel data\n", id); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); - cdrom_sector_size += 96; - } else if ((cdrom_sector_flags & 0x700) == 0x200) { - cdrom_image_log("CD-ROM %i: Q subchannel data\n", id); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16); - cdrom_sector_size += 16; - } else if ((cdrom_sector_flags & 0x700) == 0x400) { - cdrom_image_log("CD-ROM %i: R/W subchannel data\n", id); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); - cdrom_sector_size += 96; - } - - *len = cdrom_sector_size; - - return 1; -} - - -static uint32_t -image_size(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - return dev->cdrom_capacity; -} - - -static int -image_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) -{ - int number, len = 4; - int c, d, first_track, last_track; - uint32_t temp; - unsigned char attr; - TMSF tmsf; - - if (!cdimg[id]) - return 0; - - cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); - - b[2] = first_track; - b[3] = last_track; - - d = 0; - for (c = 0; c <= last_track; c++) { - cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); - if (number >= starttrack) { - d=c; - break; - } - } - - if (starttrack != 0xAA) { - cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); - b[2] = number; - } - - for (c = d; c <= last_track; c++) { - cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); - - 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); - - return len; -} - - -static int -image_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) -{ - int number, len = 4; - TMSF tmsf; - unsigned char attr; - uint32_t temp; - - if (!cdimg[id]) - return 0; - - cdimg[id]->GetAudioTrackInfo(1, number, tmsf, attr); - - if (number == 0) - number = 1; - - b[2] = 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 { - temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150. */ - b[len++] = temp >> 24; - b[len++] = temp >> 16; - b[len++] = temp >> 8; - b[len++] = temp; - } - - if (maxlen < len) - return maxlen; - - return len; -} - - -static int -image_readtoc_raw(uint8_t id, unsigned char *b, int maxlen) -{ - int track, len = 4; - int first_track, last_track; - int number; - unsigned char attr; - TMSF tmsf; - - if (!cdimg[id]) - return 0; - - cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); - - b[2] = first_track; - b[3] = last_track; - - for (track = first_track; track <= last_track; track++) { - cdimg[id]->GetAudioTrackInfo(track, number, tmsf, attr); - - 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 int -image_status(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdimg[id]) - return CD_STATUS_EMPTY; - - if (cdrom_image[id].image_is_iso) - return CD_STATUS_DATA_ONLY; - - if (cdimg[id]->HasAudioTracks()) { - switch(dev->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(UNUSED(uint8_t id)) -{ - return; -} - - -void -image_close(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->cd_state = CD_STOPPED; - if (cdimg[id]) { - delete cdimg[id]; - cdimg[id] = NULL; - } -} - - -int -image_open(uint8_t id, wchar_t *fn) -{ - cdrom_t *dev = cdrom[id]; - - wcscpy(cdrom_image[id].image_path, fn); - - if (! wcscasecmp(plat_get_extension(fn), L"ISO")) - cdrom_image[id].image_is_iso = 1; - else - cdrom_image[id].image_is_iso = 0; - - cdimg[id] = new CDROM_Interface_Image(); - memset(afn, 0, sizeof(afn)); - wcstombs(afn, fn, sizeof(afn)); - if (!cdimg[id]->SetDevice(afn, false)) { - image_close(id); - cdrom_set_null_handler(id); - cdrom_image_log("[f] image_open(): cdrom[%i]->handler = %08X\n", id, cdrom[id]->handler); - return 1; - } - dev->cd_state = CD_STOPPED; - dev->seek_pos = 0; - dev->cd_buflen = 0; - dev->cdrom_capacity = image_get_last_block(id) + 1; - cdrom[id]->handler = &image_cdrom; - - return 0; -} - - -static void -image_exit(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->handler_inited = 0; -} - - -/* TODO: Check for what data type a mixed CD is. */ -static int image_media_type_id(uint8_t id) -{ - if (image_size(id) > 405000) - return 65; /* DVD. */ - else { - if (cdrom_image[id].image_is_iso) - return 1; /* Data CD. */ - else - return 3; /* Mixed mode CD. */ - } -} - - -CDROM image_cdrom = -{ - image_ready, - image_medium_changed, - image_media_type_id, - image_audio_callback, - image_audio_stop, - image_readtoc, - image_readtoc_session, - image_readtoc_raw, - image_getcurrentsubchannel, - image_readsector_raw, - image_playaudio, - image_pause, - image_resume, - image_size, - image_status, - image_stop, - image_exit -}; diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c new file mode 100644 index 000000000..983a75efa --- /dev/null +++ b/src/cdrom/cdrom_image_backend.c @@ -0,0 +1,980 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CD-ROM image file handling module, translated to C from + * cdrom_dosbox.cpp. + * + * Version: @(#)cdrom_image_backend.c 1.0.2 2020/01/11 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * The DOSBox Team, + * + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2002-2020 The DOSBox Team. + */ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../plat.h" +#include "cdrom_image_backend.h" + + +#define CDROM_BCD(x) (((x) % 10) | (((x) / 10) << 4)) + +#define MAX_LINE_LENGTH 512 +#define MAX_FILENAME_LENGTH 256 +#define CROSS_LEN 512 + + +#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG +int cdrom_image_backend_do_log = ENABLE_CDROM_IMAGE_BACKEND_LOG; + + +void +cdrom_image_backend_log(const char *fmt, ...) +{ + va_list ap; + + if (cdrom_image_backend_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cdrom_image_backend_log(fmt, ...) +#endif + + +/* Binary file functions. */ +static int +bin_read(void *p, uint8_t *buffer, uint64_t seek, size_t count) +{ + track_file_t *tf = (track_file_t *) p; + + cdrom_image_backend_log("CDROM: binary_read(%08lx, pos=%" PRIu64 " count=%lu\n", + tf->file, seek, count); + + if (tf->file == NULL) + return 0; + + fseeko64(tf->file, seek, SEEK_SET); + + if (fread(buffer, count, 1, tf->file) != 1) { +#ifdef ENABLE_cdrom_image_backend_log + cdrom_image_backend_log("CDROM: binary_read failed!\n"); +#endif + return 0; + } + + return 1; +} + + +static uint64_t +bin_get_length(void *p) +{ + off64_t len; + track_file_t *tf = (track_file_t *) p; + + cdrom_image_backend_log("CDROM: binary_length(%08lx)\n", bf->file); + + if (tf->file == NULL) + return 0; + + fseeko64(tf->file, 0, SEEK_END); + len = ftello64(tf->file); + cdrom_image_backend_log("CDROM: binary_length(%08lx) = %" PRIu64 "\n", tf->file, len); + + return len; +} + + +static void +bin_close(void *p) +{ + track_file_t *tf = (track_file_t *) p; + + if (tf == NULL) + return; + + if (tf->file != NULL) { + fclose(tf->file); + tf->file = NULL; + } + + memset(tf->fn, 0x00, sizeof(tf->fn)); + + free(p); +} + + +static track_file_t * +bin_init(const wchar_t *filename, int *error) +{ + track_file_t *tf = (track_file_t *) malloc(sizeof(track_file_t)); + + memset(tf->fn, 0x00, sizeof(tf->fn)); + wcscpy(tf->fn, filename); + tf->file = plat_fopen64(tf->fn, L"rb"); + cdrom_image_backend_log("CDROM: binary_open(%ls) = %08lx\n", tf->fn, tf->file); + + *error = (tf->file == NULL); + + /* Set the function pointers. */ + if (!*error) { + tf->read = bin_read; + tf->get_length = bin_get_length; + tf->close = bin_close; + } + + return tf; +} + + +static track_file_t * +track_file_init(const wchar_t *filename, int *error) +{ + /* Current we only support .BIN files, either combined or one per + track. In the future, more is planned. */ + return bin_init(filename, error); +} + + +static void +track_file_close(track_t *trk) +{ + if (trk == NULL) + return; + + if (trk->file == NULL) + return; + + trk->file->close(trk->file); + trk->file = NULL; +} + + +/* Root functions. */ +static void +cdi_clear_tracks(cd_img_t *cdi) +{ + int i; + track_file_t *last = NULL; + track_t *cur = NULL; + + if ((cdi->tracks == NULL) || (cdi->tracks_num == 0)) + return; + + for (i = 0; i < cdi->tracks_num; i++) { + cur = &cdi->tracks[i]; + + if (cur->file != last) { + track_file_close(cur); + last = cur->file; + } + } + + /* Now free the array. */ + free(cdi->tracks); + cdi->tracks = NULL; + + /* Mark that there's no tracks. */ + cdi->tracks_num = 0; +} + + +void +cdi_close(cd_img_t *cdi) +{ + cdi_clear_tracks(cdi); + free(cdi); +} + + +int +cdi_set_device(cd_img_t *cdi, const wchar_t *path) +{ + if (cdi_load_cue(cdi, path)) + return 1; + + if (cdi_load_iso(cdi, path)) + return 1; + + return 0; +} + + +/* TODO: This never returns anything other than 1, should it even be an int? */ +int +cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out) +{ + *st_track = 1; + *end = cdi->tracks_num - 1; + FRAMES_TO_MSF(cdi->tracks[*end].start + 150, &lead_out->min, &lead_out->sec, &lead_out->fr); + + return 1; +} + + +/* This replaces both Info and EndInfo, they are specified by a variable. */ +int +cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr) +{ + track_t *trk = &cdi->tracks[track - 1]; + int pos = trk->start + 150; + + if ((track < 1) || (track > cdi->tracks_num)) + return 0; + + pos = trk->start + 150; + + FRAMES_TO_MSF(pos, &start->min, &start->sec, &start->fr); + *track_num = trk->track_number; + *attr = trk->attr; + + return 1; +} + + +int +cdi_get_track(cd_img_t *cdi, uint32_t sector) +{ + int i; + track_t *cur, *next; + + /* There must be at least two tracks - data and lead out. */ + if (cdi->tracks_num < 2) + return -1; + + /* This has a problem - the code skips the last track, which is + lead out - is that correct? */ + for (i = 0; i < (cdi->tracks_num - 1); i++) { + cur = &cdi->tracks[i]; + next = &cdi->tracks[i + 1]; + if ((cur->start <= sector) && (sector < next->start)) + return cur->number; + } + + return -1; +} + + +/* TODO: See if track start is adjusted by 150 or not. */ +int +cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos) +{ + int cur_track = cdi_get_track(cdi, sector); + track_t *trk; + + if (cur_track < 1) + return 0; + + *track = (uint8_t) cur_track; + trk = &cdi->tracks[*track - 1]; + *attr = trk->attr; + *index = 1; + + FRAMES_TO_MSF(sector + 150, &abs_pos->min, &abs_pos->sec, &abs_pos->fr); + + /* Absolute position should be adjusted by 150, not the relative ones. */ + FRAMES_TO_MSF(sector - trk->start, &rel_pos->min, &rel_pos->sec, &rel_pos->fr); + + return 1; +} + + +int +cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) +{ + size_t length; + int track = cdi_get_track(cdi, sector) - 1; + uint64_t sect = (uint64_t) sector, seek; + track_t *trk; + int track_is_raw, ret; + int raw_size, cooked_size; + uint64_t offset = 0ULL; + int m = 0, s = 0, f = 0; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || (trk->sector_size == 2448)); + if (raw && !track_is_raw) + return 0; + seek = trk->skip + ((sect - trk->start) * trk->sector_size); + + if (track_is_raw) + raw_size = trk->sector_size; + else + raw_size = 2448; + + if (trk->mode2 && (trk->form != 1)) { + if (trk->form == 2) + cooked_size = (track_is_raw ? 2328 : trk->sector_size); /* Both 2324 + ECC and 2328 variants are valid. */ + else + cooked_size = 2336; + } else + cooked_size = COOKED_SECTOR_SIZE; + + length = (raw ? raw_size : cooked_size); + + if (trk->mode2 && (trk->form >= 1)) + offset = 24ULL; + else + offset = 16ULL; + + if (raw && !track_is_raw) { + memset(buffer, 0x00, 2448); + ret = trk->file->read(trk->file, buffer + offset, seek, length); + if (!ret) + return 0; + /* Construct the rest of the raw sector. */ + memset(buffer + 1, 0xff, 10); + buffer += 12; + FRAMES_TO_MSF(sector + 150, &m, &s, &f); + /* These have to be BCD. */ + buffer[12] = CDROM_BCD(m & 0xff); + buffer[13] = CDROM_BCD(s & 0xff); + buffer[14] = CDROM_BCD(f & 0xff); + buffer[15] = trk->mode2 ? 2 : 1; /* Data, should reflect the actual sector type. */ + return 1; + } else if (!raw && track_is_raw) + return trk->file->read(trk->file, buffer, seek + offset, length); + else + return trk->file->read(trk->file, buffer, seek, length); +} + + +int +cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num) +{ + int sector_size, success = 1; + uint8_t buf_len, *buf; + uint32_t i; + + /* TODO: This fails to account for Mode 2. Shouldn't we have a function + to get sector size? */ + sector_size = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; + buf_len = num * sector_size; + buf = (uint8_t *) malloc(buf_len * sizeof(uint8_t)); + + for (i = 0; i < num; i++) { + success = cdi_read_sector(cdi, &buf[i * sector_size], raw, sector + i); + if (!success) + break; + } + + memcpy((void *) buffer, buf, buf_len); + free(buf); + buf = NULL; + + return success; +} + + +/* TODO: Do CUE+BIN images with a sector size of 2448 even exist? */ +int +cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector) - 1; + track_t *trk; + uint64_t s = (uint64_t) sector, seek; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + seek = trk->skip + ((s - trk->start) * trk->sector_size); + if (trk->sector_size != 2448) + return 0; + + return trk->file->read(trk->file, buffer, seek, 2448); +} + + +int +cdi_get_sector_size(cd_img_t *cdi, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector) - 1; + track_t *trk; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + return trk->sector_size; +} + + +int +cdi_is_mode2(cd_img_t *cdi, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector) - 1; + track_t *trk; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + + return !!(trk->mode2); +} + + +int +cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector) - 1; + track_t *trk; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + + return trk->form; +} + + +static int +cdi_can_read_pvd(track_file_t *file, uint64_t sector_size, int mode2, int form) +{ + uint8_t pvd[COOKED_SECTOR_SIZE]; + uint64_t seek = 16ULL * sector_size; /* First VD is located at sector 16. */ + + if ((!mode2 || (form == 0)) && (sector_size == RAW_SECTOR_SIZE)) + seek += 16; + if (mode2 && (form >= 1)) + seek += 24; + + file->read(file, pvd, seek, COOKED_SECTOR_SIZE); + + 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)); +} + + +/* This reallocates the array and returns the pointer to the last track. */ +static void +cdi_track_push_back(cd_img_t *cdi, track_t *trk) +{ + /* This has to be done so situations in which realloc would misbehave + can be detected and reported to the user. */ + if ((cdi->tracks != NULL) && (cdi->tracks_num == 0)) + fatal("CD-ROM Image: Non-null tracks array at 0 loaded tracks\n"); + if ((cdi->tracks == NULL) && (cdi->tracks_num != 0)) + fatal("CD-ROM Image: Null tracks array at non-zero loaded tracks\n"); + + cdi->tracks = realloc(cdi->tracks, (cdi->tracks_num + 1) * sizeof(track_t)); + memcpy(&(cdi->tracks[cdi->tracks_num]), trk, sizeof(track_t)); + cdi->tracks_num++; +} + + +int +cdi_load_iso(cd_img_t *cdi, const wchar_t *filename) +{ + int error; + track_t trk; + + cdi->tracks = NULL; + cdi->tracks_num = 0; + + memset(&trk, 0, sizeof(track_t)); + + /* Data track (shouldn't there be a lead in track?). */ + trk.file = bin_init(filename, &error); + if (error) { + if (trk.file != NULL) + trk.file->close(trk.file); + return 0; + } + trk.number = 1; + trk.track_number = 1; + trk.attr = DATA_TRACK; + + /* Try to detect ISO type. */ + trk.form = 0; + trk.mode2 = 0; + /* TODO: Merge the first and last cases since they result in the same thing. */ + if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 0, 0)) + trk.sector_size = RAW_SECTOR_SIZE; + else if (cdi_can_read_pvd(trk.file, 2336, 1, 0)) { + trk.sector_size = 2336; + trk.mode2 = 1; + } else if (cdi_can_read_pvd(trk.file, 2324, 1, 2)) { + trk.sector_size = 2324; + trk.mode2 = 1; + trk.form = 2; + } else if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 1, 0)) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.mode2 = 1; + } else { + /* We use 2048 mode 1 as the default. */ + trk.sector_size = COOKED_SECTOR_SIZE; + } + + trk.length = trk.file->get_length(trk.file) / trk.sector_size; + cdi_track_push_back(cdi, &trk); + + /* Lead out track. */ + trk.number = 2; + trk.track_number = 0xAA; + trk.attr = 0x16; /* Was originally 0x00, but I believe 0x16 is appropriate. */ + trk.start = trk.length; + trk.length = 0; + trk.file = NULL; + cdi_track_push_back(cdi, &trk); + + return 1; +} + + +static int +cdi_cue_get_buffer(char *str, char **line, int up) +{ + char *s = *line; + char *p = str; + int quote = 0; + int done = 0; + int space = 1; + + /* Copy to local buffer until we have end of string or whitespace. */ + while (! done) { + switch(*s) { + case '\0': + if (quote) { + /* Ouch, unterminated string.. */ + return 0; + } + done = 1; + break; + + case '\"': + quote ^= 1; + break; + + case ' ': + case '\t': + if (space) + break; + + if (! quote) { + done = 1; + break; + } + /*FALLTHROUGH*/ + + default: + if (up && islower((int) *s)) + *p++ = toupper((int) *s); + else + *p++ = *s; + space = 0; + break; + } + + if (! done) + s++; + } + *p = '\0'; + + *line = s; + + return 1; +} + + +static int +cdi_cue_get_keyword(char **dest, char **line) +{ + char temp[1024]; + int success; + + success = cdi_cue_get_buffer(temp, line, 1); + if (success) + *dest = temp; + + return success; +} + + +/* Get a string from the input line, handling quotes properly. */ +static uint64_t +cdi_cue_get_number(char **line) +{ + char temp[128]; + uint64_t num; + + if (!cdi_cue_get_buffer(temp, line, 0)) + return 0; + + if (sscanf(temp, "%" PRIu64, &num) != 1) + return 0; + + return num; +} + + +static int +cdi_cue_get_frame(uint64_t *frames, char **line) +{ + char temp[128]; + int min, sec, fr; + int success; + + success = cdi_cue_get_buffer(temp, line, 0); + if (! success) return 0; + + success = sscanf(temp, "%d:%d:%d", &min, &sec, &fr) == 3; + if (! success) return 0; + + *frames = MSF_TO_FRAMES(min, sec, fr); + + return 1; +} + + +static int +cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, uint64_t *total_pregap, uint64_t cur_pregap) +{ + /* Frames between index 0 (prestart) and 1 (current track start) must be skipped. */ + uint64_t skip, temp; + track_t *prev = NULL; + + if (prestart > 0) { + if (prestart > cur->start) + return 0; + skip = cur->start - prestart; + } else + skip = 0ULL; + + if ((cdi->tracks != NULL) && (cdi->tracks_num != 0)) + prev = &cdi->tracks[cdi->tracks_num - 1]; + + /* First track (track number must be 1). */ + if (cdi->tracks_num == 0) { + /* I guess this makes sure the structure is not filled with invalid data. */ + if (cur->number != 1) + return 0; + cur->skip = skip * cur->sector_size; + cur->start += cur_pregap; + *total_pregap = cur_pregap; + cdi_track_push_back(cdi, cur); + return 1; + } + + /* Current track consumes data from the same file as the previous. */ + if (prev->file == cur->file) { + cur->start += *shift; + prev->length = cur->start + *total_pregap - prev->start - skip; + cur->skip += prev->skip + (prev->length * prev->sector_size) + (skip * cur->sector_size); + *total_pregap += cur_pregap; + cur->start += *total_pregap; + } else { + temp = prev->file->get_length(prev->file) - ((uint64_t) prev->skip); + prev->length = temp / ((uint64_t) prev->sector_size); + if ((temp % prev->sector_size) != 0) + prev->length++; /* Padding. */ + + cur->start += prev->start + prev->length + cur_pregap; + cur->skip = skip * cur->sector_size; + *shift += prev->start + prev->length; + *total_pregap = cur_pregap; + } + + /* Error checks. */ + if (cur->number <= 1) + return 0; + if ((prev->number + 1) != cur->number) + return 0; + if (cur->start < (prev->start + prev->length)) + return 0; + + cdi_track_push_back(cdi, cur); + + return 1; +} + + +int +cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile) +{ + track_t trk; + wchar_t pathname[MAX_FILENAME_LENGTH], filename[MAX_FILENAME_LENGTH]; + wchar_t temp[MAX_FILENAME_LENGTH]; + uint64_t shift = 0ULL, prestart = 0ULL; + uint64_t cur_pregap = 0ULL, total_pregap = 0ULL; + uint64_t frame = 0ULL, index; + int i, success; + int error, can_add_track = 0; + FILE *fp; + char buf[MAX_LINE_LENGTH], ansi[MAX_FILENAME_LENGTH]; + char *line, *command; + char *type; + + cdi->tracks = NULL; + cdi->tracks_num = 0; + + memset(&trk, 0, sizeof(track_t)); + + /* Get a copy of the filename into pathname, we need it later. */ + memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); + plat_get_dirname(pathname, cuefile); + + /* Open the file. */ + fp = plat_fopen((wchar_t *) cuefile, L"r"); + if (fp == NULL) + return 0; + + success = 0; + + for (;;) { + line = buf; + + /* Read a line from the cuesheet file. */ + if (feof(fp) || fgets(buf, sizeof(buf), fp) == NULL || ferror(fp)) + break; + + /* Do two iterations to make sure to nuke even if it's \r\n or \n\r, + but do checks to make sure we're not nuking other bytes. */ + for (i = 0; i < 2; i++) { + if (strlen(buf) > 0) { + if (buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */ + else if (buf[strlen(buf) - 1] == '\r') + buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */ + } + } + + success = cdi_cue_get_keyword(&command, &line); + + if (!strcmp(command, "TRACK")) { + if (can_add_track) + success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap); + else + success = 1; + + trk.start = 0; + trk.skip = 0; + cur_pregap = 0; + prestart = 0; + + trk.number = cdi_cue_get_number(&line); + trk.track_number = trk.number; + success = cdi_cue_get_keyword(&type, &line); + if (!success) + break; + + trk.form = 0; + trk.mode2 = 0; + + if (!strcmp(type, "AUDIO")) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = AUDIO_TRACK; + } else if (!strcmp(type, "MODE1/2048")) { + trk.sector_size = COOKED_SECTOR_SIZE; + trk.attr = DATA_TRACK; + } else if (!strcmp(type, "MODE1/2352")) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = DATA_TRACK; + } else if (!strcmp(type, "MODE1/2448")) { + trk.sector_size = 2448; + trk.attr = DATA_TRACK; + } else if (!strcmp(type, "MODE2/2048")) { + trk.form = 1; + trk.sector_size = COOKED_SECTOR_SIZE; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2324")) { + trk.form = 2; + trk.sector_size = 2324; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2328")) { + trk.form = 2; + trk.sector_size = 2328; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2336")) { + trk.sector_size = 2336; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2352")) { + trk.form = 1; /* Assume this is XA Mode 2 Form 1. */ + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2448")) { + trk.form = 1; /* Assume this is XA Mode 2 Form 1. */ + trk.sector_size = 2448; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "CDG/2448")) { + trk.sector_size = 2448; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "CDI/2336")) { + trk.sector_size = 2336; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "CDI/2352")) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else + success = 0; + + can_add_track = 1; + } else if (!strcmp(command, "INDEX")) { + index = cdi_cue_get_number(&line); + success = cdi_cue_get_frame(&frame, &line); + + switch(index) { + case 0: + prestart = frame; + break; + + case 1: + trk.start = frame; + break; + + default: + /* ignore other indices */ + break; + } + } else if (!strcmp(command, "FILE")) { + if (can_add_track) + success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap); + else + success = 1; + can_add_track = 0; + + memset(ansi, 0, MAX_FILENAME_LENGTH * sizeof(char)); + memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); + + success = cdi_cue_get_buffer(ansi, &line, 0); + if (!success) + break; + success = cdi_cue_get_keyword(&type, &line); + if (!success) + break; + + trk.file = NULL; + error = 1; + + if (!strcmp(type, "BINARY")) { + memset(temp, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); + mbstowcs(temp, ansi, sizeof_w(temp)); + plat_append_filename(filename, pathname, temp); + trk.file = track_file_init(filename, &error); + } + if (error) { +#ifdef ENABLE_cdrom_image_backend_log + cdrom_image_backend_log("CUE: cannot open fille '%ls' in cue sheet!\n", + filename); +#endif + if (trk.file != NULL) { + trk.file->close(trk.file); + trk.file = NULL; + } + success = 0; + } + } else if (!strcmp(command, "PREGAP")) + success = cdi_cue_get_frame(&cur_pregap, &line); + else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || !strcmp(command, "FLAGS") || !strcmp(command, "ISRC") || + !strcmp(command, "PERFORMER") || !strcmp(command, "POSTGAP") || !strcmp(command, "REM") || + !strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || !strcmp(command, "")) { + /* Ignored commands. */ + success = 1; + } else { +#ifdef ENABLE_cdrom_image_backend_log + cdrom_image_backend_log("CUE: unsupported command '%s' in cue sheet!\n", + command.c_str()); +#endif + success = 0; + } + + if (!success) + break; + } + + fclose(fp); + if (!success) + return 0; + + /* Add last track. */ + if (!cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap)) + return 0; + + /* Add lead out track. */ + trk.number++; + trk.track_number = 0xAA; + trk.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + trk.start = 0; + trk.length = 0; + trk.file = NULL; + if (!cdi_add_track(cdi, &trk, &shift, 0, &total_pregap, 0)) + return 0; + + return 1; +} + + +int +cdi_has_data_track(cd_img_t *cdi) +{ + int i; + + if ((cdi == NULL) || (cdi->tracks == NULL)) + return 0; + + /* Data track has attribute 0x14. */ + for (i = 0; i < cdi->tracks_num; i++) { + if (cdi->tracks[i].attr == DATA_TRACK) + return 1; + } + + return 0; +} + + +int +cdi_has_audio_track(cd_img_t *cdi) +{ + int i; + + if ((cdi == NULL) || (cdi->tracks == NULL)) + return 0; + + /* Audio track has attribute 0x14. */ + for (i = 0; i < cdi->tracks_num; i++) { + if (cdi->tracks[i].attr == AUDIO_TRACK) + return 1; + } + + return 0; +} diff --git a/src/cdrom/cdrom_image_backend.h b/src/cdrom/cdrom_image_backend.h new file mode 100644 index 000000000..b58b54d7b --- /dev/null +++ b/src/cdrom/cdrom_image_backend.h @@ -0,0 +1,93 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CD-ROM image file handling module header , translated to C + * from cdrom_dosbox.h. + * + * Version: @(#)cdrom_image_backend.h 1.0.1 2019/12/21 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * The DOSBox Team, + * + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2002-2019 The DOSBox Team. + */ +#ifndef CDROM_IMAGE_BACKEND_H +#define CDROM_IMAGE_BACKEND_H + +#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) { \ + uint64_t value = f; \ + *(F) = (value%CD_FPS) & 0xff; \ + value /= CD_FPS; \ + *(S) = (value%60) & 0xff; \ + value /= 60; \ + *(M) = value & 0xff; \ +} +#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F)) + + +typedef struct SMSF { + uint8_t min; + uint8_t sec; + uint8_t fr; +} TMSF; + +/* Track file struct. */ +typedef struct { + int (*read)(void *p, uint8_t *buffer, uint64_t seek, size_t count); + uint64_t (*get_length)(void *p); + void (*close)(void *p); + + wchar_t fn[260]; + FILE *file; +} track_file_t; + +typedef struct { + int number, track_number, attr, sector_size, + mode2, form; + uint64_t start, length, + skip; + track_file_t *file; +} track_t; + +typedef struct { + int tracks_num; + track_t *tracks; +} cd_img_t; + + +/* Binary file functions. */ +extern void cdi_close(cd_img_t *cdi); +extern int cdi_set_device(cd_img_t *cdi, const wchar_t *path); +extern int cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out); +extern int cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr); +extern int cdi_get_track(cd_img_t *cdi, uint32_t sector); +extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); +extern int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector); +extern int cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num); +extern int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector); +extern int cdi_get_sector_size(cd_img_t *cdi, uint32_t sector); +extern int cdi_is_mode2(cd_img_t *cdi, uint32_t sector); +extern int cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector); +extern int cdi_load_iso(cd_img_t *cdi, const wchar_t *filename); +extern int cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile); +extern int cdi_has_data_track(cd_img_t *cdi); +extern int cdi_has_audio_track(cd_img_t *cdi); + + + +#endif /* ! CDROM_IMAGE_BACKEND_H */ diff --git a/src/cdrom/cdrom_null.c b/src/cdrom/cdrom_null.c deleted file mode 100644 index 15b2c937f..000000000 --- a/src/cdrom/cdrom_null.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of the CD-ROM null interface for unmounted - * guest CD-ROM drives. - * - * Version: @(#)cdrom_null.c 1.0.7 2018/03/26 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2016 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include "../86box.h" -#include "../scsi/scsi.h" -#include "cdrom.h" - - -static CDROM null_cdrom; - - -static int -null_ready(uint8_t id) -{ - return(0); -} - - -/* Always return 0, the contents of a null CD-ROM drive never change. */ -static int -null_medium_changed(uint8_t id) -{ - return(0); -} - - -static uint8_t -null_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) -{ - return(0x13); -} - - -static int -null_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len) -{ - *len = 0; - - return(0); -} - - -static int -null_readtoc(uint8_t id, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single) -{ - return(0); -} - - -static int -null_readtoc_session(uint8_t id, uint8_t *b, int msf, int maxlen) -{ - return(0); -} - - -static int -null_readtoc_raw(uint8_t id, uint8_t *b, int maxlen) -{ - return(0); -} - - -static uint32_t -null_size(uint8_t id) -{ - return(0); -} - - -static int -null_status(uint8_t id) -{ - return(CD_STATUS_EMPTY); -} - - -void -cdrom_null_reset(uint8_t id) -{ -} - - -void cdrom_set_null_handler(uint8_t id); - -int -cdrom_null_open(uint8_t id) -{ - cdrom_set_null_handler(id); - - return(0); -} - - -void -null_close(uint8_t id) -{ -} - - -static -void null_exit(uint8_t id) -{ -} - - -static int -null_media_type_id(uint8_t id) -{ - return(0x70); -} - - -void -cdrom_set_null_handler(uint8_t id) -{ - cdrom[id]->handler = &null_cdrom; - cdrom_drives[id].host_drive = 0; - memset(cdrom_image[id].image_path, 0, sizeof(cdrom_image[id].image_path)); -} - - -static CDROM null_cdrom = { - null_ready, - null_medium_changed, - null_media_type_id, - NULL, - NULL, - null_readtoc, - null_readtoc_session, - null_readtoc_raw, - null_getcurrentsubchannel, - null_readsector_raw, - NULL, - NULL, - NULL, - null_size, - null_status, - NULL, - null_exit -}; diff --git a/src/cdrom/cdrom_null.h b/src/cdrom/cdrom_null.h deleted file mode 100644 index 480acb29c..000000000 --- a/src/cdrom/cdrom_null.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of the CD-ROM null interface for unmounted - * guest CD-ROM drives. - * - * Version: @(#)cdrom_null.h 1.0.4 2018/03/31 - * - * Authors: Sarah Walker, - * Miran Grca, - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - */ -#ifndef EMU_CDROM_NULL_H -#define EMU_CDROM_NULL_H - - -extern int cdrom_null_open(uint8_t id); -extern void cdrom_null_reset(uint8_t id); -extern void null_close(uint8_t id); - - -#endif /*EMU_CDROM_NULL_H*/ diff --git a/src/chipset/acc2168.c b/src/chipset/acc2168.c new file mode 100644 index 000000000..1df0fec34 --- /dev/null +++ b/src/chipset/acc2168.c @@ -0,0 +1,171 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ACC 2168 chipset + * used by the Packard Bell Legend 760 Supreme (PB410A or PB430). + * + * Version: @(#)acc2168.c 1.0.1 2019/10/19 + * + * Authors: Sarah Walker, + * + * Copyright 2019 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../device.h" +#include "../keyboard.h" +#include "../io.h" +#include "../mem.h" +#include "../mouse.h" +#include "../port_92.h" +#include "../sio.h" +#include "../disk/hdc.h" +#include "../video/video.h" +#include "../video/vid_ht216.h" +#include "chipset.h" + + +typedef struct acc2168_t +{ + int reg_idx; + uint8_t regs[256]; + uint8_t port_78; +} acc2168_t; + + +static void +acc2168_shadow_recalc(acc2168_t *dev) +{ + if (dev->regs[0x02] & 8) { + switch (dev->regs[0x02] & 0x30) { + case 0x00: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | 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_EXTANY | MEM_WRITE_EXTANY); + break; + case 0x30: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + } + } else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + + if (dev->regs[0x02] & 4) { + switch (dev->regs[0x02] & 0x30) { + case 0x00: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTANY | 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_EXTANY | MEM_WRITE_EXTANY); + break; + case 0x30: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + } + } else + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); +} + + +static void +acc2168_write(uint16_t addr, uint8_t val, void *p) +{ + acc2168_t *dev = (acc2168_t *)p; + + if (!(addr & 1)) + dev->reg_idx = val; + else { + dev->regs[dev->reg_idx] = val; + + switch (dev->reg_idx) { + case 0x02: + acc2168_shadow_recalc(dev); + break; + } + } +} + + +static uint8_t +acc2168_read(uint16_t addr, void *p) +{ + acc2168_t *dev = (acc2168_t *)p; + + if (!(addr & 1)) + return dev->reg_idx; + + return dev->regs[dev->reg_idx]; +} + + +/* + Bit 7 = Super I/O chip: 1 = enabled, 0 = disabled; + Bit 6 = Graphics card: 1 = standalone, 0 = on-board; + Bit 5 = ???? (if 1, siren and hangs). +*/ +static uint8_t +acc2168_port_78_read(uint16_t addr, void *p) +{ + acc2168_t *dev = (acc2168_t *)p; + + return dev->port_78; +} + + +static void +acc2168_close(void *priv) +{ + acc2168_t *dev = (acc2168_t *) priv; + + free(dev); +} + + +static void * +acc2168_init(const device_t *info) +{ + acc2168_t *dev = (acc2168_t *)malloc(sizeof(acc2168_t)); + memset(dev, 0, sizeof(acc2168_t)); + + io_sethandler(0x00f2, 0x0002, + acc2168_read, NULL, NULL, acc2168_write, NULL, NULL, dev); + io_sethandler(0x0078, 0x0001, + acc2168_port_78_read, NULL, NULL, NULL, NULL, NULL, dev); + + device_add(&port_92_inv_device); + + if (gfxcard != VID_INTERNAL) + dev->port_78 = 0x40; + else + dev->port_78 = 0; + + return dev; +} + + +const device_t acc2168_device = { + "ACC 2168", + 0, + 0, + acc2168_init, acc2168_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/acer_m3a.c b/src/chipset/acer_m3a.c new file mode 100644 index 000000000..0d8ab2052 --- /dev/null +++ b/src/chipset/acer_m3a.c @@ -0,0 +1,97 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Acer M3A and V35N ports EAh and EBh. + * + * Version: @(#)acer_m3a.c 1.0.0 2019/05/13 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../keyboard.h" +#include "chipset.h" + + +typedef struct +{ + int index; +} acerm3a_t; + + +static void +acerm3a_out(uint16_t port, uint8_t val, void *p) +{ + acerm3a_t *dev = (acerm3a_t *) p; + + if (port == 0xea) + dev->index = val; +} + + +static uint8_t +acerm3a_in(uint16_t port, void *p) +{ + acerm3a_t *dev = (acerm3a_t *) p; + + if (port == 0xeb) { + switch (dev->index) { + case 2: + return 0xfd; + } + } + return 0xff; +} + + +static void +acerm3a_close(void *p) +{ + acerm3a_t *dev = (acerm3a_t *)p; + + free(dev); +} + + +static void +*acerm3a_init(const device_t *info) +{ + acerm3a_t *acerm3a = (acerm3a_t *) malloc(sizeof(acerm3a_t)); + memset(acerm3a, 0, sizeof(acerm3a_t)); + + io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, acerm3a); + + return acerm3a; +} + + +const device_t acerm3a_device = +{ + "Acer M3A Register", + 0, + 0, + acerm3a_init, + acerm3a_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/chipset/ali1429.c b/src/chipset/ali1429.c new file mode 100644 index 000000000..5d5b4bd83 --- /dev/null +++ b/src/chipset/ali1429.c @@ -0,0 +1,146 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ALi M-1429/1431 chipset. + * + * Version: @(#)ali1429.c 1.0.9 2019/10/09 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../io.h" +#include "../mem.h" +#include "../device.h" +#include "../keyboard.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../timer.h" +#include "../port_92.h" +#include "chipset.h" + + +typedef struct +{ + uint8_t cur_reg, + regs[256]; +} ali1429_t; + + +static void +ali1429_recalc(ali1429_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + for (i = 0; i < 8; i++) { + base = 0xc0000 + (i << 15); + + if (dev->regs[0x13] & (1 << i)) { + shadowbios |= (base >= 0xe8000) && !!(dev->regs[0x14] & 0x01); + shadowbios_write |= (base >= 0xe8000) && !!(dev->regs[0x14] & 0x02); + shflags = (dev->regs[0x14] & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + shflags |= !(dev->regs[0x14] & 0x02) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; + mem_set_mem_state(base, 0x8000, shflags); + } else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + + flushmmucache(); +} + + +static void +ali1429_write(uint16_t port, uint8_t val, void *priv) +{ + ali1429_t *dev = (ali1429_t *) priv; + + if (port & 1) { + dev->regs[dev->cur_reg] = val; + + switch (dev->cur_reg) { + case 0x13: + ali1429_recalc(dev); + break; + case 0x14: + ali1429_recalc(dev); + break; + } + } else + dev->cur_reg = val; +} + + +static uint8_t +ali1429_read(uint16_t port, void *priv) +{ + uint8_t ret = 0xff; + ali1429_t *dev = (ali1429_t *) priv; + + if (!(port & 1)) + ret = dev->cur_reg; + else if (((dev->cur_reg >= 0xc0) || (dev->cur_reg == 0x20)) && cpu_iscyrix) + ret = 0xff; /*Don't conflict with Cyrix config registers*/ + else + ret = dev->regs[dev->cur_reg]; + + return ret; +} + + +static void +ali1429_close(void *priv) +{ + ali1429_t *dev = (ali1429_t *) priv; + + free(dev); +} + + +static void * +ali1429_init(const device_t *info) +{ + ali1429_t *dev = (ali1429_t *) malloc(sizeof(ali1429_t)); + memset(dev, 0, sizeof(ali1429_t)); + + memset(dev->regs, 0xff, 256); + dev->regs[0x13] = dev->regs[0x14] = 0x00; + + io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, dev); + + ali1429_recalc(dev); + + device_add(&port_92_device); + + return dev; +} + + +const device_t ali1429_device = { + "ALi-M1429", + 0, + 0, + ali1429_init, ali1429_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/chipset.h b/src/chipset/chipset.h new file mode 100644 index 000000000..bf2cda160 --- /dev/null +++ b/src/chipset/chipset.h @@ -0,0 +1,68 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handling of the emulated chipsets. + * + * Version: @(#)machine.h 1.0.0 2019/05/13 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#ifndef EMU_CHIPSET_H +# define EMU_CHIPSET_H + + +/* ACC */ +extern const device_t acc2168_device; + +/* Acer M3A and V35N */ +extern const device_t acerm3a_device; + +/* ALi */ +extern const device_t ali1429_device; + +/* Headland */ +extern const device_t headland_device; +extern const device_t headland_386_device; + +/* Intel 4x0xX */ +extern const device_t i420tx_device; +extern const device_t i430lx_device; +extern const device_t i430nx_device; +extern const device_t i430fx_device; +extern const device_t i430fx_pb640_device; +extern const device_t i430hx_device; +extern const device_t i430vx_device; +#if defined(DEV_BRANCH) && defined(USE_I686) +extern const device_t i440fx_device; +#endif + +/* NEAT */ +extern const device_t neat_device; + +/* OPTi */ +extern const device_t opti495_device; + +/* SCAT */ +extern const device_t scat_device; +extern const device_t scat_4_device; +extern const device_t scat_sx_device; + +/* SiS */ +extern const device_t sis_85c471_device; +extern const device_t sis_85c496_device; +#if defined(DEV_BRANCH) && defined(USE_SIS_85C50X) +extern const device_t sis_85c50x_device; +#endif + +/* WD */ +extern const device_t wd76c10_device; + + +#endif /*EMU_CHIPSET_H*/ diff --git a/src/chipset/headland.c b/src/chipset/headland.c new file mode 100644 index 000000000..cbd52cfb1 --- /dev/null +++ b/src/chipset/headland.c @@ -0,0 +1,635 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the HEADLAND AT286 chipset. + * + * Version: @(#)headland.c 1.0.1 2019/10/19 + * + * Authors: Sarah Walker, + * Fred N. van Kempen, + * Original by GreatPsycho for PCem. + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2017-2019 Miran Grca. + * Copyright 2017-2019 GreatPsycho. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../cpu/x86.h" +#include "../timer.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../keyboard.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../port_92.h" +#include "chipset.h" + + +typedef struct { + uint8_t valid, pad; + uint16_t mr; + + struct headland_t * headland; +} headland_mr_t; + + +typedef struct headland_t { + uint8_t type; + + uint8_t cri; + uint8_t cr[8]; + + uint8_t indx; + uint8_t regs[256]; + + uint8_t ems_mar; + + headland_mr_t null_mr, + ems_mr[64]; + + rom_t vid_bios; + + mem_mapping_t low_mapping; + mem_mapping_t ems_mapping[64]; + mem_mapping_t mid_mapping; + mem_mapping_t high_mapping; + mem_mapping_t upper_mapping[24]; +} headland_t; + + +/* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet, + so memory configuration is hardcoded now. */ +static const int 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 const int 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 +}; + + +static uint32_t +get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) +{ + if (mr && mr->valid && (dev->cr[0] & 2) && (mr->mr & 0x200)) { + addr = (addr & 0x3fff) | ((mr->mr & 0x1F) << 14); + if (dev->cr[1] & 0x40) { + if ((dev->cr[4] & 0x80) && (dev->cr[6] & 1)) { + if (dev->cr[0] & 0x80) { + addr |= (mr->mr & 0x60) << 14; + if (mr->mr & 0x100) + addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x80) + 0x80) << 15); + else + addr += (mr->mr & 0x80) << 14; + } else if (mr->mr & 0x100) + addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x80) + 0x20) << 15); + else + addr += (mr->mr & 0x80) << 12; + } else if (dev->cr[0] & 0x80) + addr |= (mr->mr & 0x100) ? ((mr->mr & 0x80) + 0x400) << 12 : (mr->mr & 0xE0) << 14; + else + addr |= (mr->mr & 0x100) ? ((mr->mr & 0xE0) + 0x40) << 14 : (mr->mr & 0x80) << 12; + } else { + if ((dev->cr[4] & 0x80) && (dev->cr[6] & 1)) { + if (dev->cr[0] & 0x80) { + addr |= ((mr->mr & 0x60) << 14); + if (mr->mr & 0x180) + addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x180) - 0x60) << 16); + } else + addr |= ((mr->mr & 0x60) << 14) | ((mr->mr & 0x180) << 16) | ((mr->mr & 0xC00) << 13); + } else if (dev->cr[0] & 0x80) + addr |= (mr->mr & 0x1E0) << 14; + else + addr |= (mr->mr & 0x180) << 12; + } + } else if ((mr == NULL) && ((dev->cr[0] & 4) == 0) && (mem_size >= 1024) && (addr >= 0x100000)) + addr -= 0x60000; + + return addr; +} + + +static void +set_global_EMS_state(headland_t *dev, int state) +{ + uint32_t base_addr, virt_addr; + int i; + + for (i = 0; i < 32; i++) { + base_addr = (i + 16) << 14; + if (i >= 24) + base_addr += 0x20000; + if ((state & 2) && (dev->ems_mr[((state & 1) << 5) | i].mr & 0x200)) { + virt_addr = get_addr(dev, base_addr, &dev->ems_mr[((state & 1) << 5) | i]); + if (i < 24) + mem_mapping_disable(&dev->upper_mapping[i]); + mem_mapping_disable(&dev->ems_mapping[(((state ^ 1) & 1) << 5) | i]); + mem_mapping_enable(&dev->ems_mapping[((state & 1) << 5) | i]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], NULL); + } else { + mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[(((state ^ 1) & 1) << 5) | i]); + mem_mapping_disable(&dev->ems_mapping[((state & 1) << 5) | i]); + if (i < 24) + mem_mapping_enable(&dev->upper_mapping[i]); + } + } + + flushmmucache(); +} + + +static void +memmap_state_update(headland_t *dev) +{ + uint32_t addr; + int i; + + for (i = 0; i < 24; i++) { + addr = get_addr(dev, 0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&dev->upper_mapping[i], addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + } + mem_set_mem_state(0xA0000, 0x40000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + if (mem_size > 640) { + if ((dev->cr[0] & 4) == 0) { + mem_mapping_set_addr(&dev->mid_mapping, 0x100000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); + if (mem_size > 1024) { + mem_mapping_set_addr(&dev->high_mapping, 0x160000, (mem_size - 1024) << 10); + mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } + } else { + mem_mapping_set_addr(&dev->mid_mapping, 0xA0000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); + if (mem_size > 1024) { + mem_mapping_set_addr(&dev->high_mapping, 0x100000, (mem_size - 1024) << 10); + mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } + } + } + + set_global_EMS_state(dev, dev->cr[0] & 3); +} + + +static void +hl_write(uint16_t addr, uint8_t val, void *priv) +{ + headland_t *dev = (headland_t *)priv; + uint32_t base_addr, virt_addr; + uint8_t old_val, indx; + + switch(addr) { + case 0x0022: + dev->indx = val; + break; + + case 0x0023: + old_val = dev->regs[dev->indx]; + if ((dev->indx == 0xc1) && !is486) + val = 0; + dev->regs[dev->indx] = val; + if (dev->indx == 0x82) { + shadowbios = val & 0x10; + shadowbios_write = !(val & 0x10); + if (shadowbios) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + } else if (dev->indx == 0x87) { + if ((val & 1) && !(old_val & 1)) + softresetx86(); + } + break; + + case 0x01ec: + dev->ems_mr[dev->ems_mar & 0x3f].mr = val | 0xff00; + indx = dev->ems_mar & 0x1f; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x20000; + if ((dev->cr[0] & 2) && ((dev->cr[0] & 1) == ((dev->ems_mar & 0x20) >> 5))) { + virt_addr = get_addr(dev, base_addr, &dev->ems_mr[dev->ems_mar & 0x3F]); + if (indx < 24) + mem_mapping_disable(&dev->upper_mapping[indx]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], NULL); + mem_mapping_enable(&dev->ems_mapping[dev->ems_mar & 0x3f]); + flushmmucache(); + } + if (dev->ems_mar & 0x80) + dev->ems_mar++; + break; + + case 0x01ed: + dev->cri = val; + break; + + case 0x01ee: + dev->ems_mar = val; + break; + + case 0x01ef: + old_val = dev->cr[dev->cri]; + switch(dev->cri) { + case 0: + dev->cr[0] = (val & 0x1f) | 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_EXTANY) | MEM_WRITE_DISABLED); + mem_set_mem_state(0xf0000, 0x10000, (val & 0x10 ? MEM_READ_INTERNAL: MEM_READ_EXTANY) | MEM_WRITE_DISABLED); + memmap_state_update(dev); + break; + + case 1: + dev->cr[1] = (val & 0xbf) | mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + memmap_state_update(dev); + break; + + case 2: + case 3: + case 5: + dev->cr[dev->cri] = val; + memmap_state_update(dev); + break; + + case 4: + dev->cr[4] = (dev->cr[4] & 0xf0) | (val & 0x0f); + if (val & 1) { + mem_mapping_set_addr(&bios_mapping, 0x000f0000, 0x10000); + mem_mapping_set_exec(&bios_mapping, &(rom[0x10000])); + } else { + mem_mapping_set_addr(&bios_mapping, 0x000e0000, 0x20000); + mem_mapping_set_exec(&bios_mapping, rom); + } + break; + + case 6: + if (dev->cr[4] & 0x80) { + dev->cr[dev->cri] = (val & 0xfe) | (mem_size > 8192 ? 1 : 0); + memmap_state_update(dev); + } + break; + + default: + break; + } + break; + + default: + break; + } +} + + +static void +hl_writew(uint16_t addr, uint16_t val, void *priv) +{ + headland_t *dev = (headland_t *)priv; + uint32_t base_addr, virt_addr; + uint8_t indx; + + switch(addr) { + case 0x01ec: + dev->ems_mr[dev->ems_mar & 0x3f].mr = val; + indx = dev->ems_mar & 0x1f; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x20000; + if ((dev->cr[0] & 2) && (dev->cr[0] & 1) == ((dev->ems_mar & 0x20) >> 5)) { + if (val & 0x200) { + virt_addr = get_addr(dev, base_addr, &dev->ems_mr[dev->ems_mar & 0x3f]); + if (indx < 24) + mem_mapping_disable(&dev->upper_mapping[indx]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], NULL); + mem_mapping_enable(&dev->ems_mapping[dev->ems_mar & 0x3f]); + } else { + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[dev->ems_mar & 0x3f]); + if (indx < 24) + mem_mapping_enable(&dev->upper_mapping[indx]); + } + flushmmucache(); + } + if (dev->ems_mar & 0x80) + dev->ems_mar++; + break; + + default: + break; + } +} + + +static uint8_t +hl_read(uint16_t addr, void *priv) +{ + headland_t *dev = (headland_t *)priv; + uint8_t ret = 0xff; + + switch(addr) { + case 0x0022: + ret = dev->indx; + break; + + case 0x0023: + if ((dev->indx >= 0xc0 || dev->indx == 0x20) && cpu_iscyrix) + ret = 0xff; /*Don't conflict with Cyrix config registers*/ + else + ret = dev->regs[dev->indx]; + break; + + case 0x01ec: + ret = (uint8_t)dev->ems_mr[dev->ems_mar & 0x3f].mr; + if (dev->ems_mar & 0x80) + dev->ems_mar++; + break; + + case 0x01ed: + ret = dev->cri; + break; + + case 0x01ee: + ret = dev->ems_mar; + break; + + case 0x01ef: + switch(dev->cri) { + case 0: + ret = (dev->cr[0] & 0x1f) | mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + break; + + case 1: + ret = (dev->cr[1] & 0xbf) | mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + break; + + case 6: + if (dev->cr[4] & 0x80) + ret = (dev->cr[6] & 0xfe) | (mem_size > 8192 ? 1 : 0); + else + ret = 0; + break; + + default: + ret = dev->cr[dev->cri]; + break; + } + break; + + default: + break; + } + + return ret; +} + + +static uint16_t +hl_readw(uint16_t addr, void *priv) +{ + headland_t *dev = (headland_t *)priv; + uint16_t ret = 0xffff; + + switch(addr) { + case 0x01ec: + ret = dev->ems_mr[dev->ems_mar & 0x3f].mr | ((dev->cr[4] & 0x80) ? 0xf000 : 0xfc00); + if (dev->ems_mar & 0x80) + dev->ems_mar++; + break; + + default: + break; + } + + return ret; +} + + +static uint8_t +mem_read_b(uint32_t addr, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + uint8_t ret = 0xff; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + ret = ram[addr]; + + return ret; +} + + +static uint16_t +mem_read_w(uint32_t addr, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + uint16_t ret = 0xffff; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + ret = *(uint16_t *)&ram[addr]; + + return ret; +} + + +static uint32_t +mem_read_l(uint32_t addr, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + uint32_t ret = 0xffffffff; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + ret = *(uint32_t *)&ram[addr]; + + return ret; +} + + +static void +mem_write_b(uint32_t addr, uint8_t val, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + ram[addr] = val; +} + + +static void +mem_write_w(uint32_t addr, uint16_t val, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + + +static void +mem_write_l(uint32_t addr, uint32_t val, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + *(uint32_t *)&ram[addr] = val; +} + + +static void +headland_close(void *priv) +{ + headland_t *dev = (headland_t *)priv; + + free(dev); +} + + +static void * +headland_init(const device_t *info) +{ + headland_t *dev; + int ht386; + uint32_t i; + + dev = (headland_t *) malloc(sizeof(headland_t)); + memset(dev, 0x00, sizeof(headland_t)); + dev->type = info->local; + + ht386 = (dev->type == 32) ? 1 : 0; + + for (i = 0; i < 8; i++) + dev->cr[i] = 0x00; + dev->cr[0] = 0x04; + + if (ht386) { + dev->cr[4] = 0x20; + + device_add(&port_92_inv_device); + } else + dev->cr[4] = 0x00; + + io_sethandler(0x01ec, 1, + hl_read,hl_readw,NULL, hl_write,hl_writew,NULL, dev); + + io_sethandler(0x01ed, 3, hl_read,NULL,NULL, hl_write,NULL,NULL, dev); + + dev->ems_mr[i].valid = 0; + dev->ems_mr[i].mr = 0xff; + dev->ems_mr[i].headland = dev; + + for (i = 0; i < 64; i++) { + dev->ems_mr[i].valid = 1; + dev->ems_mr[i].mr = 0x00; + dev->ems_mr[i].headland = dev; + } + + /* Turn off mem.c mappings. */ + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + + mem_mapping_add(&dev->low_mapping, 0, 0x40000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ram, MEM_MAPPING_INTERNAL, &dev->null_mr); + + if (mem_size > 640) { + mem_mapping_add(&dev->mid_mapping, 0xa0000, 0x60000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ram + 0xa0000, MEM_MAPPING_INTERNAL, &dev->null_mr); + mem_mapping_enable(&dev->mid_mapping); + } + + if (mem_size > 1024) { + mem_mapping_add(&dev->high_mapping, 0x100000, ((mem_size-1024)*1024), + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ram + 0x100000, MEM_MAPPING_INTERNAL, &dev->null_mr); + mem_mapping_enable(&dev->high_mapping); + } + + for (i = 0; i < 24; i++) { + mem_mapping_add(&dev->upper_mapping[i], + 0x40000 + (i << 14), 0x4000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, + MEM_MAPPING_INTERNAL, &dev->null_mr); + mem_mapping_enable(&dev->upper_mapping[i]); + } + + for (i = 0; i < 64; i++) { + dev->ems_mr[i].mr = 0x00; + mem_mapping_add(&dev->ems_mapping[i], + ((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14, 0x04000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ram + (((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14), + 0, &dev->ems_mr[i]); + } + + memmap_state_update(dev); + + return(dev); +} + + +const device_t headland_device = { + "Headland 286", + 0, + 0, + headland_init, headland_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t headland_386_device = { + "Headland 386", + 0, + 32, + headland_init, headland_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c new file mode 100644 index 000000000..cf2901146 --- /dev/null +++ b/src/chipset/intel_4x0.c @@ -0,0 +1,452 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel PCISet chips from 420TX to 440FX. + * + * Version: @(#)intel_4x0.c 1.0.2 2019/10/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../keyboard.h" +#include "chipset.h" + + +enum +{ + INTEL_420TX, + INTEL_430LX, + INTEL_430NX, + INTEL_430FX, + INTEL_430FX_PB640, + INTEL_430HX, + INTEL_430VX +#if defined(DEV_BRANCH) && defined(USE_I686) + ,INTEL_440FX +#endif +}; + +typedef struct +{ + uint8_t regs[256]; + int type; +} i4x0_t; +static void +i4x0_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + + +static void +i4x0_write(int func, int addr, uint8_t val, void *priv) +{ + i4x0_t *dev = (i4x0_t *) 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*/ + if (dev->type >= INTEL_430FX) { + if (dev->type == INTEL_430FX_PB640) + val &= 0x06; + else + val &= 0x02; + } else + val &= 0x42; + val |= 0x04; + break; + case 0x05: + if (dev->type >= INTEL_430FX) + val = 0; + else + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + if (dev->type >= INTEL_430HX) { + val &= 0x80; + val |= 0x02; + } else { + val = 0x02; + if (dev->type == INTEL_430FX_PB640) + val |= 0x20; + } + break; + + case 0x52: /*Cache Control Register*/ +#if defined(DEV_BRANCH) && defined(USE_I686) + if (dev->type < INTEL_440FX) { +#endif + cpu_cache_ext_enabled = (val & 0x01); + cpu_update_waitstates(); +#if defined(DEV_BRANCH) && defined(USE_I686) + } +#endif + break; + + case 0x59: /*PAM0*/ + if ((dev->regs[0x59] ^ val) & 0xf0) { + i4x0_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + break; + case 0x5a: /*PAM1*/ + if ((dev->regs[0x5a] ^ val) & 0x0f) + i4x0_map(0xc0000, 0x04000, val & 0xf); + if ((dev->regs[0x5a] ^ val) & 0xf0) + i4x0_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((dev->regs[0x5b] ^ val) & 0x0f) + i4x0_map(0xc8000, 0x04000, val & 0xf); + if ((dev->regs[0x5b] ^ val) & 0xf0) + i4x0_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((dev->regs[0x5c] ^ val) & 0x0f) + i4x0_map(0xd0000, 0x04000, val & 0xf); + if ((dev->regs[0x5c] ^ val) & 0xf0) + i4x0_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((dev->regs[0x5d] ^ val) & 0x0f) + i4x0_map(0xd8000, 0x04000, val & 0xf); + if ((dev->regs[0x5d] ^ val) & 0xf0) + i4x0_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((dev->regs[0x5e] ^ val) & 0x0f) + i4x0_map(0xe0000, 0x04000, val & 0xf); + if ((dev->regs[0x5e] ^ val) & 0xf0) + i4x0_map(0xe4000, 0x04000, val >> 4); + break; + case 0x5f: /*PAM6*/ + if ((dev->regs[0x5f] ^ val) & 0x0f) + i4x0_map(0xe8000, 0x04000, val & 0xf); + if ((dev->regs[0x5f] ^ val) & 0xf0) + i4x0_map(0xec000, 0x04000, val >> 4); + break; + case 0x72: /*SMRAM*/ + if ((dev->type >= INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x48)) + i4x0_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + else if ((dev->type < INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x20)) + i4x0_map(0xa0000, 0x20000, ((val & 0x20) == 0x20) ? 3 : 0); + break; + } + + dev->regs[addr] = val; +} + + +static uint8_t +i4x0_read(int func, int addr, void *priv) +{ + i4x0_t *dev = (i4x0_t *) priv; + + if (func) + return 0xff; + + return dev->regs[addr]; +} + + +static void +i4x0_reset(void *priv) +{ + i4x0_t *i4x0 = (i4x0_t *)priv; + + i4x0_write(0, 0x59, 0x00, priv); + if (i4x0->type >= INTEL_430FX) + i4x0_write(0, 0x72, 0x02, priv); +} + + +static void +i4x0_close(void *p) +{ + i4x0_t *i4x0 = (i4x0_t *)p; + + free(i4x0); +} + + +static void +*i4x0_init(const device_t *info) +{ + i4x0_t *i4x0 = (i4x0_t *) malloc(sizeof(i4x0_t)); + memset(i4x0, 0, sizeof(i4x0_t)); + + i4x0->type = info->local; + + i4x0->regs[0x00] = 0x86; i4x0->regs[0x01] = 0x80; /*Intel*/ + switch(i4x0->type) { + case INTEL_420TX: + i4x0->regs[0x02] = 0x83; i4x0->regs[0x03] = 0x04; /*82424TX/ZX*/ + i4x0->regs[0x08] = 0x03; /*A3 stepping*/ + i4x0->regs[0x50] = 0x80; + i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ + break; + case INTEL_430LX: + i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ + i4x0->regs[0x08] = 0x03; /*A3 stepping*/ + i4x0->regs[0x50] = 0x80; + i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ + break; + case INTEL_430NX: + i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ + i4x0->regs[0x08] = 0x10; /*A0 stepping*/ + i4x0->regs[0x50] = 0xA0; + i4x0->regs[0x52] = 0x44; /*256kb PLB cache*/ + i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; + break; + case INTEL_430FX: + case INTEL_430FX_PB640: + i4x0->regs[0x02] = 0x2d; i4x0->regs[0x03] = 0x12; /*SB82437FX-66*/ + if (i4x0->type == INTEL_430FX_PB640) + i4x0->regs[0x08] = 0x02; /*???? stepping*/ + else + i4x0->regs[0x08] = 0x00; /*A0 stepping*/ + i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ + break; + case INTEL_430HX: + i4x0->regs[0x02] = 0x50; i4x0->regs[0x03] = 0x12; /*82439HX*/ + i4x0->regs[0x08] = 0x00; /*A0 stepping*/ + i4x0->regs[0x51] = 0x20; + i4x0->regs[0x52] = 0xB5; /*512kb cache*/ + i4x0->regs[0x56] = 0x52; /*DRAM control*/ + i4x0->regs[0x59] = 0x40; + i4x0->regs[0x5A] = i4x0->regs[0x5B] = i4x0->regs[0x5C] = i4x0->regs[0x5D] = 0x44; + i4x0->regs[0x5E] = i4x0->regs[0x5F] = 0x44; + i4x0->regs[0x65] = i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; + i4x0->regs[0x68] = 0x11; + break; + case INTEL_430VX: + i4x0->regs[0x02] = 0x30; i4x0->regs[0x03] = 0x70; /*82437VX*/ + i4x0->regs[0x08] = 0x00; /*A0 stepping*/ + i4x0->regs[0x52] = 0x42; /*256kb PLB cache*/ + i4x0->regs[0x53] = 0x14; + i4x0->regs[0x56] = 0x52; /*DRAM control*/ + i4x0->regs[0x67] = 0x11; + i4x0->regs[0x69] = 0x03; + i4x0->regs[0x70] = 0x20; + i4x0->regs[0x74] = 0x0e; + i4x0->regs[0x78] = 0x23; + break; +#if defined(DEV_BRANCH) && defined(USE_I686) + case INTEL_440FX: + i4x0->regs[0x02] = 0x37; i4x0->regs[0x03] = 0x12; /*82441FX*/ + i4x0->regs[0x08] = 0x02; /*A0 stepping*/ + i4x0->regs[0x2c] = 0xf4; + i4x0->regs[0x2d] = 0x1a; + i4x0->regs[0x2f] = 0x11; + i4x0->regs[0x51] = 0x01; + i4x0->regs[0x53] = 0x80; + i4x0->regs[0x58] = 0x10; + i4x0->regs[0x5a] = i4x0->regs[0x5b] = i4x0->regs[0x5c] = i4x0->regs[0x5d] = 0x11; + i4x0->regs[0x5e] = 0x11; + i4x0->regs[0x5f] = 0x31; + break; +#endif + } + i4x0->regs[0x04] = 0x06; i4x0->regs[0x05] = 0x00; +#if defined(DEV_BRANCH) && defined(USE_I686) + if (i4x0->type == INTEL_440FX) + i4x0->regs[0x06] = 0x80; +#endif + if (i4x0->type == INTEL_430FX) + i4x0->regs[0x07] = 0x82; +#if defined(DEV_BRANCH) && defined(USE_I686) + else if (i4x0->type != INTEL_440FX) +#else + else +#endif + i4x0->regs[0x07] = 0x02; + i4x0->regs[0x0b] = 0x06; + if (i4x0->type >= INTEL_430FX) + i4x0->regs[0x57] = 0x01; + else + i4x0->regs[0x57] = 0x31; + i4x0->regs[0x60] = i4x0->regs[0x61] = i4x0->regs[0x62] = i4x0->regs[0x63] = 0x02; + i4x0->regs[0x64] = 0x02; + if (i4x0->type >= INTEL_430FX) + i4x0->regs[0x72] = 0x02; + +#if defined(DEV_BRANCH) && defined(USE_I686) + if (i4x0->type == INTEL_440FX) { + cpu_cache_ext_enabled = 1; + cpu_update_waitstates(); + } +#endif + + pci_add_card(0, i4x0_read, i4x0_write, i4x0); + + return i4x0; +} + + +const device_t i420tx_device = +{ + "Intel 82424TX", + DEVICE_PCI, + INTEL_420TX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430lx_device = +{ + "Intel 82434LX", + DEVICE_PCI, + INTEL_430LX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430nx_device = +{ + "Intel 82434NX", + DEVICE_PCI, + INTEL_430NX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430fx_device = +{ + "Intel SB82437FX-66", + DEVICE_PCI, + INTEL_430FX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430fx_pb640_device = +{ + "Intel SB82437FX-66 (PB640)", + DEVICE_PCI, + INTEL_430FX_PB640, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430hx_device = +{ + "Intel 82439HX", + DEVICE_PCI, + INTEL_430HX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430vx_device = +{ + "Intel 82437VX", + DEVICE_PCI, + INTEL_430VX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +#if defined(DEV_BRANCH) && defined(USE_I686) +const device_t i440fx_device = +{ + "Intel 82441FX", + DEVICE_PCI, + INTEL_440FX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; +#endif diff --git a/src/chipset/neat.c b/src/chipset/neat.c new file mode 100644 index 000000000..4f2524db9 --- /dev/null +++ b/src/chipset/neat.c @@ -0,0 +1,861 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of C&T CS8121 ("NEAT") 82C206/211/212/215 chipset. + * + * Note: The datasheet mentions that the chipset supports up to 8MB + * of DRAM. This is intepreted as 'being able to refresh up to + * 8MB of DRAM chips', because it works fine with bus-based + * memory expansion. + * + * Version: @(#)m_at_neat.c 1.0.5 2018/10/22 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../keyboard.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "chipset.h" + +#define NEAT_DEBUG 0 + + +#define EMS_MAXPAGE 4 +#define EMS_PGSIZE 16384 + + +/* CS8221 82C211 controller registers. */ +#define REG_RA0 0x60 /* PROCCLK selector */ +# define RA0_MASK 0x34 /* RR11 X1XR */ +# define RA0_READY 0x01 /* local bus READY timeout */ +# define RA0_RDYNMIEN 0x04 /* local bus READY tmo NMI enable */ +# define RA0_PROCCLK 0x10 /* PROCCLK=BCLK (1) or CLK2IN (0) */ +# define RA0_ALTRST 0x20 /* alternate CPU reset (1) */ +# define RA0_REV 0xc0 /* chip revision ID */ +# define RA0_REV_SH 6 +# define RA0_REV_ID 2 /* faked revision# for 82C211 */ + +#define REG_RA1 0x61 /* Command Delay */ +# define RA1_MASK 0xff /* 1111 1111 */ +# define RA1_BUSDLY 0x03 /* AT BUS command delay */ +# define RA1_BUSDLY_SH 0 +# define RA1_BUS8DLY 0x0c /* AT BUS 8bit command delay */ +# define RA1_BUS8DLY_SH 2 +# define RA1_MEMDLY 0x30 /* AT BUS 16bit memory delay */ +# define RA1_MEMDLY_SH 4 +# define RA1_QUICKEN 0x40 /* Quick Mode enable */ +# define RA1_HOLDDLY 0x80 /* Hold Time Delay */ + +#define REG_RA2 0x62 /* Wait State / BCLK selector */ +# define RA2_MASK 0x3f /* XX11 1111 */ +# define RA2_BCLK 0x03 /* BCLK select */ +# define RA2_BCLK_SH 0 +# define BCLK_IN2 0 /* BCLK = CLK2IN/2 */ +# define BCLK_IN 1 /* BCLK = CLK2IN */ +# define BCLK_AT 2 /* BCLK = ATCLK */ +# define RA2_AT8WS 0x0c /* AT 8-bit wait states */ +# define RA2_AT8WS_SH 2 +# define AT8WS_2 0 /* 2 wait states */ +# define AT8WS_3 1 /* 3 wait states */ +# define AT8WS_4 2 /* 4 wait states */ +# define AT8WS_5 4 /* 5 wait states */ +# define RA2_ATWS 0x30 /* AT 16-bit wait states */ +# define RA2_ATWS_SH 4 +# define ATWS_2 0 /* 2 wait states */ +# define ATWS_3 1 /* 3 wait states */ +# define ATWS_4 2 /* 4 wait states */ +# define ATWS_5 4 /* 5 wait states */ + +/* CS8221 82C212 controller registers. */ +#define REG_RB0 0x64 /* Version ID */ +# define RB0_MASK 0x60 /* R11X XXXX */ +# define RB0_REV 0x60 /* Chip revsion number */ +# define RB0_REV_SH 5 +# define RB0_REV_ID 2 /* faked revision# for 82C212 */ +# define RB0_VERSION 0x80 /* Chip version (0=82C212) */ + +#define REG_RB1 0x65 /* ROM configuration */ +# define RB1_MASK 0xff /* 1111 1111 */ +# define RB1_ROMF0 0x01 /* ROM F0000 enabled (0) */ +# define RB1_ROME0 0x02 /* ROM E0000 disabled (1) */ +# define RB1_ROMD0 0x04 /* ROM D0000 disabled (1) */ +# define RB1_ROMC0 0x08 /* ROM C0000 disabled (1) */ +# define RB1_SHADOWF0 0x10 /* Shadow F0000 R/W (0) */ +# define RB1_SHADOWE0 0x20 /* Shadow E0000 R/W (0) */ +# define RB1_SHADOWD0 0x40 /* Shadow D0000 R/W (0) */ +# define RB1_SHADOWC0 0x80 /* Shadow C0000 R/W (0) */ + +#define REG_RB2 0x66 /* Memory Enable 1 */ +# define RB2_MASK 0x80 /* 1XXX XXXX */ +# define RB2_TOP128 0x80 /* top 128K is on sysboard (1) */ + +#define REG_RB3 0x67 /* Memory Enable 2 */ +# define RB3_MASK 0xff /* 1111 1111 */ +# define RB3_SHENB0 0x01 /* enable B0000-B3FFF shadow (1) */ +# define RB3_SHENB4 0x02 /* enable B4000-B7FFF shadow (1) */ +# define RB3_SHENB8 0x04 /* enable B8000-BBFFF shadow (1) */ +# define RB3_SHENBC 0x08 /* enable BC000-BFFFF shadow (1) */ +# define RB3_SHENA0 0x10 /* enable A0000-A3FFF shadow (1) */ +# define RB3_SHENA4 0x20 /* enable A4000-A7FFF shadow (1) */ +# define RB3_SHENA8 0x40 /* enable A8000-ABFFF shadow (1) */ +# define RB3_SHENAC 0x80 /* enable AC000-AFFFF shadow (1) */ + +#define REG_RB4 0x68 /* Memory Enable 3 */ +# define RB4_MASK 0xff /* 1111 1111 */ +# define RB4_SHENC0 0x01 /* enable C0000-C3FFF shadow (1) */ +# define RB4_SHENC4 0x02 /* enable C4000-C7FFF shadow (1) */ +# define RB4_SHENC8 0x04 /* enable C8000-CBFFF shadow (1) */ +# define RB4_SHENCC 0x08 /* enable CC000-CFFFF shadow (1) */ +# define RB4_SHEND0 0x10 /* enable D0000-D3FFF shadow (1) */ +# define RB4_SHEND4 0x20 /* enable D4000-D7FFF shadow (1) */ +# define RB4_SHEND8 0x40 /* enable D8000-DBFFF shadow (1) */ +# define RB4_SHENDC 0x80 /* enable DC000-DFFFF shadow (1) */ + +#define REG_RB5 0x69 /* Memory Enable 4 */ +# define RB5_MASK 0xff /* 1111 1111 */ +# define RB5_SHENE0 0x01 /* enable E0000-E3FFF shadow (1) */ +# define RB5_SHENE4 0x02 /* enable E4000-E7FFF shadow (1) */ +# define RB5_SHENE8 0x04 /* enable E8000-EBFFF shadow (1) */ +# define RB5_SHENEC 0x08 /* enable EC000-EFFFF shadow (1) */ +# define RB5_SHENF0 0x10 /* enable F0000-F3FFF shadow (1) */ +# define RB5_SHENF4 0x20 /* enable F4000-F7FFF shadow (1) */ +# define RB5_SHENF8 0x40 /* enable F8000-FBFFF shadow (1) */ +# define RB5_SHENFC 0x80 /* enable FC000-FFFFF shadow (1) */ + +#define REG_RB6 0x6a /* Bank 0/1 Enable */ +# define RB6_MASK 0xe0 /* 111R RRRR */ +# define RB6_BANKS 0x20 /* #banks used (1=two) */ +# define RB6_RTYPE 0xc0 /* DRAM chip size used */ +# define RTYPE_SH 6 +# define RTYPE_NONE 0 /* Disabled */ +# define RTYPE_MIXED 1 /* 64K/256K mixed (for 640K) */ +# define RTYPE_256K 2 /* 256K (default) */ +# define RTYPE_1M 3 /* 1M */ + +#define REG_RB7 0x6b /* DRAM configuration */ +# define RB7_MASK 0xff /* 1111 1111 */ +# define RB7_ROMWS 0x03 /* ROM access wait states */ +# define RB7_ROMWS_SH 0 +# define ROMWS_0 0 /* 0 wait states */ +# define ROMWS_1 1 /* 1 wait states */ +# define ROMWS_2 2 /* 2 wait states */ +# define ROMWS_3 3 /* 3 wait states (default) */ +# define RB7_EMSWS 0x0c /* EMS access wait states */ +# define RB7_EMSWS_SH 2 +# define EMSWS_0 0 /* 0 wait states */ +# define EMSWS_1 1 /* 1 wait states */ +# define EMSWS_2 2 /* 2 wait states */ +# define EMSWS_3 3 /* 3 wait states (default) */ +# define RB7_EMSEN 0x10 /* enable EMS (1=on) */ +# define RB7_RAMWS 0x20 /* RAM access wait state (1=1ws) */ +# define RB7_UMAREL 0x40 /* relocate 640-1024K to 1M */ +# define RB7_PAGEEN 0x80 /* enable Page/Interleaved mode */ + +#define REG_RB8 0x6c /* Bank 2/3 Enable */ +# define RB8_MASK 0xf0 /* 1111 RRRR */ +# define RB8_4WAY 0x10 /* enable 4-way interleave mode */ +# define RB8_BANKS 0x20 /* enable 2 banks (1) */ +# define RB8_RTYPE 0xc0 /* DRAM chip size used */ +# define RB8_RTYPE_SH 6 + +#define REG_RB9 0x6d /* EMS base address */ +# define RB9_MASK 0xff /* 1111 1111 */ +# define RB9_BASE 0x0f /* I/O base address selection */ +# define RB9_BASE_SH 0 +# define RB9_FRAME 0xf0 /* frame address selection */ +# define RB9_FRAME_SH 4 + +#define REG_RB10 0x6e /* EMS address extension */ +# define RB10_MASK 0xff /* 1111 1111 */ +# define RB10_P3EXT 0x03 /* page 3 extension */ +# define RB10_P3EXT_SH 0 +# define PEXT_0M 0 /* page is at 0-2M */ +# define PEXT_2M 1 /* page is at 2-4M */ +# define PEXT_4M 2 /* page is at 4-6M */ +# define PEXT_6M 3 /* page is at 6-8M */ +# define RB10_P2EXT 0x0c /* page 2 extension */ +# define RB10_P2EXT_SH 2 +# define RB10_P1EXT 0x30 /* page 1 extension */ +# define RB10_P1EXT_SH 4 +# define RB10_P0EXT 0xc0 /* page 0 extension */ +# define RB10_P0EXT_SH 6 + +#define REG_RB11 0x6f /* Miscellaneous */ +# define RB11_MASK 0xe6 /* 111R R11R */ +# define RB11_GA20 0x02 /* gate for A20 */ +# define RB11_RASTMO 0x04 /* enable RAS timeout counter */ +# define RB11_EMSLEN 0xe0 /* EMS memory chunk size */ +# define RB11_EMSLEN_SH 5 + +typedef struct { + int8_t enabled; /* 1=ENABLED */ + char pad; + uint16_t page; /* selected page in EMS block */ + uint32_t start; /* start of EMS in RAM */ + uint8_t *addr; /* start addr in EMS RAM */ + mem_mapping_t mapping; /* mapping entry for page */ +} emspage_t; + +typedef struct { + uint8_t regs[128]; /* all the CS8221 registers */ + uint8_t indx; /* programmed index into registers */ + + char pad; + + uint16_t ems_base, /* configured base address */ + ems_oldbase; + uint32_t ems_frame, /* configured frame address */ + ems_oldframe; + uint16_t ems_size, /* EMS size in KB */ + ems_pages; /* EMS size in pages */ + emspage_t ems[EMS_MAXPAGE]; /* EMS page registers */ +} neat_t; + + +#ifdef ENABLE_NEAT_LOG +int neat_do_log = ENABLE_NEAT_LOG; + + +static void +neat_log(const char *fmt, ...) +{ + va_list ap; + + if (neat_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define neat_log(fmt, ...) +#endif + + +/* Read one byte from paged RAM. */ +static uint8_t +ems_readb(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + neat_t *dev = (neat_t *)map->dev; + uint8_t ret = 0xff; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Grab the data. */ + ret = *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)); + + return(ret); +} + +/* Read one word from paged RAM. */ +static uint16_t +ems_readw(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + neat_t *dev = (neat_t *)map->dev; + uint16_t ret = 0xffff; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Grab the data. */ + ret = *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)); + + return(ret); +} + +/* Write one byte to paged RAM. */ +static void +ems_writeb(uint32_t addr, uint8_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + neat_t *dev = (neat_t *)map->dev; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Write the data. */ + *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; +} + +/* Write one word to paged RAM. */ +static void +ems_writew(uint32_t addr, uint16_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + neat_t *dev = (neat_t *)map->dev; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Write the data. */ + *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; +} + +/* Re-calculate the active-page physical address. */ +static void +ems_recalc(neat_t *dev, emspage_t *ems) +{ + if (ems->page >= dev->ems_pages) { + /* That page does not exist. */ + ems->enabled = 0; + } + + /* Pre-calculate the page address in EMS RAM. */ + ems->addr = ram + ems->start + (ems->page * EMS_PGSIZE); + + if (ems->enabled) { + /* Update the EMS RAM address for this page. */ + mem_mapping_set_exec(&ems->mapping, ems->addr); + + /* Enable this page. */ + mem_mapping_enable(&ems->mapping); + +#if NEAT_DEBUG > 1 + neat_log("NEAT EMS: page %d set to %08lx, %sabled)\n", + ems->page, ems->addr-ram, ems->enabled?"en":"dis"); +#endif + } else { + /* Disable this page. */ + mem_mapping_disable(&ems->mapping); + } +} + +static void +ems_write(uint16_t port, uint8_t val, void *priv) +{ + neat_t *dev = (neat_t *)priv; + emspage_t *ems; + int vpage; + +#if NEAT_DEBUG > 1 + neat_log("NEAT: ems_write(%04x, %02x)\n", port, val); +#endif + + /* Get the viewport page number. */ + vpage = (port / EMS_PGSIZE); + ems = &dev->ems[vpage]; + + switch(port & 0x000f) { + case 0x0008: + case 0x0009: + ems->enabled = !!(val & 0x80); + ems->page &= 0x0180; /* clear lower bits */ + ems->page |= (val & 0x7f); /* add new bits */ + ems_recalc(dev, ems); + break; + } +} + +static uint8_t +ems_read(uint16_t port, void *priv) +{ + neat_t *dev = (neat_t *)priv; + uint8_t ret = 0xff; + int vpage; + + /* Get the viewport page number. */ + vpage = (port / EMS_PGSIZE); + + switch(port & 0x000f) { + case 0x0008: /* page number register */ + ret = dev->ems[vpage].page & 0x7f; + if (dev->ems[vpage].enabled) + ret |= 0x80; + break; + } + +#if NEAT_DEBUG > 1 + neat_log("NEAT: ems_read(%04x) = %02x\n", port, ret); +#endif + + return(ret); +} + +/* Initialize the EMS module. */ +static void +ems_init(neat_t *dev, int en) +{ + int i; + + /* Remove if needed. */ + if (! en) { + if (dev->ems_base > 0) for (i = 0; i < EMS_MAXPAGE; i++) { + /* Disable for now. */ + mem_mapping_disable(&dev->ems[i].mapping); + + /* Remove I/O handler. */ + io_removehandler(dev->ems_base + (i * EMS_PGSIZE), 2, + ems_read,NULL,NULL, ems_write,NULL,NULL, dev); + } + +#ifdef ENABLE_NEAT_LOG + neat_log("NEAT: EMS disabled\n"); +#endif + + return; + } + + /* Get configured I/O address. */ + i = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; + dev->ems_base = 0x0208 + (0x10 * i); + + /* Get configured frame address. */ + i = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH; + dev->ems_frame = 0xC0000 + (EMS_PGSIZE * i); + + /* + * For each supported page (we can have a maximum of 4), + * create, initialize and disable the mappings, and set + * up the I/O control handler. + */ + for (i = 0; i < EMS_MAXPAGE; i++) { + /* Create and initialize a page mapping. */ + mem_mapping_add(&dev->ems[i].mapping, + dev->ems_frame + (EMS_PGSIZE*i), EMS_PGSIZE, + ems_readb, ems_readw, NULL, + ems_writeb, ems_writew, NULL, + ram, MEM_MAPPING_EXTERNAL, + &dev->ems[i].mapping); + mem_mapping_set_dev(&dev->ems[i].mapping, dev); + + /* Disable for now. */ + mem_mapping_disable(&dev->ems[i].mapping); + + /* Set up an I/O port handler. */ + io_sethandler(dev->ems_base + (i * EMS_PGSIZE), 2, + ems_read,NULL,NULL, ems_write,NULL,NULL, dev); + + /* + * TODO: update the 'high_mem' mapping to reflect that we now + * have NN MB less extended memory available.. + */ + } + + neat_log("NEAT: EMS enabled, I/O=%04xH, Frame=%05XH\n", + dev->ems_base, dev->ems_frame); +} + +static void +neat_write(uint16_t port, uint8_t val, void *priv) +{ + neat_t *dev = (neat_t *)priv; + uint8_t xval, *reg; + int i; + +#if NEAT_DEBUG > 2 + neat_log("NEAT: write(%04x, %02x)\n", port, val); +#endif + + switch (port) { + case 0x22: + dev->indx = val; + break; + + case 0x23: + reg = &dev->regs[dev->indx]; + xval = *reg ^ val; + switch (dev->indx) { + case REG_RA0: + val &= RA0_MASK; + *reg = (*reg & ~RA0_MASK) | val | \ + (RA0_REV_ID << RA0_REV_SH); +#if NEAT_DEBUG > 1 + neat_log("NEAT: RA0=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RA1: + val &= RA1_MASK; + *reg = (*reg & ~RA1_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RA1=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RA2: + val &= RA2_MASK; + *reg = (*reg & ~RA2_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RA2=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RB0: + val &= RB0_MASK; + *reg = (*reg & ~RB0_MASK) | val | \ + (RB0_REV_ID << RB0_REV_SH); +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB0=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RB1: + val &= RB1_MASK; + *reg = (*reg & ~RB1_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB1=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RB2: + val &= RB2_MASK; + *reg = (*reg & ~RB2_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB2=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RB3: + val &= RB3_MASK; + *reg = (*reg & ~RB3_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB3=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RB4: + val &= RB4_MASK; + *reg = (*reg & ~RB4_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB4=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RB5: + val &= RB5_MASK; + *reg = (*reg & ~RB5_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB5=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RB6: + val &= RB6_MASK; + *reg = (*reg & ~RB6_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB6=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RB7: + val &= RB7_MASK; + *reg = (*reg & ~RB7_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB7=%02x(%02x)\n", val, *reg); +#endif + if (val & RB7_EMSEN) + ems_init(dev, 1); + else if (xval & RB7_EMSEN) + ems_init(dev, 0); + + if (xval & RB7_UMAREL) { + if (val & RB7_UMAREL) + mem_remap_top(384); + else + mem_remap_top(0); + } + break; + + case REG_RB8: + val &= RB8_MASK; + *reg = (*reg & ~RB8_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB8=%02x(%02x)\n", val, *reg); +#endif + break; + + case REG_RB9: + val &= RB9_MASK; + *reg = (*reg & ~RB9_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB9=%02x(%02x)\n", val, *reg); +#endif + if (dev->regs[REG_RB7] & RB7_EMSEN) { + ems_init(dev, 0); + ems_init(dev, 1); + } + break; + + case REG_RB10: + val &= RB10_MASK; + *reg = (*reg & ~RB10_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB10=%02x(%02x)\n", val, *reg); +#endif + + dev->ems[3].start = ((val & RB10_P3EXT) >> RB10_P3EXT_SH) << 21; + dev->ems[2].start = ((val & RB10_P2EXT) >> RB10_P2EXT_SH) << 21; + dev->ems[1].start = ((val & RB10_P1EXT) >> RB10_P1EXT_SH) << 21; + dev->ems[0].start = ((val & RB10_P0EXT) >> RB10_P0EXT_SH) << 21; + for (i = 0; i < EMS_MAXPAGE; i++) + ems_recalc(dev, &dev->ems[i]); + break; + + case REG_RB11: + val &= RB11_MASK; + *reg = (*reg & ~RB11_MASK) | val; +#if NEAT_DEBUG > 1 + neat_log("NEAT: RB11=%02x(%02x)\n", val, *reg); +#endif + i = (val & RB11_EMSLEN) >> RB11_EMSLEN_SH; + switch(i) { + case 0: /* "less than 2MB" */ + dev->ems_size = 512; + break; + + case 1: /* 1 MB */ + case 2: /* 2 MB */ + case 3: /* 3 MB */ + case 4: /* 4 MB */ + case 5: /* 5 MB */ + case 6: /* 6 MB */ + case 7: /* 7 MB */ + dev->ems_size = i << 10; + break; + } + dev->ems_pages = (dev->ems_size << 10) / EMS_PGSIZE; + if (dev->regs[REG_RB7] & RB7_EMSEN) { + neat_log("NEAT: EMS %iKB (%i pages)\n", + dev->ems_size, dev->ems_pages); + } + break; + + default: + neat_log("NEAT: inv write to reg %02x (%02x)\n", + dev->indx, val); + break; + } + break; + } +} + + +static uint8_t +neat_read(uint16_t port, void *priv) +{ + neat_t *dev = (neat_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x22: + ret = dev->indx; + break; + + case 0x23: + ret = dev->regs[dev->indx]; + break; + + default: + break; + } + +#if NEAT_DEBUG > 2 + neat_log("NEAT: read(%04x) = %02x\n", port, ret); +#endif + + return(ret); +} + + +static void +neat_close(void *priv) +{ + neat_t *dev = (neat_t *) priv; + + free(dev); +} + + +static void * +neat_init(const device_t *info) +{ + neat_t *dev; + int i; + + /* Create an instance. */ + dev = (neat_t *)malloc(sizeof(neat_t)); + memset(dev, 0x00, sizeof(neat_t)); + + /* Initialize some of the registers to specific defaults. */ + for (i = REG_RA0; i <= REG_RB11; i++) { + dev->indx = i; + neat_write(0x0023, 0x00, dev); + } + + /* + * Based on the value of mem_size, we have to set up + * a proper DRAM configuration (so that EMS works.) + * + * TODO: We might also want to set 'valid' waitstate + * bits, based on our cpu speed. + */ + i = 0; + switch(mem_size) { + case 512: /* 512KB */ + /* 256K, 0, 0, 0 */ + dev->regs[REG_RB6] &= ~RB6_BANKS; /* one bank */ + dev->regs[REG_RB6] |= (RTYPE_256K<regs[REG_RB8] &= ~RB8_BANKS; /* one bank */ + dev->regs[REG_RB8] |= (RTYPE_NONE<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_MIXED<regs[REG_RB8] &= ~RB8_BANKS; /* one bank */ + dev->regs[REG_RB8] |= (RTYPE_NONE<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_256K<regs[REG_RB8] &= ~RB8_BANKS; /* one bank */ + dev->regs[REG_RB8] |= (RTYPE_NONE<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_256K<regs[REG_RB8] &= ~RB8_BANKS; /* one bank */ + dev->regs[REG_RB8] |= (RTYPE_256K<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_MIXED<regs[REG_RB8] |= RB8_BANKS; /* two banks */ + dev->regs[REG_RB8] |= (RTYPE_256K<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_256K<regs[REG_RB8] |= RB8_BANKS; /* two banks */ + dev->regs[REG_RB8] |= (RTYPE_256K<regs[REG_RB8] |= RB8_4WAY; /* 4way intl */ + i = 11; +#else + /* 1M, 0, 0, 0 */ + dev->regs[REG_RB6] &= ~RB6_BANKS; /* one bank */ + dev->regs[REG_RB6] |= (RTYPE_1M<regs[REG_RB8] &= ~RB8_BANKS; /* one bank */ + dev->regs[REG_RB8] |= (RTYPE_NONE<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_256K<regs[REG_RB8] &= ~RB8_BANKS; /* one bank */ + dev->regs[REG_RB8] |= (RTYPE_1M<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_1M<regs[REG_RB8] &= ~RB8_BANKS; /* one bank */ + dev->regs[REG_RB8] |= (RTYPE_NONE<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_MIXED<regs[REG_RB8] |= RB8_BANKS; /* two banks */ + dev->regs[REG_RB8] |= (RTYPE_1M<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_256K<regs[REG_RB8] |= RB8_BANKS; /* two banks */ + dev->regs[REG_RB8] |= (RTYPE_1M<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_1M<regs[REG_RB8] &= ~RB8_BANKS; /* one bank */ + dev->regs[REG_RB8] |= (RTYPE_1M<regs[REG_RB6] |= RB6_BANKS; /* two banks */ + dev->regs[REG_RB6] |= (RTYPE_1M<regs[REG_RB8] |= RB8_BANKS; /* two banks */ + dev->regs[REG_RB8] |= (RTYPE_1M<regs[REG_RB8] |= RB8_4WAY; /* 4way intl */ + i = 14; + break; + + default: + neat_log("NEAT: **INVALID DRAM SIZE %iKB !**\n", mem_size); + } + if (i > 0) { + neat_log("NEAT: using DRAM mode #%i (mem=%iKB)\n", i, mem_size); + } + + /* Set up an I/O handler for the chipset. */ + io_sethandler(0x0022, 2, + neat_read,NULL,NULL, neat_write,NULL,NULL, dev); + + return dev; +} + + +const device_t neat_device = { + "C&T CS8121 (NEAT)", + 0, + 0, + neat_init, neat_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/machine/m_at_opti495.c b/src/chipset/opti495.c similarity index 80% rename from src/machine/m_at_opti495.c rename to src/chipset/opti495.c index d38e47066..b6ffb0ff8 100644 --- a/src/machine/m_at_opti495.c +++ b/src/chipset/opti495.c @@ -254,94 +254,116 @@ SeeAlso: #P0178,#P0187 #include #include #include +#include #include #include #define HAVE_STDARG_H #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../io.h" #include "../device.h" #include "../keyboard.h" #include "../mem.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" -#include "machine.h" +#include "chipset.h" -static uint8_t optiregs[0x10]; -static int optireg; - - -static void opti495_write(uint16_t addr, uint8_t val, void *p) +typedef struct { - switch (addr) - { - case 0x22: - optireg=val; - break; - case 0x24: - if (optireg>=0x20 && optireg<=0x2C) - { - optiregs[optireg-0x20]=val; - if (optireg == 0x21) - { - cpu_cache_ext_enabled = val & 0x10; - cpu_update_waitstates(); - } - if (optireg == 0x22) - { - shadowbios = !(val & 0x80); - shadowbios_write = val & 0x80; - if (shadowbios) - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); - else - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - } - } - break; - } + uint8_t cur_reg, + regs[16], + scratch[2]; +} opti495_t; + + +static void +opti495_write(uint16_t addr, uint8_t val, void *priv) +{ + opti495_t *dev = (opti495_t *) priv; + + switch (addr) { + case 0x22: + dev->cur_reg = val; + break; + case 0x24: + if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C)) { + dev->regs[dev->cur_reg - 0x20] = val; + if (dev->cur_reg == 0x21) { + cpu_cache_ext_enabled = val & 0x10; + cpu_update_waitstates(); + } + if (dev->cur_reg == 0x22) { + if (!(val & 0x80)) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + } + } + break; + case 0xe1: + case 0xe2: + dev->scratch[addr - 0xe1] = val; + break; + } } -static uint8_t opti495_read(uint16_t addr, void *p) +static uint8_t +opti495_read(uint16_t addr, void *priv) { - switch (addr) - { - case 0x24: - if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20]; - break; - } - return 0xFF; + uint8_t ret = 0xff; + opti495_t *dev = (opti495_t *) priv; + + switch (addr) { + case 0x24: + if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C)) + ret = dev->regs[dev->cur_reg - 0x20]; + break; + case 0xe1: + case 0xe2: + ret = dev->scratch[addr - 0xe1]; + break; + } + + return ret; } -static void opti495_init(void) +static void +opti495_close(void *priv) { - io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); - io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); - optiregs[0x22-0x20] = 0x80; + opti495_t *dev = (opti495_t *) priv; + + free(dev); } -void -machine_at_opti495_init(const machine_t *model) +static void * +opti495_init(const device_t *info) { - machine_at_common_ide_init(model); + opti495_t *dev = (opti495_t *) malloc(sizeof(opti495_t)); + memset(dev, 0, sizeof(opti495_t)); - device_add(&keyboard_at_device); - device_add(&fdc_at_device); + io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); + io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); - opti495_init(); + dev->scratch[0] = dev->scratch[1] = 0xff; + + io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); + + dev->regs[0x22 - 0x20] = 0x80; + + return dev; } -void -machine_at_opti495_ami_init(const machine_t *model) -{ - machine_at_common_ide_init(model); - - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); - - opti495_init(); -} +const device_t opti495_device = { + "OPTi 82C495", + 0, + 0, + opti495_init, opti495_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/scat.c b/src/chipset/scat.c new file mode 100644 index 000000000..0c3223486 --- /dev/null +++ b/src/chipset/scat.c @@ -0,0 +1,1597 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Chips&Technology's SCAT (82C235) chipset. + * + * Re-worked version based on the 82C235 datasheet and errata. + * + * Version: @(#)scat.c 1.0.1 2019/10/19 + * + * Authors: Original by GreatPsycho for PCem. + * Fred N. van Kempen, + * + * Copyright 2017-2019 GreatPsycho. + * Copyright 2017-2019 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#ifdef USE_NEW_DYNAREC +#include "../cpu_new/cpu.h" +#include "../cpu_new/x86.h" +#else +#include "../cpu/cpu.h" +#include "../cpu/x86.h" +#endif +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../keyboard.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "../port_92.h" +#include "../rom.h" +#include "chipset.h" + + +#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 +#define SCAT_VERSION 0x40 +#define SCAT_CLOCK_CONTROL 0x41 +#define SCAT_PERIPHERAL_CONTROL 0x44 +#define SCAT_MISCELLANEOUS_STATUS 0x45 +#define SCAT_POWER_MANAGEMENT 0x46 +#define SCAT_ROM_ENABLE 0x48 +#define SCAT_RAM_WRITE_PROTECT 0x49 +#define SCAT_SHADOW_RAM_ENABLE_1 0x4A +#define SCAT_SHADOW_RAM_ENABLE_2 0x4B +#define SCAT_SHADOW_RAM_ENABLE_3 0x4C +#define SCAT_DRAM_CONFIGURATION 0x4D +#define SCAT_EXTENDED_BOUNDARY 0x4E +#define SCAT_EMS_CONTROL 0x4F + +#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 { + uint8_t valid, pad; + + uint8_t regs_2x8; + uint8_t regs_2x9; + + struct scat_t * scat; +} ems_page_t; + +typedef struct scat_t { + int type; + + int indx; + uint8_t regs[256]; + uint8_t reg_2xA; + + uint32_t xms_bound; + + int external_is_RAS; + + ems_page_t null_page, page[32]; + + mem_mapping_t low_mapping[32]; + mem_mapping_t high_mapping[16]; + mem_mapping_t remap_mapping[6]; + mem_mapping_t efff_mapping[44]; + mem_mapping_t ems_mapping[32]; +} scat_t; + + +static const uint8_t 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 const uint8_t max_map_sx[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 const uint8_t 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 +}; + + +static uint8_t scat_in(uint16_t port, void *priv); +static void scat_out(uint16_t port, uint8_t val, void *priv); + + +static void +shadow_state_update(scat_t *dev) +{ + int i, val; + + uint32_t base, bit, romcs, wp, shflags = 0; + + for (i = 0; i < 24; i++) { + val = (dev->regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1; + + base = 0xa0000 + (i << 14); + bit = (base - 0xc0000) >> 15; + romcs = 0; + wp = 0; + + if (base >= 0xc0000) { + romcs = dev->regs[SCAT_ROM_ENABLE] & (1 << bit); + + wp = dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << bit); + } + + shflags = val ? MEM_READ_INTERNAL : (romcs ? MEM_READ_ROMCS : MEM_READ_EXTERNAL); + + if (wp) + shflags |= MEM_WRITE_DISABLED; + else + shflags |= (val ? MEM_WRITE_INTERNAL : (romcs ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL)); + + mem_set_mem_state(base, 0x4000, shflags); + } + + flushmmucache(); +} + + +static void +set_xms_bound(scat_t *dev, uint8_t val) +{ + uint32_t xms_max = ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && ((val & 0x10) != 0)) || (dev->regs[SCAT_VERSION] >= 4) ? 0xfe0000 : 0xfc0000; + int i; + + switch (val & 0x0f) { + case 1: + dev->xms_bound = 0x100000; + break; + + case 2: + dev->xms_bound = 0x140000; + break; + + case 3: + dev->xms_bound = 0x180000; + break; + + case 4: + dev->xms_bound = 0x200000; + break; + + case 5: + dev->xms_bound = 0x300000; + break; + + case 6: + dev->xms_bound = 0x400000; + break; + + case 7: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x600000 : 0x500000; + break; + + case 8: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x800000 : 0x700000; + break; + + case 9: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xa00000 : 0x800000; + break; + + case 10: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xc00000 : 0x900000; + break; + + case 11: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xe00000 : 0xa00000; + break; + + case 12: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xb00000; + break; + + case 13: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xc00000; + break; + + case 14: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xd00000; + break; + + case 15: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xf00000; + break; + + default: + dev->xms_bound = xms_max; + break; + } + + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && (val & 0x40) == 0 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3) || + (((dev->regs[SCAT_VERSION] & 0xf0) != 0) && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3)) { + if ((val & 0x0f) == 0 || dev->xms_bound > 0x160000) + dev->xms_bound = 0x160000; + + if (dev->xms_bound > 0x100000) + mem_set_mem_state(0x100000, dev->xms_bound - 0x100000, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + if (dev->xms_bound < 0x160000) + mem_set_mem_state(dev->xms_bound, 0x160000 - dev->xms_bound, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } else { + if (dev->xms_bound > xms_max) + dev->xms_bound = xms_max; + + if (dev->xms_bound > 0x100000) + mem_set_mem_state(0x100000, dev->xms_bound - 0x100000, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + if (dev->xms_bound < ((uint32_t)mem_size << 10)) + mem_set_mem_state(dev->xms_bound, (mem_size << 10) - dev->xms_bound, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + mem_mapping_set_addr(&dev->low_mapping[31], 0xf80000, + ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && ((val & 0x10) != 0)) || + (dev->regs[SCAT_VERSION] >= 4) ? 0x60000 : 0x40000); + if (dev->regs[SCAT_VERSION] & 0xf0) { + for (i = 0; i < 8; i++) { + if (val & 0x10) + mem_mapping_disable(&dev->high_mapping[i]); + else + mem_mapping_enable(&dev->high_mapping[i]); + } + } +} + + +static uint32_t +get_addr(scat_t *dev, uint32_t addr, ems_page_t *p) +{ +#if 1 + int nbanks_2048k, nbanks_512k; + uint32_t addr2; + int nbank; +#else + uint32_t nbanks_2048k, nbanks_512k, addr2, nbank; +#endif + + if (p && p->valid && (dev->regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) + addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; + + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + switch((dev->regs[SCAT_EXTENDED_BOUNDARY] & ((dev->regs[SCAT_VERSION] & 0x0f) > 3 ? 0x40 : 0)) | (dev->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 >> (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) < 8 && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) ? 19 : 21); + break; + } + + nbank &= (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + + if ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3 && + nbank == 2 && (addr & 0x7ffff) < 0x60000 && mem_size > 640) { + nbank = 1; + addr ^= 0x70000; + } + + if (dev->external_is_RAS && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { + if (nbank == 3) + nbank = 7; + else + return 0xffffffff; + } else if (!dev->external_is_RAS && dev->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 ((dev->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 { + if (mem_size <= ((dev->regs[SCAT_VERSION] & 0x0f) > 3 ? 2048 : 4096) && (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) < 8) || dev->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 { + switch(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) { + case 0x02: + case 0x04: + nbank = addr >> 19; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else + addr2 = addr >> 10; + break; + + case 0x03: + nbank = addr >> 19; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if ((nbank & (dev->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 0x05: + nbank = addr >> 19; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) { + nbank = (addr >> 10) & 3; + addr2 = addr >> 12; + } else + addr2 = addr >> 10; + break; + + case 0x06: + 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 0x07: + 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 0x08: + 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 0x09: + 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 & (dev->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 & (dev->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 (dev->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 (dev->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 (dev->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 ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 6) { + nbank = addr >> 19; + addr2 = (addr >> 10) & 0x1ff; + } else if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 0x17) { + nbank = addr >> 21; + addr2 = (addr >> 11) & 0x3ff; + } else { + nbank = addr >> 23; + addr2 = (addr >> 12) & 0x7ff; + } + break; + } + + nbank &= (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) > 0x16 && nbank == 3) + return 0xffffffff; + + if (dev->external_is_RAS && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { + if (nbank == 3) + nbank = 7; + else + return 0xffffffff; + } else if (!dev->external_is_RAS && dev->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 ((dev->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 (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) >= 8 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) <= 0x0a) || ((dev->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 (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) >= 8 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) <= 0x0a) || ((dev->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 (dev->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 (dev->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 (dev->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 (dev->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 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 6)) { + addr &= 0x3ff; + addr2 &= 0x1ff; + addr |= (addr2 << 10) | (nbank << 19); + } else if (mem_size < 8192 || (dev->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; +} + + +static void +set_global_EMS_state(scat_t *dev, int state) +{ + uint32_t base_addr, virt_addr; + int i, conf; + + for (i = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0 : 24; i < 32; i++) { + base_addr = (i + 16) << 14; + + if (i >= 24) + base_addr += 0x30000; + if (state && (dev->page[i].regs_2x9 & 0x80)) { + virt_addr = get_addr(dev, base_addr, &dev->page[i]); + if (i < 24) + mem_mapping_disable(&dev->efff_mapping[i]); + else + mem_mapping_disable(&dev->efff_mapping[i + 12]); + mem_mapping_enable(&dev->ems_mapping[i]); + + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[i], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[i], NULL); + } else { + mem_mapping_set_exec(&dev->ems_mapping[i], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[i]); + + conf = (dev->regs[SCAT_VERSION] & 0xf0) ? (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) + : (dev->regs[SCAT_DRAM_CONFIGURATION] & 0xf) | + ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2); + if (i < 24) { + if (conf > 1 || (conf == 1 && i < 16)) + mem_mapping_enable(&dev->efff_mapping[i]); + else + mem_mapping_disable(&dev->efff_mapping[i]); + } else if (conf > 3 || ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && conf == 2)) + mem_mapping_enable(&dev->efff_mapping[i + 12]); + else + mem_mapping_disable(&dev->efff_mapping[i + 12]); + } + } + + flushmmucache(); +} + + +static void +memmap_state_update(scat_t *dev) +{ + uint32_t addr; + int i; + + for (i = (((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0 : 16); i < 44; i++) { + addr = get_addr(dev, 0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&dev->efff_mapping[i], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + } + + addr = get_addr(dev, 0, NULL); + mem_mapping_set_exec(&dev->low_mapping[0], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + + addr = get_addr(dev, 0xf0000, NULL); + mem_mapping_set_exec(&dev->low_mapping[1], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + + for (i = 2; i < 32; i++) { + addr = get_addr(dev, i << 19, NULL); + mem_mapping_set_exec(&dev->low_mapping[i], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + } + + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + for (i = 0; i < max_map[(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) | + ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2)]; i++) + mem_mapping_enable(&dev->low_mapping[i]); + + for (; i < 32; i++) + mem_mapping_disable(&dev->low_mapping[i]); + + for (i = 24; i < 36; i++) { + if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) | (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40)) < 4) + mem_mapping_disable(&dev->efff_mapping[i]); + else + mem_mapping_enable(&dev->efff_mapping[i]); + } + } else { + for (i = 0; i < max_map_sx[dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f]; i++) + mem_mapping_enable(&dev->low_mapping[i]); + + for (; i < 32; i++) + mem_mapping_disable(&dev->low_mapping[i]); + + for(i = 24; i < 36; i++) { + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 2 || (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3) + mem_mapping_disable(&dev->efff_mapping[i]); + else + mem_mapping_enable(&dev->efff_mapping[i]); + } + } + + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && + (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) || ((dev->regs[SCAT_VERSION] & 0xf0) != 0)) { + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3) || + (((dev->regs[SCAT_VERSION] & 0xf0) != 0) && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3)) { + mem_mapping_disable(&dev->low_mapping[2]); + + for (i = 0; i < 6; i++) { + addr = get_addr(dev, 0x100000 + (i << 16), NULL); + mem_mapping_set_exec(&dev->remap_mapping[i], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + mem_mapping_enable(&dev->remap_mapping[i]); + } + } else { + for (i = 0; i < 6; i++) + mem_mapping_disable(&dev->remap_mapping[i]); + + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) > 4) || + (((dev->regs[SCAT_VERSION] & 0xf0) != 0) && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) > 3)) + mem_mapping_enable(&dev->low_mapping[2]); + } + } else { + for (i = 0; i < 6; i++) + mem_mapping_disable(&dev->remap_mapping[i]); + + mem_mapping_enable(&dev->low_mapping[2]); + } + + set_global_EMS_state(dev, dev->regs[SCAT_EMS_CONTROL] & 0x80); + + flushmmucache_cr3(); +} + + +static void +scat_out(uint16_t port, uint8_t val, void *priv) +{ + scat_t *dev = (scat_t *)priv; + uint8_t reg_valid = 0, + shadow_update = 0, + map_update = 0, + indx; + uint32_t base_addr, virt_addr; + + switch (port) { + case 0x22: + dev->indx = val; + break; + + case 0x23: + switch (dev->indx) { + case SCAT_DMA_WAIT_STATE_CONTROL: + case SCAT_CLOCK_CONTROL: + case SCAT_PERIPHERAL_CONTROL: + reg_valid = 1; + break; + + case SCAT_EMS_CONTROL: + if (val & 0x40) { + if (val & 1) { + io_sethandler(0x0218, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + io_removehandler(0x0208, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + } else { + io_sethandler(0x0208, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + io_removehandler(0x0218, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + } + } else { + io_removehandler(0x0208, 0x0003, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + io_removehandler(0x0218, 0x0003, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + } + set_global_EMS_state(dev, val & 0x80); + reg_valid = 1; + break; + + case SCAT_POWER_MANAGEMENT: + /* TODO - Only use AUX parity disable bit for this version. + Other bits should be implemented later. */ + val &= (dev->regs[SCAT_VERSION] & 0xf0) == 0 ? 0x40 : 0x60; + reg_valid = 1; + break; + + case SCAT_DRAM_CONFIGURATION: + map_update = 1; + + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + cpu_waitstates = (val & 0x70) == 0 ? 1 : 2; + cpu_update_waitstates(); + } + + reg_valid = 1; + break; + + case SCAT_EXTENDED_BOUNDARY: + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + if (dev->regs[SCAT_VERSION] < 4) { + val &= 0xbf; + set_xms_bound(dev, val & 0x0f); + } else { + val = (val & 0x7f) | 0x80; + set_xms_bound(dev, val & 0x4f); + } + } else + set_xms_bound(dev, val & 0x1f); + + mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if ((val ^ dev->regs[SCAT_EXTENDED_BOUNDARY]) & 0xc0) + map_update = 1; + reg_valid = 1; + break; + + case SCAT_ROM_ENABLE: + case SCAT_RAM_WRITE_PROTECT: + case SCAT_SHADOW_RAM_ENABLE_1: + case SCAT_SHADOW_RAM_ENABLE_2: + case SCAT_SHADOW_RAM_ENABLE_3: + reg_valid = 1; + shadow_update = 1; + break; + + case SCATSX_LAPTOP_FEATURES: + if ((dev->regs[SCAT_VERSION] & 0xf0) != 0) { + val = (val & ~8) | (dev->regs[SCATSX_LAPTOP_FEATURES] & 8); + 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 ((dev->regs[SCAT_VERSION] & 0xf0) != 0) + reg_valid = 1; + break; + + default: + break; + } + + if (reg_valid) + dev->regs[dev->indx] = val; + + if (shadow_update) + shadow_state_update(dev); + + if (map_update) + memmap_state_update(dev); + break; + + case 0x208: + case 0x218: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + dev->page[indx].regs_2x8 = val; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x30000; + + if ((dev->regs[SCAT_EMS_CONTROL] & 0x80) && (dev->page[indx].regs_2x9 & 0x80)) { + virt_addr = get_addr(dev, base_addr, &dev->page[indx]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[indx], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[indx], NULL); + flushmmucache(); + } + } + break; + + case 0x209: + case 0x219: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + dev->page[indx].regs_2x9 = val; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x30000; + + if (dev->regs[SCAT_EMS_CONTROL] & 0x80) { + if (val & 0x80) { + virt_addr = get_addr(dev, base_addr, &dev->page[indx]); + if (indx < 24) + mem_mapping_disable(&dev->efff_mapping[indx]); + else + mem_mapping_disable(&dev->efff_mapping[indx + 12]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[indx], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[indx], NULL); + mem_mapping_enable(&dev->ems_mapping[indx]); + } else { + mem_mapping_set_exec(&dev->ems_mapping[indx], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[indx]); + if (indx < 24) + mem_mapping_enable(&dev->efff_mapping[indx]); + else + mem_mapping_enable(&dev->efff_mapping[indx + 12]); + } + + flushmmucache(); + } + + if (dev->reg_2xA & 0x80) + dev->reg_2xA = (dev->reg_2xA & 0xe0) | ((dev->reg_2xA + 1) & (((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x1f : 3)); + } + break; + + case 0x20a: + case 0x21a: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) + dev->reg_2xA = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? val : val & 0xc3; + break; + } +} + + +static uint8_t +scat_in(uint16_t port, void *priv) +{ + scat_t *dev = (scat_t *)priv; + uint8_t ret = 0xff, indx; + + switch (port) { + case 0x23: + switch (dev->indx) { + case SCAT_MISCELLANEOUS_STATUS: + ret = (dev->regs[dev->indx] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5); + break; + + case SCAT_DRAM_CONFIGURATION: + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + ret = (dev->regs[dev->indx] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10); + else + ret = dev->regs[dev->indx]; + break; + + case SCAT_EXTENDED_BOUNDARY: + ret = dev->regs[dev->indx]; + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + if ((dev->regs[SCAT_VERSION] & 0x0f) >= 4) + ret |= 0x80; + else + ret &= 0xaf; + } + break; + + default: + ret = dev->regs[dev->indx]; + break; + } + break; + + case 0x208: + case 0x218: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + ret = dev->page[indx].regs_2x8; + } + break; + + case 0x209: + case 0x219: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + ret = dev->page[indx].regs_2x9; + } + break; + + case 0x20a: + case 0x21a: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) + ret = dev->reg_2xA; + break; + } + + return ret; +} + + +static uint8_t +mem_read_scatb(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint8_t val = 0xff; + + addr = get_addr(dev, addr, page); + if (addr < ((uint32_t)mem_size << 10)) + val = ram[addr]; + + return val; +} + + +static uint16_t +mem_read_scatw(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint16_t val = 0xffff; + + addr = get_addr(dev, addr, page); + if (addr < ((uint32_t)mem_size << 10)) + val = *(uint16_t *)&ram[addr]; + + return val; +} + + +static uint32_t +mem_read_scatl(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint32_t val = 0xffffffff; + + addr = get_addr(dev, addr, page); + if (addr < ((uint32_t)mem_size << 10)) + val = *(uint32_t *)&ram[addr]; + + return val; +} + + +static void +mem_write_scatb(uint32_t addr, uint8_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint32_t oldaddr = addr, chkaddr; + + addr = get_addr(dev, addr, page); + chkaddr = page ? addr : oldaddr; + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + } + + if (addr < ((uint32_t)mem_size << 10)) + ram[addr] = val; +} + + +static void +mem_write_scatw(uint32_t addr, uint16_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint32_t oldaddr = addr, chkaddr; + + addr = get_addr(dev, addr, page); + chkaddr = page ? addr : oldaddr; + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + } + + if (addr < ((uint32_t)mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + + +static void +mem_write_scatl(uint32_t addr, uint32_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint32_t oldaddr = addr, chkaddr; + + addr = get_addr(dev, addr, page); + chkaddr = page ? addr : oldaddr; + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + } + if (addr < ((uint32_t)mem_size << 10)) + *(uint32_t *)&ram[addr] = val; +} + + +static void +scat_close(void *priv) +{ + scat_t *dev = (scat_t *)priv; + + free(dev); +} + + +static void * +scat_init(const device_t *info) +{ + scat_t *dev; + uint32_t i, k; + int sx; + + dev = (scat_t *)malloc(sizeof(scat_t)); + memset(dev, 0x00, sizeof(scat_t)); + dev->type = info->local; + + sx = (dev->type == 32) ? 1 : 0; + + for (i = 0; i < sizeof(dev->regs); i++) + dev->regs[i] = 0xff; + + if (sx) { + dev->regs[SCAT_VERSION] = 0x13; + dev->regs[SCAT_CLOCK_CONTROL] = 6; + dev->regs[SCAT_PERIPHERAL_CONTROL] = 0; + dev->regs[SCAT_DRAM_CONFIGURATION] = 1; + dev->regs[SCATSX_LAPTOP_FEATURES] = 0; + dev->regs[SCATSX_FAST_VIDEO_CONTROL] = 0; + dev->regs[SCATSX_FAST_VIDEORAM_ENABLE] = 0; + dev->regs[SCATSX_HIGH_PERFORMANCE_REFRESH] = 8; + dev->regs[SCATSX_CAS_TIMING_FOR_DMA] = 3; + } else { + switch(dev->type) { + case 4: + dev->regs[SCAT_VERSION] = 4; + break; + + default: + dev->regs[SCAT_VERSION] = 1; + break; + } + dev->regs[SCAT_CLOCK_CONTROL] = 2; + dev->regs[SCAT_PERIPHERAL_CONTROL] = 0x80; + dev->regs[SCAT_DRAM_CONFIGURATION] = cpu_waitstates == 1 ? 2 : 0x12; + } + dev->regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + dev->regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; + dev->regs[SCAT_ROM_ENABLE] = 0xc0; + dev->regs[SCAT_RAM_WRITE_PROTECT] = 0; + dev->regs[SCAT_POWER_MANAGEMENT] = 0; + dev->regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; + dev->regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; + dev->regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; + dev->regs[SCAT_EXTENDED_BOUNDARY] = 0; + dev->regs[SCAT_EMS_CONTROL] = 0; + + /* Disable all system mappings, we will override them. */ + mem_mapping_disable(&ram_low_mapping); + if (! sx) + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); +#if 0 + mem_mapping_disable(&bios_mapping); +#endif + + k = (sx) ? 0x80000 : 0x40000; + + dev->null_page.valid = 0; + dev->null_page.regs_2x8 = 0xff; + dev->null_page.regs_2x9 = 0xff; + dev->null_page.scat = dev; + + mem_mapping_add(&dev->low_mapping[0], 0, k, + mem_read_scatb, mem_read_scatw, mem_read_scatl, + mem_write_scatb, mem_write_scatw, mem_write_scatl, + ram, MEM_MAPPING_INTERNAL, &dev->null_page); + + mem_mapping_add(&dev->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, &dev->null_page); + + for (i = 2; i < 32; i++) { + mem_mapping_add(&dev->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, &dev->null_page); + } + + if (sx) { + i = 16; + k = 0x40000; + } else { + i = 0; + k = (dev->regs[SCAT_VERSION] < 4) ? 0x40000 : 0x60000; + } + mem_mapping_set_addr(&dev->low_mapping[31], 0xf80000, k); + + for (; i < 44; i++) { + mem_mapping_add(&dev->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, &dev->null_page); + + if (sx) + mem_mapping_enable(&dev->efff_mapping[i]); + } + + if (sx) { + for (i = 24; i < 32; i++) { + dev->page[i].valid = 1; + dev->page[i].regs_2x8 = 0xff; + dev->page[i].regs_2x9 = 0x03; + dev->page[i].scat = dev; + mem_mapping_add(&dev->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, &dev->page[i]); + mem_mapping_disable(&dev->ems_mapping[i]); + } + + for (i = 0; i < 16; i++) { + mem_mapping_add(&dev->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(&dev->high_mapping[i]); + } + } else { + for (i = 0; i < 32; i++) { + dev->page[i].valid = 1; + dev->page[i].regs_2x8 = 0xff; + dev->page[i].regs_2x9 = 0x03; + dev->page[i].scat = dev; + mem_mapping_add(&dev->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, &dev->page[i]); + } + + for (i = (dev->regs[SCAT_VERSION] < 4 ? 0 : 8); i < 16; i++) { + mem_mapping_add(&dev->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(&dev->high_mapping[i]); + } + } + + for (i = 0; i < 6; i++) { + mem_mapping_add(&dev->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_addr(dev, 0x100000 + (i << 16), NULL) : NULL, + MEM_MAPPING_INTERNAL, &dev->null_page); + } + + if (sx) { + dev->external_is_RAS = scatsx_external_is_RAS[mem_size >> 9]; + } else { + dev->external_is_RAS = (dev->regs[SCAT_VERSION] > 3) || (((mem_size & ~2047) >> 11) + ((mem_size & 1536) >> 9) + ((mem_size & 511) >> 7)) > 4; + } + + set_xms_bound(dev, 0); + memmap_state_update(dev); + shadow_state_update(dev); + + io_sethandler(0x0022, 2, + scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + + device_add(&port_92_device); + + return(dev); +} + + +const device_t scat_device = { + "C&T SCAT (v1)", + 0, + 0, + scat_init, scat_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t scat_4_device = { + "C&T SCAT (v4)", + 0, + 4, + scat_init, scat_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t scat_sx_device = { + "C&T SCATsx", + 0, + 32, + scat_init, scat_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/sis_85c471.c b/src/chipset/sis_85c471.c new file mode 100644 index 000000000..934e84c55 --- /dev/null +++ b/src/chipset/sis_85c471.c @@ -0,0 +1,293 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the SiS 85c471 chip. + * + * SiS sis85c471 Super I/O Chip + * Used by DTK PKM-0038S E-2 + * + * Version: @(#)sis_85c471.c 1.0.2 2019/10/21 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../io.h" +#include "../lpt.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../disk/hdc_ide.h" +#include "../keyboard.h" +#include "../timer.h" +#include "../port_92.h" +#include "../serial.h" +#include "../machine/machine.h" +#include "chipset.h" + + +typedef struct { + uint8_t cur_reg, + regs[39], + scratch[2]; + port_92_t * port_92; +} sis_85c471_t; + + +static void +sis_85c471_recalcmapping(sis_85c471_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + for (i = 0; i < 8; i++) { + base = 0xc0000 + (i << 15); + + if ((i > 5) || (dev->regs[0x02] & (1 << i))) { + shadowbios |= (base >= 0xe0000) && (dev->regs[0x02] & 0x80); + shadowbios_write |= (base >= 0xe0000) && !(dev->regs[0x02] & 0x40); + shflags = (dev->regs[0x02] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + shflags |= (dev->regs[0x02] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; + mem_set_mem_state(base, 0x8000, shflags); + } else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); +} + + +static void +sis_85c471_write(uint16_t port, uint8_t val, void *priv) +{ + sis_85c471_t *dev = (sis_85c471_t *) priv; + uint8_t valxor = 0x00; + + if (port == 0x22) { + if ((val >= 0x50) && (val <= 0x76)) + dev->cur_reg = val; + return; + } else if (port == 0x23) { + if ((dev->cur_reg < 0x50) || (dev->cur_reg > 0x76)) + return; + valxor = val ^ dev->regs[dev->cur_reg - 0x50]; + dev->regs[dev->cur_reg - 0x50] = val; + } else if ((port == 0xe1) || (port == 0xe2)) { + dev->scratch[port - 0xe1] = val; + return; + } + + switch(dev->cur_reg) { + case 0x51: + cpu_cache_ext_enabled = ((val & 0x84) == 0x84); + cpu_update_waitstates(); + break; + + case 0x52: + sis_85c471_recalcmapping(dev); + break; + + case 0x57: + if (valxor & 0x12) + port_92_set_features(dev->port_92, !!(val & 0x10), !!(val & 0x02)); + + if (valxor & 0x08) { + if (val & 0x08) + port_92_set_period(dev->port_92, 6ULL * TIMER_USEC); + else + port_92_set_period(dev->port_92, 2ULL * TIMER_USEC); + } + break; + + case 0x5b: + if (valxor & 0x02) { + if (val & 0x02) + mem_remap_top(0); + else + mem_remap_top(256); + } + break; + + case 0x63: + if (valxor & 0x10) { + if (dev->regs[0x13] & 0x10) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + break; + + case 0x72: + if (valxor & 0x01) { + port_92_remove(dev->port_92); + if (val & 0x01) + port_92_add(dev->port_92); + } + break; + } + + dev->cur_reg = 0; +} + + +static uint8_t +sis_85c471_read(uint16_t port, void *priv) +{ + sis_85c471_t *dev = (sis_85c471_t *) priv; + uint8_t ret = 0xff; + + if (port == 0x22) + ret = dev->cur_reg; + else if (port == 0x23) { + if ((dev->cur_reg >= 0x50) && (dev->cur_reg <= 0x76)) { + ret = dev->regs[dev->cur_reg - 0x50]; + if (dev->cur_reg == 0x58) + ret &= 0xf7; + dev->cur_reg = 0; + } + } else if ((port == 0xe1) || (port == 0xe2)) + ret = dev->scratch[port - 0xe1]; + + return ret; +} + + +static void +sis_85c471_close(void *priv) +{ + sis_85c471_t *dev = (sis_85c471_t *) priv; + + free(dev); +} + + +static void * +sis_85c471_init(const device_t *info) +{ + int mem_size_mb, i = 0; + + sis_85c471_t *dev = (sis_85c471_t *) malloc(sizeof(sis_85c471_t)); + memset(dev, 0, sizeof(sis_85c471_t)); + + dev->cur_reg = 0; + for (i = 0; i < 0x27; i++) + dev->regs[i] = 0x00; + + dev->regs[9] = 0x40; + + mem_size_mb = mem_size >> 10; + switch (mem_size_mb) { + case 0: case 1: + dev->regs[9] |= 0; + break; + case 2: case 3: + dev->regs[9] |= 1; + break; + case 4: + dev->regs[9] |= 2; + break; + case 5: + dev->regs[9] |= 0x20; + break; + case 6: case 7: + dev->regs[9] |= 9; + break; + case 8: case 9: + dev->regs[9] |= 4; + break; + case 10: case 11: + dev->regs[9] |= 5; + break; + case 12: case 13: case 14: case 15: + dev->regs[9] |= 0xB; + break; + case 16: + dev->regs[9] |= 0x13; + break; + case 17: + dev->regs[9] |= 0x21; + break; + case 18: case 19: + dev->regs[9] |= 6; + break; + case 20: case 21: case 22: case 23: + dev->regs[9] |= 0xD; + break; + case 24: case 25: case 26: case 27: + case 28: case 29: case 30: case 31: + dev->regs[9] |= 0xE; + break; + case 32: case 33: case 34: case 35: + dev->regs[9] |= 0x1B; + break; + case 36: case 37: case 38: case 39: + dev->regs[9] |= 0xF; + break; + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + dev->regs[9] |= 0x17; + break; + case 48: + dev->regs[9] |= 0x1E; + break; + default: + if (mem_size_mb < 64) + dev->regs[9] |= 0x1E; + else if ((mem_size_mb >= 65) && (mem_size_mb < 68)) + dev->regs[9] |= 0x22; + else + dev->regs[9] |= 0x24; + break; + } + + dev->regs[0x11] = 9; + dev->regs[0x12] = 0xFF; + dev->regs[0x1f] = 0x20; /* Video access enabled. */ + dev->regs[0x23] = 0xF0; + dev->regs[0x26] = 1; + + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed < 25000000) + dev->regs[0x08] |= 0x80; + + io_sethandler(0x0022, 0x0002, + sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev); + + dev->scratch[0] = dev->scratch[1] = 0xff; + + io_sethandler(0x00e1, 0x0002, + sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev); + + dev->port_92 = device_add(&port_92_device); + port_92_set_period(dev->port_92, 2ULL * TIMER_USEC); + port_92_set_features(dev->port_92, 0, 0); + + sis_85c471_recalcmapping(dev); + + return dev; +} + + +const device_t sis_85c471_device = { + "SiS 85c471", + 0, + 0, + sis_85c471_init, sis_85c471_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/sis_85c496.c b/src/chipset/sis_85c496.c new file mode 100644 index 000000000..cddb74b9d --- /dev/null +++ b/src/chipset/sis_85c496.c @@ -0,0 +1,342 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SiS 85c496/85c497 chip. + * + * Version: @(#)sis_85c496.c 1.0.2 2019/10/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../keyboard.h" +#include "../timer.h" +#include "../port_92.h" +#include "../disk/hdc_ide.h" +#include "../machine/machine.h" +#include "chipset.h" + + +typedef struct sis_85c496_t +{ + uint8_t cur_reg, + regs[127], + pci_conf[256]; + port_92_t * port_92; +} sis_85c496_t; + + +static void +sis_85c497_write(uint16_t port, uint8_t val, void *priv) +{ + sis_85c496_t *dev = (sis_85c496_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + + if (index) { + if ((val != 0x01) || ((val >= 0x70) && (val <= 0x76))) + dev->cur_reg = val; + } else { + if (((dev->cur_reg < 0x70) && (dev->cur_reg != 0x01)) || (dev->cur_reg > 0x76)) + return; + dev->regs[dev->cur_reg] = val; + dev->cur_reg = 0; + } +} + + +static uint8_t +sis_85c497_read(uint16_t port, void *priv) +{ + sis_85c496_t *dev = (sis_85c496_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; + + if (index) + ret = dev->cur_reg; + else { + if ((dev->cur_reg != 0x01) || ((dev->cur_reg >= 0x70) && (dev->cur_reg <= 0x76))) { + ret = dev->regs[dev->cur_reg]; + dev->cur_reg = 0; + } + } + + return ret; +} + + +static void +sis_85c496_recalcmapping(sis_85c496_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + for (i = 0; i < 8; i++) { + base = 0xc0000 + (i << 15); + + if (dev->pci_conf[0x44] & (1 << i)) { + shadowbios |= (base >= 0xe0000) && (dev->pci_conf[0x45] & 0x02); + shadowbios_write |= (base >= 0xe0000) && !(dev->pci_conf[0x45] & 0x01); + shflags = (dev->pci_conf[0x45] & 0x02) ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + shflags |= (dev->pci_conf[0x45] & 0x01) ? MEM_WRITE_EXTANY : MEM_WRITE_INTERNAL; + mem_set_mem_state(base, 0x8000, shflags); + } else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + + flushmmucache(); +} + + +/* 00 - 3F = PCI Configuration, 40 - 7F = 85C496, 80 - FF = 85C497 */ +static void +sis_85c496_write(int func, int addr, uint8_t val, void *priv) +{ + sis_85c496_t *dev = (sis_85c496_t *) priv; + uint8_t old = dev->pci_conf[addr]; + uint8_t valxor; + + if ((addr >= 4 && addr < 8) || addr >= 0x40) + dev->pci_conf[addr] = val; + + valxor = old ^ val; + + switch (addr) { + case 0x42: /*Cache configure*/ + cpu_cache_ext_enabled = (val & 0x01); + cpu_update_waitstates(); + break; + + case 0x44: /*Shadow configure*/ + if (valxor & 0xff) + sis_85c496_recalcmapping(dev); + break; + case 0x45: /*Shadow configure*/ + if (valxor & 0x03) + sis_85c496_recalcmapping(dev); + break; + + case 0x56: + if (valxor & 0x02) { + port_92_remove(dev->port_92); + if (val & 0x02) + port_92_add(dev->port_92); + pclog("Port 92: %sabled\n", (val & 0x02) ? "En" : "Dis"); + } + break; + + case 0x59: + if (valxor & 0x02) { + if (val & 0x02) { + ide_set_base(0, 0x0170); + ide_set_side(0, 0x0376); + ide_set_base(1, 0x01f0); + ide_set_side(1, 0x03f6); + } else { + ide_set_base(0, 0x01f0); + ide_set_side(0, 0x03f6); + ide_set_base(1, 0x0170); + ide_set_side(1, 0x0376); + } + } + break; + + case 0x58: + if (valxor & 0x80) { + if (dev->pci_conf[0x59] & 0x02) { + ide_sec_disable(); + if (val & 0x80) + ide_sec_enable(); + } else { + ide_pri_disable(); + if (val & 0x80) + ide_pri_enable(); + } + } + if (valxor & 0x40) { + if (dev->pci_conf[0x59] & 0x02) { + ide_pri_disable(); + if (val & 0x40) + ide_pri_enable(); + } else { + ide_sec_disable(); + if (val & 0x40) + ide_sec_enable(); + } + } + break; + + case 0x5a: + if (valxor & 0x04) { + if (val & 0x04) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + break; + + case 0x67: + if (valxor & 0x60) { + port_92_set_features(dev->port_92, !!(val & 0x20), !!(val & 0x40)); + pclog("[Port 92] Set features: %sreset, %sA20\n", !!(val & 0x20) ? "" : "no ", !!(val & 0x40) ? "" : "no "); + } + break; + + case 0x82: + sis_85c497_write(0x22, val, priv); + break; + + case 0xc0: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, val & 0xf); + else + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + break; + case 0xc1: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, val & 0xf); + else + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + break; + case 0xc2: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, val & 0xf); + else + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + break; + case 0xc3: + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, val & 0xf); + else + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + break; + } +} + + +static uint8_t +sis_85c496_read(int func, int addr, void *priv) +{ + sis_85c496_t *dev = (sis_85c496_t *) priv; + + switch (addr) { + case 0x82: /*Port 22h Mirror*/ + return inb(0x22); + case 0x70: /*Port 70h Mirror*/ + return inb(0x70); + } + + return dev->pci_conf[addr]; +} + + +static void +sis_85c497_reset(sis_85c496_t *dev) +{ + memset(dev->regs, 0, sizeof(dev->regs)); + + dev->regs[0x01] = 0xc0; + dev->regs[0x71] = 0x01; + dev->regs[0x72] = 0xff; + + io_removehandler(0x0022, 0x0002, + sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev); + io_sethandler(0x0022, 0x0002, + sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev); +} + + +static void +sis_85c496_reset(void *priv) +{ + sis_85c496_t *dev = (sis_85c496_t *) priv; + + sis_85c497_reset(dev); +} + + +static void +sis_85c496_close(void *p) +{ + sis_85c496_t *sis_85c496 = (sis_85c496_t *)p; + + free(sis_85c496); +} + + +static void +*sis_85c496_init(const device_t *info) +{ + sis_85c496_t *dev = malloc(sizeof(sis_85c496_t)); + memset(dev, 0, sizeof(sis_85c496_t)); + + dev->pci_conf[0x00] = 0x39; /*SiS*/ + dev->pci_conf[0x01] = 0x10; + dev->pci_conf[0x02] = 0x96; /*496/497*/ + dev->pci_conf[0x03] = 0x04; + + dev->pci_conf[0x04] = 7; + dev->pci_conf[0x05] = 0; + + dev->pci_conf[0x06] = 0x80; + dev->pci_conf[0x07] = 0x02; + + dev->pci_conf[0x08] = 2; /*Device revision*/ + + dev->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + + dev->pci_conf[0x0e] = 0x00; /*Single function device*/ + + dev->pci_conf[0xd0] = 0x78; /* ROM at E0000-FFFFF, Flash enable. */ + dev->pci_conf[0xd1] = 0xff; + + pci_add_card(5, sis_85c496_read, sis_85c496_write, dev); + + sis_85c497_reset(dev); + + dev->port_92 = device_add(&port_92_device); + port_92_set_period(dev->port_92, 2ULL * TIMER_USEC); + port_92_set_features(dev->port_92, 0, 0); + + sis_85c496_recalcmapping(dev); + + return dev; +} + + +const device_t sis_85c496_device = +{ + "SiS 85c496/85c497", + DEVICE_PCI, + 0, + sis_85c496_init, + sis_85c496_close, + sis_85c496_reset, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/chipset/sis_85c50x.c b/src/chipset/sis_85c50x.c new file mode 100644 index 000000000..f5a67198d --- /dev/null +++ b/src/chipset/sis_85c50x.c @@ -0,0 +1,441 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SiS 85c501/85c503 chip. + * + * Version: @(#)sis_85c50x.c 1.0.1 2019/10/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../keyboard.h" +#include "../port_92.h" +#include "chipset.h" + + +typedef struct sis_85c501_t +{ + /* 85c501 */ + uint8_t turbo_reg; + + /* 85c503 */ + + /* Registers */ + uint8_t pci_conf[2][256]; + + /* 85c50x ISA */ + uint8_t cur_reg, + regs[39]; +} sis_85c50x_t; + + +static void +sis_85c501_recalcmapping(sis_85c50x_t *dev) +{ + int c, d; + uint32_t base; + + for (c = 0; c < 1; c++) { + for (d = 0; d < 4; d++) { + base = 0xe0000 + (d << 14); + if (dev->pci_conf[0][0x54 + c] & (1 << (d + 4))) { + switch (dev->pci_conf[0][0x53] & 0x60) { + case 0x00: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + break; + case 0x20: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 0x40: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x60: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + } + } else + mem_set_mem_state(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + } + + flushmmucache(); + shadowbios = 1; +} + + +static void +sis_85c501_write(int func, int addr, uint8_t val, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) 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 &= 0x42; + val |= 0x04; + break; + case 0x05: + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x54: /*Shadow configure*/ + if ((dev->pci_conf[0][0x54] & val) ^ 0xf0) { + dev->pci_conf[0][0x54] = val; + sis_85c501_recalcmapping(dev); + } + break; + } + + dev->pci_conf[0][addr] = val; +} + + +static void +sis_85c503_write(int func, int addr, uint8_t val, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (func > 0) + return; + + if (addr >= 0x0f && addr < 0x41) + 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 0x41: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x42: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x43: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x44: + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + } + + dev->pci_conf[1][addr] = val; +} + + +static void +sis_85c50x_isa_write(uint16_t port, uint8_t val, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (port & 1) { + if (dev->cur_reg <= 0x1a) + dev->regs[dev->cur_reg] = val; + } else + dev->cur_reg = val; +} + + +static uint8_t +sis_85c501_read(int func, int addr, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (func) + return 0xff; + + return dev->pci_conf[0][addr]; +} + + +static uint8_t +sis_85c503_read(int func, int addr, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (func > 0) + return 0xff; + + return dev->pci_conf[1][addr]; +} + + +static uint8_t +sis_85c50x_isa_read(uint16_t port, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (port & 1) { + if (dev->cur_reg <= 0x1a) + return dev->regs[dev->cur_reg]; + else + return 0xff; + } else + return dev->cur_reg; +} + + +static void +sis_85c50x_isa_reset(sis_85c50x_t *dev) +{ + int mem_size_mb, i = 0; + + memset(dev->regs, 0, sizeof(dev->regs)); + + dev->cur_reg = 0; + for (i = 0; i < 0x27; i++) + dev->regs[i] = 0x00; + + dev->regs[9] = 0x40; + + mem_size_mb = mem_size >> 10; + switch (mem_size_mb) { + case 0: case 1: + dev->regs[9] |= 0; + break; + case 2: case 3: + dev->regs[9] |= 1; + break; + case 4: + dev->regs[9] |= 2; + break; + case 5: + dev->regs[9] |= 0x20; + break; + case 6: case 7: + dev->regs[9] |= 9; + break; + case 8: case 9: + dev->regs[9] |= 4; + break; + case 10: case 11: + dev->regs[9] |= 5; + break; + case 12: case 13: case 14: case 15: + dev->regs[9] |= 0xB; + break; + case 16: + dev->regs[9] |= 0x13; + break; + case 17: + dev->regs[9] |= 0x21; + break; + case 18: case 19: + dev->regs[9] |= 6; + break; + case 20: case 21: case 22: case 23: + dev->regs[9] |= 0xD; + break; + case 24: case 25: case 26: case 27: + case 28: case 29: case 30: case 31: + dev->regs[9] |= 0xE; + break; + case 32: case 33: case 34: case 35: + dev->regs[9] |= 0x1B; + break; + case 36: case 37: case 38: case 39: + dev->regs[9] |= 0xF; + break; + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + dev->regs[9] |= 0x17; + break; + case 48: + dev->regs[9] |= 0x1E; + break; + default: + if (mem_size_mb < 64) + dev->regs[9] |= 0x1E; + else if ((mem_size_mb >= 65) && (mem_size_mb < 68)) + dev->regs[9] |= 0x22; + else + dev->regs[9] |= 0x24; + break; + } + + dev->regs[0x11] = 9; + dev->regs[0x12] = 0xFF; + dev->regs[0x23] = 0xF0; + dev->regs[0x26] = 1; + + io_removehandler(0x22, 0x0002, + sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, dev); + io_sethandler(0x22, 0x0002, + sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, dev); +} + + +static void +sis_85c50x_reset(void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + uint8_t val = 0; + + val = sis_85c501_read(0, 0x54, priv); /* Read current value of 0x44. */ + sis_85c501_write(0, 0x54, val & 0xf, priv); /* Turn off shadow BIOS but keep the lower 4 bits. */ + + sis_85c50x_isa_reset(dev); +} + + +static void +sis_85c50x_setup(sis_85c50x_t *dev) +{ + memset(dev, 0, sizeof(sis_85c50x_t)); + + /* 85c501 */ + dev->pci_conf[0][0x00] = 0x39; /*SiS*/ + dev->pci_conf[0][0x01] = 0x10; + dev->pci_conf[0][0x02] = 0x06; /*501/502*/ + dev->pci_conf[0][0x03] = 0x04; + + dev->pci_conf[0][0x04] = 7; + dev->pci_conf[0][0x05] = 0; + + dev->pci_conf[0][0x06] = 0x80; + dev->pci_conf[0][0x07] = 0x02; + + dev->pci_conf[0][0x08] = 0; /*Device revision*/ + + dev->pci_conf[0][0x09] = 0x00; /*Device class (PCI bridge)*/ + dev->pci_conf[0][0x0a] = 0x00; + dev->pci_conf[0][0x0b] = 0x06; + + dev->pci_conf[0][0x0e] = 0x00; /*Single function device*/ + + dev->pci_conf[0][0x50] = 0xbc; + dev->pci_conf[0][0x51] = 0xfb; + dev->pci_conf[0][0x52] = 0xad; + dev->pci_conf[0][0x53] = 0xfe; + + shadowbios = 1; + + /* 85c503 */ + dev->pci_conf[1][0x00] = 0x39; /*SiS*/ + dev->pci_conf[1][0x01] = 0x10; + dev->pci_conf[1][0x02] = 0x08; /*503*/ + dev->pci_conf[1][0x03] = 0x00; + + dev->pci_conf[1][0x04] = 7; + dev->pci_conf[1][0x05] = 0; + + dev->pci_conf[1][0x06] = 0x80; + dev->pci_conf[1][0x07] = 0x02; + + dev->pci_conf[1][0x08] = 0; /*Device revision*/ + + dev->pci_conf[1][0x09] = 0x00; /*Device class (PCI bridge)*/ + dev->pci_conf[1][0x0a] = 0x01; + dev->pci_conf[1][0x0b] = 0x06; + + dev->pci_conf[1][0x0e] = 0x00; /*Single function device*/ + + dev->pci_conf[1][0x41] = dev->pci_conf[1][0x42] = + dev->pci_conf[1][0x43] = dev->pci_conf[1][0x44] = 0x80; +} + + +static void +sis_85c50x_close(void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + free(dev); +} + + +static void * +sis_85c50x_init(const device_t *info) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) malloc(sizeof(sis_85c50x_t)); + + pci_add_card(0, sis_85c501_read, sis_85c501_write, dev); + pci_add_card(5, sis_85c503_read, sis_85c503_write, dev); + + sis_85c50x_setup(dev); + sis_85c50x_isa_reset(dev); + + device_add(&port_92_pci_device); + + return dev; +} + + +const device_t sis_85c50x_device = +{ + "SiS 85c501/85c503", + DEVICE_PCI, + 0, + sis_85c50x_init, + sis_85c50x_close, + sis_85c50x_reset, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/chipset/wd76c10.c b/src/chipset/wd76c10.c new file mode 100644 index 000000000..e469f6672 --- /dev/null +++ b/src/chipset/wd76c10.c @@ -0,0 +1,292 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the WD76C10 System Controller chip. + * + * Version: @(#)wd76c10.c 1.0.1 2019/10/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "../io.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../port_92.h" +#include "../serial.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../video/vid_paradise.h" +#include "chipset.h" + + +typedef struct { + int type; + + uint16_t reg_0092; + uint16_t reg_2072; + uint16_t reg_2872; + uint16_t reg_5872; + + uint16_t reg_f872; + + serial_t *uart[2]; + + fdc_t *fdc; + + mem_mapping_t extram_mapping; + uint8_t extram[65536]; +} wd76c10_t; + + +static uint16_t +wd76c10_read(uint16_t port, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + int16_t ret = 0xffff; + + switch (port) { + case 0x2072: + ret = dev->reg_2072; + break; + + case 0x2872: + ret = dev->reg_2872; + break; + + case 0x5872: + ret = dev->reg_5872; + break; + + case 0xf872: + ret = dev->reg_f872; + break; + } + + return(ret); +} + + +static void +wd76c10_write(uint16_t port, uint16_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + switch (port) { + case 0x2072: + dev->reg_2072 = val; + + serial_remove(dev->uart[0]); + if (!(val & 0x10)) + { + switch ((val >> 5) & 7) + { + case 1: serial_setup(dev->uart[0], 0x3f8, 4); break; + case 2: serial_setup(dev->uart[0], 0x2f8, 4); break; + case 3: serial_setup(dev->uart[0], 0x3e8, 4); break; + case 4: serial_setup(dev->uart[0], 0x2e8, 4); break; + default: break; + } + } + serial_remove(dev->uart[1]); + if (!(val & 0x01)) + { + switch ((val >> 1) & 7) + { + case 1: serial_setup(dev->uart[1], 0x3f8, 3); break; + case 2: serial_setup(dev->uart[1], 0x2f8, 3); break; + case 3: serial_setup(dev->uart[1], 0x3e8, 3); break; + case 4: serial_setup(dev->uart[1], 0x2e8, 3); break; + default: break; + } + } + break; + + case 0x2872: + dev->reg_2872 = val; + + fdc_remove(dev->fdc); + if (! (val & 1)) + fdc_set_base(dev->fdc, 0x03f0); + break; + + case 0x5872: + dev->reg_5872 = val; + break; + + case 0xf872: + dev->reg_f872 = val; + switch (val & 3) { + case 0: + mem_set_mem_state(0xd0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 1: + mem_set_mem_state(0xd0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + case 2: + mem_set_mem_state(0xd0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(0xd0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); + if (val & 4) + mem_mapping_enable(&dev->extram_mapping); + else + mem_mapping_disable(&dev->extram_mapping); + flushmmucache_nopc(); + break; + } +} + + +static uint8_t +wd76c10_readb(uint16_t port, void *priv) +{ + if (port & 1) + return(wd76c10_read(port & ~1, priv) >> 8); + + return(wd76c10_read(port, priv) & 0xff); +} + + +static void +wd76c10_writeb(uint16_t port, uint8_t val, void *priv) +{ + uint16_t temp = wd76c10_read(port, priv); + + if (port & 1) + wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv); + else + wd76c10_write(port , (temp & 0xff00) | val, priv); +} + + +uint8_t +wd76c10_read_extram(uint32_t addr, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + return dev->extram[addr & 0xffff]; +} + + +uint16_t +wd76c10_read_extramw(uint32_t addr, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + return *(uint16_t *)&dev->extram[addr & 0xffff]; +} + + +uint32_t +wd76c10_read_extraml(uint32_t addr, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + return *(uint32_t *)&dev->extram[addr & 0xffff]; +} + + +void +wd76c10_write_extram(uint32_t addr, uint8_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + dev->extram[addr & 0xffff] = val; +} + + +void +wd76c10_write_extramw(uint32_t addr, uint16_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + *(uint16_t *)&dev->extram[addr & 0xffff] = val; +} + + +void +wd76c10_write_extraml(uint32_t addr, uint32_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + *(uint32_t *)&dev->extram[addr & 0xffff] = val; +} + + +static void +wd76c10_close(void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + free(dev); +} + + +static void * +wd76c10_init(const device_t *info) +{ + wd76c10_t *dev; + + dev = (wd76c10_t *) malloc(sizeof(wd76c10_t)); + memset(dev, 0x00, sizeof(wd76c10_t)); + dev->type = info->local; + + dev->fdc = (fdc_t *)device_add(&fdc_at_device); + + dev->uart[0] = device_add_inst(&i8250_device, 1); + dev->uart[1] = device_add_inst(&i8250_device, 2); + + device_add(&port_92_word_device); + + io_sethandler(0x2072, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + io_sethandler(0x2872, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + io_sethandler(0x5872, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + io_sethandler(0xf872, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + + mem_mapping_add(&dev->extram_mapping, 0xd0000, 0x10000, + wd76c10_read_extram,wd76c10_read_extramw,wd76c10_read_extraml, + wd76c10_write_extram,wd76c10_write_extramw,wd76c10_write_extraml, + dev->extram, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_disable(&dev->extram_mapping); + + return(dev); +} + + +const device_t wd76c10_device = { + "WD 76C10", + 0, + 0, + wd76c10_init, wd76c10_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/config.c b/src/config.c index f419539da..2b9026989 100644 --- a/src/config.c +++ b/src/config.c @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -8,16 +8,18 @@ * * Configuration file handler. * - * Version: @(#)config.c 1.0.48 2018/05/25 + * Version: @(#)config.c 1.0.66 2019/12/21 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * Overdoze, + * David HrdliÄka, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2018,2019 David HrdliÄka. * * NOTE: Forcing config files to be in Unicode encoding breaks * it on Windows XP, and possibly also Vista. Use the @@ -34,8 +36,11 @@ #include "86box.h" #include "cpu/cpu.h" #include "device.h" +#include "timer.h" #include "nvr.h" #include "config.h" +#include "isamem.h" +#include "isartc.h" #include "lpt.h" #include "disk/hdd.h" #include "disk/hdc.h" @@ -47,13 +52,12 @@ #include "mouse.h" #include "network/network.h" #include "scsi/scsi.h" +#include "scsi/scsi_device.h" #include "cdrom/cdrom.h" #include "disk/zip.h" #include "sound/sound.h" #include "sound/midi.h" -#include "sound/snd_dbopl.h" #include "sound/snd_mpu401.h" -#include "sound/snd_opl.h" #include "sound/sound.h" #include "video/video.h" #include "plat.h" @@ -107,22 +111,22 @@ static list_t config_head; #ifdef ENABLE_CONFIG_LOG int config_do_log = ENABLE_CONFIG_LOG; -#endif static void -config_log(const char *format, ...) +config_log(const char *fmt, ...) { -#ifdef ENABLE_CONFIG_LOG va_list ap; if (config_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define config_log(fmt, ...) +#endif static section_t * @@ -203,7 +207,7 @@ create_section(char *name) section_t *ns = malloc(sizeof(section_t)); memset(ns, 0x00, sizeof(section_t)); - strncpy(ns->name, name, sizeof(ns->name)); + memcpy(ns->name, name, strlen(name) + 1); list_add(&ns->list, &config_head); return(ns); @@ -216,7 +220,7 @@ create_entry(section_t *section, char *name) entry_t *ne = malloc(sizeof(entry_t)); memset(ne, 0x00, sizeof(entry_t)); - strncpy(ne->name, name, sizeof(ne->name)); + memcpy(ne->name, name, strlen(name) + 1); list_add(&ne->list, §ion->entry_head); return(ne); @@ -480,6 +484,10 @@ load_general(void) */ plat_langid = config_get_hex16(cat, "language", 0x0409); #endif + +#if USE_DISCORD + enable_discord = !!config_get_int(cat, "enable_discord", 0); +#endif } @@ -512,26 +520,43 @@ load_machine(void) if (machine >= machine_count()) machine = machine_count() - 1; - romset = machine_getromset(); cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0); cpu = config_get_int(cat, "cpu", 0); cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); mem_size = config_get_int(cat, "mem_size", 4096); + +#if 0 if (mem_size < (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram)) mem_size = (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram); - if (mem_size > 1048576) +#endif + + if (mem_size > 1048576) mem_size = 1048576; cpu_use_dynarec = !!config_get_int(cat, "cpu_use_dynarec", 0); enable_external_fpu = !!config_get_int(cat, "cpu_enable_fpu", 0); - enable_sync = !!config_get_int(cat, "enable_sync", 1); + p = config_get_string(cat, "time_sync", NULL); + if (p != NULL) { + if (!strcmp(p, "disabled")) + time_sync = TIME_SYNC_DISABLED; + else + if (!strcmp(p, "local")) + time_sync = TIME_SYNC_ENABLED; + else + if (!strcmp(p, "utc") || !strcmp(p, "gmt")) + time_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC; + else + time_sync = TIME_SYNC_ENABLED; + } else + time_sync = !!config_get_int(cat, "enable_sync", 1); /* Remove this after a while.. */ config_delete_var(cat, "nvr_path"); + config_delete_var(cat, "enable_sync"); } @@ -542,9 +567,9 @@ load_video(void) char *cat = "Video"; char *p; - if (machines[machine].fixed_gfxcard) { + if (machines[machine].flags & MACHINE_VIDEO_FIXED) { config_delete_var(cat, "gfxcard"); - gfxcard = GFX_INTERNAL; + gfxcard = VID_INTERNAL; } else { p = config_get_string(cat, "gfxcard", NULL); if (p == NULL) { @@ -624,20 +649,18 @@ load_sound(void) else midi_device_current = 0; + p = config_get_string(cat, "midi_in_device", NULL); + if (p != NULL) + midi_input_device_current = midi_in_device_get_from_internal_name(p); + else + midi_input_device_current = 0; + mpu401_standalone_enable = !!config_get_int(cat, "mpu401_standalone", 0); SSI2001 = !!config_get_int(cat, "ssi2001", 0); GAMEBLASTER = !!config_get_int(cat, "gameblaster", 0); GUS = !!config_get_int(cat, "gus", 0); - - memset(temp, '\0', sizeof(temp)); - p = config_get_string(cat, "opl_type", "dbopl"); - strcpy(temp, p); - if (!strcmp(temp, "nukedopl") || !strcmp(temp, "1")) - opl_type = 1; - else - opl_type = 0; - + memset(temp, '\0', sizeof(temp)); p = config_get_string(cat, "sound_type", "float"); strcpy(temp, p); @@ -703,28 +726,30 @@ load_ports(void) { char *cat = "Ports (COM & LPT)"; char *p; + char temp[512]; + int c, d; - serial_enabled[0] = !!config_get_int(cat, "serial1_enabled", 1); - serial_enabled[1] = !!config_get_int(cat, "serial2_enabled", 1); - lpt_enabled = !!config_get_int(cat, "lpt_enabled", 1); + for (c = 0; c < 2; c++) { + sprintf(temp, "serial%d_enabled", c + 1); + serial_enabled[c] = !!config_get_int(cat, temp, 1); + } - p = (char *)config_get_string(cat, "lpt1_device", NULL); - if (p != NULL) - strcpy(lpt_device_names[0], p); - else - strcpy(lpt_device_names[0], "none"); + for (c = 0; c < 3; c++) { + sprintf(temp, "lpt%d_enabled", c + 1); + lpt_ports[c].enabled = !!config_get_int(cat, temp, (c == 0) ? 1 : 0); - p = (char *)config_get_string(cat, "lpt2_device", NULL); - if (p != NULL) - strcpy(lpt_device_names[1], p); - else - strcpy(lpt_device_names[1], "none"); + sprintf(temp, "lpt%d_device", c + 1); + p = (char *) config_get_string(cat, temp, "none"); + lpt_ports[c].device = lpt_device_get_from_internal_name(p); + } - p = (char *)config_get_string(cat, "lpt3_device", NULL); - if (p != NULL) - strcpy(lpt_device_names[2], p); - else - strcpy(lpt_device_names[2], "none"); + /* Legacy config compatibility. */ + d = config_get_int(cat, "lpt_enabled", 2); + if (d < 2) { + for (c = 0; c < 3; c++) + lpt_ports[c].enabled = d; + } + config_delete_var(cat, "lpt_enabled"); } @@ -734,41 +759,48 @@ load_other_peripherals(void) { char *cat = "Other peripherals"; char *p; - + char temp[512]; + int c; + p = config_get_string(cat, "scsicard", NULL); if (p != NULL) scsi_card_current = scsi_card_get_from_internal_name(p); else scsi_card_current = 0; - if (hdc_name) { - free(hdc_name); - hdc_name = NULL; - } p = config_get_string(cat, "hdc", NULL); - if (p == NULL) { - p = config_get_string(cat, "hdd_controller", NULL); - if (p != NULL) - config_delete_var(cat, "hdd_controller"); - } if (p == NULL) { if (machines[machine].flags & MACHINE_HDC) { - hdc_name = (char *) malloc((strlen("internal") + 1) * sizeof(char)); - strcpy(hdc_name, "internal"); + p = (char *)malloc((strlen("internal")+1)*sizeof(char)); + strcpy(p, "internal"); } else { - hdc_name = (char *) malloc((strlen("none") + 1) * sizeof(char)); - strcpy(hdc_name, "none"); + p = (char *)malloc((strlen("none")+1)*sizeof(char)); + strcpy(p, "none"); } - } else { - hdc_name = (char *) malloc((strlen(p) + 1) * sizeof(char)); - strcpy(hdc_name, p); } - config_set_string(cat, "hdc", hdc_name); + if (!strcmp(p, "mfm_xt")) + hdc_current = hdc_get_from_internal_name("st506_xt"); + else if (!strcmp(p, "mfm_xt_dtc5150x")) + hdc_current = hdc_get_from_internal_name("st506_xt_dtc5150x"); + else if (!strcmp(p, "mfm_at")) + hdc_current = hdc_get_from_internal_name("st506_at"); + else + hdc_current = hdc_get_from_internal_name(p); ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0); ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0); bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0); + + for (c = 0; c < ISAMEM_MAX; c++) { + sprintf(temp, "isamem%d_type", c); + + p = config_get_string(cat, temp, "none"); + isamem_type[c] = isamem_get_from_internal_name(p); + } + + p = config_get_string(cat, "isartc_type", "none"); + isartc_type = isartc_get_from_internal_name(p); } @@ -784,8 +816,6 @@ load_hard_disks(void) wchar_t *wp; uint32_t max_spt, max_hpc, max_tracks; uint32_t board = 0, dev = 0; - /* FIXME: Remove in a month. */ - int lun; memset(temp, '\0', sizeof(temp)); for (c=0; c>1, c&1); @@ -888,21 +916,6 @@ load_hard_disks(void) } else config_delete_var(cat, temp); - /* FIXME: Remove in a month. */ - sprintf(temp, "hdd_%02i_scsi_location", c+1); - if (hdd[c].bus == HDD_BUS_SCSI) { - p = config_get_string(cat, temp, NULL); - - if (p) { - sscanf(p, "%02i:%02i", - (int *)&hdd[c].scsi_id, (int *)&lun); - - if (hdd[c].scsi_id > 15) - hdd[c].scsi_id = 15; - } - } - config_delete_var(cat, temp); - memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn)); memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn)); sprintf(temp, "hdd_%02i_fn", c+1); @@ -941,10 +954,6 @@ load_hard_disks(void) sprintf(temp, "hdd_%02i_scsi_id", c+1); config_delete_var(cat, temp); - /* FIXME: Remove in a month. */ - sprintf(temp, "hdd_%02i_scsi_location", c+1); - config_delete_var(cat, temp); - sprintf(temp, "hdd_%02i_fn", c+1); config_delete_var(cat, temp); } @@ -1039,64 +1048,49 @@ load_other_removable_devices(void) char s[512]; unsigned int board = 0, dev = 0; wchar_t *wp; - int c; - /* FIXME: Remove in a month. */ - int lun; + int c, d = 0; memset(temp, 0x00, sizeof(temp)); for (c=0; c>1, (c+2)&1); p = config_get_string(cat, temp, tmp2); sscanf(p, "%01u:%01u", &board, &dev); board &= 3; dev &= 1; - cdrom_drives[c].ide_channel = (board<<1)+dev; + cdrom[c].ide_channel = (board<<1)+dev; - if (cdrom_drives[c].ide_channel > 7) - cdrom_drives[c].ide_channel = 7; + if (cdrom[c].ide_channel > 7) + cdrom[c].ide_channel = 7; } else { sprintf(temp, "cdrom_%02i_scsi_id", c+1); - if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) { - cdrom_drives[c].scsi_device_id = config_get_int(cat, temp, c+2); + if (cdrom[c].bus_type == CDROM_BUS_SCSI) { + cdrom[c].scsi_device_id = config_get_int(cat, temp, c+2); - if (cdrom_drives[c].scsi_device_id > 15) - cdrom_drives[c].scsi_device_id = 15; + if (cdrom[c].scsi_device_id > 15) + cdrom[c].scsi_device_id = 15; } else config_delete_var(cat, temp); - - /* FIXME: Remove in a month. */ - sprintf(temp, "cdrom_%02i_scsi_location", c+1); - if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) { - p = config_get_string(cat, temp, NULL); - if (p) { - sscanf(p, "%02u:%02u", - &cdrom_drives[c].scsi_device_id, &lun); - - if (cdrom_drives[c].scsi_device_id > 15) - cdrom_drives[c].scsi_device_id = 15; - } - } - config_delete_var(cat, temp); } sprintf(temp, "cdrom_%02i_image_path", c+1); @@ -1116,20 +1110,20 @@ load_other_removable_devices(void) * with the EXE path. Just strip * that off for now... */ - wcsncpy(cdrom_image[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom_image[c].image_path)); + wcsncpy(cdrom[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom[c].image_path)); } else #endif - wcsncpy(cdrom_image[c].image_path, wp, sizeof_w(cdrom_image[c].image_path)); + wcsncpy(cdrom[c].image_path, wp, sizeof_w(cdrom[c].image_path)); - if (cdrom_drives[c].host_drive < 'A') - cdrom_drives[c].host_drive = 0; + if (cdrom[c].host_drive && (cdrom[c].host_drive != 200)) + cdrom[c].host_drive = 0; - if ((cdrom_drives[c].host_drive == 0x200) && - (wcslen(cdrom_image[c].image_path) == 0)) - cdrom_drives[c].host_drive = 0; + if ((cdrom[c].host_drive == 0x200) && + (wcslen(cdrom[c].image_path) == 0)) + cdrom[c].host_drive = 0; /* If the CD-ROM is disabled, delete all its variables. */ - if (cdrom_drives[c].bus_type == CDROM_BUS_DISABLED) { + if (cdrom[c].bus_type == CDROM_BUS_DISABLED) { sprintf(temp, "cdrom_%02i_host_drive", c+1); config_delete_var(cat, temp); @@ -1142,10 +1136,6 @@ load_other_removable_devices(void) sprintf(temp, "cdrom_%02i_scsi_id", c+1); config_delete_var(cat, temp); - /* FIXME: Remove in a month. */ - sprintf(temp, "cdrom_%02i_scsi_location", c+1); - config_delete_var(cat, temp); - sprintf(temp, "cdrom_%02i_image_path", c+1); config_delete_var(cat, temp); } @@ -1187,20 +1177,6 @@ load_other_removable_devices(void) zip_drives[c].scsi_device_id = 15; } else config_delete_var(cat, temp); - - /* FIXME: Remove in a month. */ - sprintf(temp, "zip_%02i_scsi_location", c+1); - if (zip_drives[c].bus_type == CDROM_BUS_SCSI) { - p = config_get_string(cat, temp, NULL); - if (p) { - sscanf(p, "%02u:%02u", - &zip_drives[c].scsi_device_id, &lun); - - if (zip_drives[c].scsi_device_id > 15) - zip_drives[c].scsi_device_id = 15; - } - } - config_delete_var(cat, temp); } sprintf(temp, "zip_%02i_image_path", c+1); @@ -1239,10 +1215,6 @@ load_other_removable_devices(void) sprintf(temp, "zip_%02i_scsi_id", c+1); config_delete_var(cat, temp); - /* FIXME: Remove in a month. */ - sprintf(temp, "zip_%02i_scsi_location", c+1); - config_delete_var(cat, temp); - sprintf(temp, "zip_%02i_image_path", c+1); config_delete_var(cat, temp); } @@ -1262,8 +1234,7 @@ config_load(void) config_log("Loading config file '%ls'..\n", cfg_path); memset(hdd, 0, sizeof(hard_disk_t)); - memset(cdrom_drives, 0, sizeof(cdrom_drive_t) * CDROM_NUM); - memset(cdrom_image, 0, sizeof(cdrom_image_t) * CDROM_NUM); + memset(cdrom, 0, sizeof(cdrom_t) * CDROM_NUM); #ifdef USE_IOCTL memset(cdrom_ioctl, 0, sizeof(cdrom_ioctl_t) * CDROM_NUM); #endif @@ -1276,19 +1247,16 @@ config_load(void) #endif scale = 1; machine = machine_get_machine_from_internal_name("ibmpc"); - gfxcard = GFX_CGA; + gfxcard = video_get_video_from_internal_name("cga"); vid_api = plat_vidapi("default"); - enable_sync = 1; + time_sync = TIME_SYNC_ENABLED; joystick_type = 7; - if (hdc_name) { - free(hdc_name); - hdc_name = NULL; - } - hdc_name = (char *) malloc((strlen("none")+1) * sizeof(char)); - strcpy(hdc_name, "none"); + hdc_current = hdc_get_from_internal_name("none"); serial_enabled[0] = 1; serial_enabled[1] = 1; - lpt_enabled = 1; + lpt_ports[0].enabled = 1; + lpt_ports[1].enabled = 0; + lpt_ports[2].enabled = 0; for (i = 0; i < FDD_NUM; i++) { if (i < 2) fdd_set_type(i, 2); @@ -1299,7 +1267,9 @@ config_load(void) fdd_set_check_bpb(i, 1); } mem_size = 640; - opl_type = 0; + isartc_type = 0; + for (i = 0; i < ISAMEM_MAX; i++) + isamem_type[i] = 0; config_log("Config file not present or invalid!\n"); return; @@ -1416,6 +1386,13 @@ save_general(void) config_set_hex16(cat, "language", plat_langid); #endif +#if USE_DISCORD + if (enable_discord) + config_set_int(cat, "enable_discord", enable_discord); + else + config_delete_var(cat, "enable_discord"); +#endif + delete_section_if_empty(cat); } @@ -1455,10 +1432,13 @@ save_machine(void) else config_set_int(cat, "cpu_enable_fpu", enable_external_fpu); - if (enable_sync == 1) - config_delete_var(cat, "enable_sync"); - else - config_set_int(cat, "enable_sync", enable_sync); + if (time_sync & TIME_SYNC_ENABLED) + if (time_sync & TIME_SYNC_UTC) + config_set_string(cat, "time_sync", "utc"); + else + config_set_string(cat, "time_sync", "local"); + else + config_set_string(cat, "time_sync", "disabled"); delete_section_if_empty(cat); } @@ -1471,7 +1451,7 @@ save_video(void) char *cat = "Video"; config_set_string(cat, "gfxcard", - video_get_internal_name(video_old_to_new(gfxcard))); + video_get_internal_name(gfxcard)); if (voodoo_enabled == 0) config_delete_var(cat, "voodoo"); @@ -1492,13 +1472,10 @@ save_input_devices(void) config_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type)); - if ((joystick_type == 0) || (joystick_type == 7)) { - if (joystick_type == 7) - config_delete_var(cat, "joystick_type"); - else - config_set_int(cat, "joystick_type", joystick_type); + if (joystick_type == 7) { + config_delete_var(cat, "joystick_type"); - for (c=0; c<16; c++) { + for (c = 0; c < 16; c++) { sprintf(tmp2, "joystick_%i_nr", c); config_delete_var(cat, tmp2); @@ -1518,7 +1495,7 @@ save_input_devices(void) } else { config_set_int(cat, "joystick_type", joystick_type); - for (c=0; c 'Z') && (cdrom_drives[c].host_drive != 200))) { + if ((cdrom[c].bus_type == 0) || (cdrom[c].host_drive != 200)) { config_delete_var(cat, temp); } else { - config_set_int(cat, temp, cdrom_drives[c].host_drive); + config_set_int(cat, temp, cdrom[c].host_drive); } sprintf(temp, "cdrom_%02i_speed", c+1); - if ((cdrom_drives[c].bus_type == 0) || (cdrom_drives[c].speed == 8)) { + if ((cdrom[c].bus_type == 0) || (cdrom[c].speed == 8)) { config_delete_var(cat, temp); } else { - config_set_int(cat, temp, cdrom_drives[c].speed); + config_set_int(cat, temp, cdrom[c].speed); } sprintf(temp, "cdrom_%02i_parameters", c+1); - if (cdrom_drives[c].bus_type == 0) { + if (cdrom[c].bus_type == 0) { config_delete_var(cat, temp); } else { - sprintf(tmp2, "%u, %s", cdrom_drives[c].sound_on, - hdd_bus_to_string(cdrom_drives[c].bus_type, 1)); + sprintf(tmp2, "%u, %s", cdrom[c].sound_on, + hdd_bus_to_string(cdrom[c].bus_type, 1)); config_set_string(cat, temp, tmp2); } sprintf(temp, "cdrom_%02i_ide_channel", c+1); - if (cdrom_drives[c].bus_type != CDROM_BUS_ATAPI) + if (cdrom[c].bus_type != CDROM_BUS_ATAPI) config_delete_var(cat, temp); else { - sprintf(tmp2, "%01u:%01u", cdrom_drives[c].ide_channel>>1, - cdrom_drives[c].ide_channel & 1); + sprintf(tmp2, "%01u:%01u", cdrom[c].ide_channel>>1, + cdrom[c].ide_channel & 1); config_set_string(cat, temp, tmp2); } sprintf(temp, "cdrom_%02i_scsi_id", c + 1); - if (cdrom_drives[c].bus_type != CDROM_BUS_SCSI) { + if (cdrom[c].bus_type != CDROM_BUS_SCSI) { config_delete_var(cat, temp); } else { - config_set_int(cat, temp, cdrom_drives[c].scsi_device_id); + config_set_int(cat, temp, cdrom[c].scsi_device_id); } sprintf(temp, "cdrom_%02i_image_path", c + 1); - if ((cdrom_drives[c].bus_type == 0) || - (wcslen(cdrom_image[c].image_path) == 0)) { + if ((cdrom[c].bus_type == 0) || + (wcslen(cdrom[c].image_path) == 0)) { config_delete_var(cat, temp); } else { - config_set_wstring(cat, temp, cdrom_image[c].image_path); + config_set_wstring(cat, temp, cdrom[c].image_path); } } @@ -1939,7 +1929,7 @@ config_dump(void) while (sec != NULL) { entry_t *ent; - if (sec->name && sec->name[0]) + if (sec->name[0]) config_log("[%s]\n", sec->name); ent = (entry_t *)sec->entry_head.next; @@ -2182,7 +2172,7 @@ config_set_string(char *head, char *name, char *val) if (ent == NULL) ent = create_entry(section, name); - strncpy(ent->data, val, sizeof(ent->data)); + memcpy(ent->data, val, sizeof(ent->data)); mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); } diff --git a/src/config.h b/src/config.h index 138748585..a3abf7f74 100644 --- a/src/config.h +++ b/src/config.h @@ -27,6 +27,116 @@ extern "C" { #endif +#if 0 +typedef struct { + uint8_t id, + uint8_t bus_type, /* Bus type: IDE, SCSI, etc. */ + bus, :4, /* ID of the bus (for example, for IDE, + 0 = primary, 1 = secondary, etc. */ + bus_id, :4, /* ID of the device on the bus */ + uint8_t type, /* Type flags, interpretation depends + on the device */ + uint8_t is_image; /* This is only used for CD-ROM: + 0 = Image; + 1 = Host drive */ + + wchar_t path[1024]; /* Name of current image file or + host drive */ + + uint32_t spt, /* Physical geometry parameters */ + hpc, + tracks; +} storage_cfg_t; + +typedef struct { + /* General configuration */ + int vid_resize, /* Window is resizable or not */ + vid_renderer, /* Renderer */ + vid_fullscreen_scale, /* Full screen scale type */ + vid_fullscreen_start, /* Start emulator in full screen */ + vid_force_43, /* Force 4:3 display ratio in windowed mode */ + vid_scale, /* Windowed mode scale */ + vid_overscan, /* EGA/(S)VGA overscan enabled */ + vid_cga_contrast, /* CGA alternate contrast enabled */ + vid_grayscale, /* Video is grayscale */ + vid_grayscale_type, /* Video grayscale type */ + vid_invert_display, /* Invert display */ + rctrl_is_lalt, /* Right CTRL is left ALT */ + update_icons, /* Update status bar icons */ + window_remember, /* Remember window position and size */ + window_w, /* Window coordinates */ + window_h, + window_x, + window_y, + sound_gain; /* Sound gain */ +#ifdef USE_LANGUAGE + uint16_t language_id; /* Language ID (0x0409 = English (US)) */ +#endif + + /* Machine cateogory */ + int machine, /* Machine */ + cpu_manufacturer, /* CPU manufacturer */ + cpu, /* CPU */ +#ifdef USE_DYNAREC + cpu_use_dynarec, /* CPU recompiler enabled */ +#endif + wait_states, /* CPU wait states */ + enable_external_fpu, /* FPU enabled */ + time_sync; /* Time sync enabled */ + uint32_t mem_size; /* Memory size */ + + /* Video category */ + int video_card, /* Video card */ + voodoo_enabled; /* Voodoo enabled */ + + /* Input devices category */ + int mouse_type, /* Mouse type */ + joystick_type; /* Joystick type */ + + /* Sound category */ + int sound_card, /* Sound card */ + midi_device, /* Midi device */ + mpu_401, /* Standalone MPU-401 enabled */ + ssi_2001_enabled, /* SSI-2001 enabled */ + game_blaster_enabled, /* Game blaster enabled */ + gus_enabled, /* Gravis Ultrasound enabled */ + opl_type, /* OPL emulation type */ + sound_is_float; /* Sound is 32-bit float or 16-bit integer */ + + /* Network category */ + int network_type, /* Network type (SLiRP or PCap) */ + network_card; /* Network card */ + char network_host[520]; /* PCap device */ + + /* Ports category */ + char parallel_devices[3][32]; /* LPT device names */ +#ifdef USE_SERIAL_DEVICES + char serial_devices[2][32]; /* Serial device names */ +#endif + int serial_enabled[2], /* Serial ports 1 and 2 enabled */ + parallel_enabled[3]; /* LPT1, LPT2, LPT3 enabled */ + + /* Other peripherals category */ + int hdc, /* Hard disk controller */ + scsi_card, /* SCSI controller */ + ide_ter_enabled, /* Tertiary IDE controller enabled */ + ide_qua_enabled, /* Quaternary IDE controller enabled */ + bugger_enabled, /* ISA bugger device enabled */ + isa_rtc_type, /* ISA RTC card */ + isa_mem_type[ISAMEM_MAX]; /* ISA memory boards */ + + /* Hard disks category */ + storage_cfg_t hdd[HDD_NUM]; /* Hard disk drives */ + + /* Floppy drives category */ + storage_cfg_t fdd[FDD_NUM]; /* Floppy drives */ + + /* Other removable devices category */ + storage_cfg_t cdrom[CDROM_NUM], /* CD-ROM drives */ + storage_cfg_t rdisk[ZIP_NUM]; /* Removable disk drives */ +} config_t; +#endif + extern void config_load(void); extern void config_save(void); extern void config_write(wchar_t *fn); diff --git a/src/cpu/386.c b/src/cpu/386.c index 60012df57..7694a0be4 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -11,13 +11,13 @@ #define HAVE_STDARG_H #include "../86box.h" #include "cpu.h" +#include "../timer.h" #include "x86.h" #include "x87.h" #include "../nmi.h" #include "../mem.h" #include "../pic.h" #include "../pit.h" -#include "../timer.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "386_common.h" @@ -27,53 +27,30 @@ extern int codegen_flags_changed; -extern int nmi_enable; +int cpl_override = 0, fpucount = 0; +int tempc, oldcpl, optype, inttype, oddeven = 0; +int stack32, timetolive; -int inscounts[256]; -uint32_t oldpc2; +uint16_t oldcs; -int trap; - -uint16_t flags,eflags; -uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; +uint32_t use32; +uint32_t oldds, oldss, olddslimit, oldsslimit, + olddslimitw, oldsslimitw; +uint32_t *eal_r, *eal_w; +uint32_t oxpc, cr2, cr3, cr4; +uint32_t dr[8]; +uint32_t rmdat32; +uint32_t backupregs[16]; x86seg gdt,ldt,idt,tr; -x86seg _cs,_ds,_es,_ss,_fs,_gs; x86seg _oldds; - - -extern int cpl_override; - -extern int fpucount; -uint16_t rds; -uint16_t ea_rseg; - -int cgate32; - -uint32_t cr2, cr3, cr4; -uint32_t dr[8]; - -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]; - +uint32_t rmdat; #define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 0; } #define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 0 + #include "x86_flags.h" #define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ @@ -88,7 +65,7 @@ uint32_t testr[9]; extern int dontprint; #undef NOTRM -#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ +#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\ { \ x86_int(6); \ return 0; \ @@ -102,7 +79,7 @@ extern int dontprint; #include "x86_ops.h" #undef NOTRM -#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ +#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\ { \ x86_int(6); \ break; \ @@ -111,13 +88,11 @@ extern int dontprint; #ifdef ENABLE_386_LOG int x386_do_log = ENABLE_386_LOG; -#endif static void x386_log(const char *fmt, ...) { -#ifdef ENABLE_386_LOG va_list ap; if (x386_do_log) { @@ -125,60 +100,54 @@ x386_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define x386_log(fmt, ...) +#endif void exec386(int cycs) { - uint8_t temp; + int vector, tempi, cycdiff, oldcyc; + int ins_cycles; uint32_t addr; - int tempi; - int cycdiff; - int oldcyc; cycles+=cycs; - /* output=3; */ while (cycles>0) { - int cycle_period = (timer_count >> TIMER_SHIFT) + 1; + int cycle_period = (timer_target - (uint32_t)tsc) + 1; x86_was_reset = 0; cycdiff=0; oldcyc=cycles; - timer_start_period(cycles << TIMER_SHIFT); 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; */ + ins_cycles = cycles; + oldcs=CS; cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; + oldcpl=CPL; cpu_state.op32 = use32; x86_was_reset = 0; 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; - fetchdat >>= 8; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; cpu_state.pc++; x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); - if (x86_was_reset) - break; - if(x86_was_reset) break; + if(x86_was_reset) + break; } if (!use32) cpu_state.pc &= 0xffff; @@ -205,6 +174,10 @@ dontprint=0; } } } + + ins_cycles -= cycles; + tsc += ins_cycles; + cycdiff=oldcyc-cycles; if (trap) @@ -218,13 +191,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 = (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)); } @@ -241,26 +214,26 @@ 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) + vector = picinterrupt(); + if (vector != -1) { flags_rebuild(); if (msw&1) { - pmodeint(temp,0); + pmodeint(vector,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; + addr = (vector << 2) + idt.base; + cpu_state.flags&=~I_FLAG; + cpu_state.flags&=~T_FLAG; + oxpc = cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); } @@ -277,8 +250,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/cpu/386.h b/src/cpu/386.h deleted file mode 100644 index e207d48ca..000000000 --- a/src/cpu/386.h +++ /dev/null @@ -1,5 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -extern void cpu_386_flags_extract(); -extern void cpu_386_flags_rebuild(); diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index c7abc9793..428bf3118 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -8,16 +8,14 @@ * * Common 386 CPU code. * - * Version: @(#)386_common.h 1.0.0 2017/05/30 + * Version: @(#)386_common.h 1.0.1 2019/02/19 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016-2017 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ -extern uint16_t ea_rseg; - #undef readmemb #undef writememb @@ -32,7 +30,7 @@ extern uint16_t ea_rseg; #define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ +#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (cpu_state.eflags&VM_FLAG))) \ { \ int tempi = checkio(port); \ if (cpu_state.abrt) return 1; \ @@ -43,46 +41,91 @@ extern uint16_t ea_rseg; } \ } -#define checkio_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ - { \ - tempi = checkio(port); \ - if (cpu_state.abrt) break; \ - if (tempi) \ - { \ - x86gpf("checkio_perm(): no permission",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(chseg, low, high) \ - if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \ { \ x86gpf("Limit check (READ)", 0); \ return 1; \ } \ - if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ { \ - if ((chseg) == &_ss) \ + if ((chseg) == &cpu_state.seg_ss) \ x86ss(NULL,(chseg)->seg & 0xfffc); \ else \ x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ return 1; \ - } + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 0); \ + (void) mmutranslatereal((chseg)->base + high, 0); \ + if (cpu_state.abrt) \ + return 1; \ + } -#define CHECK_WRITE(chseg, low, high) \ - if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(eflags & VM_FLAG) && ((chseg)->access & 8))) \ +#define CHECK_READ_REP(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (READ)", 0); \ + break; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 0); \ + (void) mmutranslatereal((chseg)->base + high, 0); \ + if (cpu_state.abrt) \ + break; \ + } + +#define CHECK_WRITE_COMMON(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && ((chseg)->access & 8))) \ { \ x86gpf("Limit check (WRITE)", 0); \ return 1; \ } \ - if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ { \ - if ((chseg) == &_ss) \ + if ((chseg) == &cpu_state.seg_ss) \ x86ss(NULL,(chseg)->seg & 0xfffc); \ else \ x86np("Write to seg not present", (chseg)->seg & 0xfffc); \ return 1; \ - } + } + +#define CHECK_WRITE(chseg, low, high) \ + CHECK_WRITE_COMMON(chseg, low, high) \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 1); \ + (void) mmutranslatereal((chseg)->base + high, 1); \ + if (cpu_state.abrt) \ + return 1; \ + } #define CHECK_WRITE_REP(chseg, low, high) \ if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ @@ -90,17 +133,23 @@ extern uint16_t ea_rseg; x86gpf("Limit check (WRITE REP)", 0); \ break; \ } \ - if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ { \ - if ((chseg) == &_ss) \ + if ((chseg) == &cpu_state.seg_ss) \ x86ss(NULL,(chseg)->seg & 0xfffc); \ else \ x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ break; \ - } + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 1); \ + (void) mmutranslatereal((chseg)->base + high, 1); \ + if (cpu_state.abrt) \ + break; \ + } -#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ +#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\ { \ x86_int(6); \ return 1; \ @@ -165,6 +214,17 @@ static __inline uint32_t fastreadl(uint32_t a) 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++; @@ -204,7 +264,6 @@ 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); @@ -214,7 +273,6 @@ 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); @@ -241,15 +299,24 @@ static __inline uint32_t geteal_mem() return readmeml(easeg,cpu_state.eaaddr); } +static __inline int seteaq_cwc(void) +{ + CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + return 0; +} + static __inline void seteaq(uint64_t v) { + if (seteaq_cwc()) + return; 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) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); 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) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); 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) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 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); @@ -258,9 +325,3 @@ static __inline void seteaq(uint64_t v) #define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 #define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ #define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 - - -#define rmdat rmdat32 -#define fetchdat rmdat32 - -void x86_int(int num); diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index a3ff0c0ee..7a26ae37d 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -34,53 +34,18 @@ uint32_t cpu_cur_status = 0; int cpu_reps, cpu_reps_latched; int cpu_notreps, cpu_notreps_latched; -int inrecomp = 0; +int inrecomp = 0, cpu_block_end = 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 fpucount=0; -uint16_t rds; -uint16_t ea_rseg; - -int cgate32; - -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]; - #ifdef ENABLE_386_DYNAREC_LOG int x386_dynarec_do_log = ENABLE_386_DYNAREC_LOG; -#endif -static void +void x386_dynarec_log(const char *fmt, ...) { -#ifdef ENABLE_386_DYNAREC_LOG va_list ap; if (x386_dynarec_do_log) { @@ -88,15 +53,16 @@ x386_dynarec_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define x86_dynarec_log (fmt, ...) +#endif 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; @@ -122,8 +88,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); @@ -136,8 +101,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) { @@ -169,7 +133,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 (!cpu_mod && cpu_rm == 6) { cpu_state.eaaddr = getword(); @@ -192,8 +155,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; } @@ -233,7 +195,9 @@ void x86_int(int num) cpu_state.abrt = 0; softresetx86(); cpu_set_edx(); +#ifdef ENABLE_386_DYNAREC_LOG x386_dynarec_log("Triple fault in real mode - reset\n"); +#endif } else x86_int(8); @@ -242,22 +206,22 @@ void x86_int(int num) { 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; + oxpc=cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); } @@ -287,22 +251,22 @@ void x86_int_sw(int num) { 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; + oxpc=cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); cycles -= timing_int_rm; @@ -326,16 +290,28 @@ int x86_int_sw_rm(int num) if (cpu_state.abrt) return 1; - writememw(ss,((SP-2)&0xFFFF),flags); if (cpu_state.abrt) {x386_dynarec_log("abrt5\n"); return 1; } + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); + if (cpu_state.abrt) { +#ifdef ENABLE_386_DYNAREC_LOG + x386_dynarec_log("abrt5\n"); +#endif + return 1; + } writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); if (cpu_state.abrt) {x386_dynarec_log("abrt6\n"); return 1; } + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + if (cpu_state.abrt) { +#ifdef ENABLE_386_DYNAREC_LOG + x386_dynarec_log("abrt6\n"); +#endif + return 1; + } SP-=6; - eflags &= ~VIF_FLAG; - flags &= ~T_FLAG; + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags &= ~T_FLAG; cpu_state.pc = new_pc; loadcs(new_cs); - oxpc=cpu_state.pc; + oxpc=cpu_state.pc; cycles -= timing_int_rm; trap = 0; @@ -419,6 +395,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() @@ -521,6 +499,216 @@ int oldi; uint32_t testr[9]; int dontprint=0; +void enter_smm() +{ + uint32_t smram_state = smbase + 0xfe00; + uint32_t old_cr0 = cr0; + uint32_t old_flags = cpu_state.flags | ((uint32_t)cpu_state.eflags << 16); + + cr0 &= ~0x8000000d; + cpu_state.flags = 2; + cpu_state.eflags = 0; + + in_smm = 1; + smi_latched = 1; + + mem_writel_phys(smram_state + 0xf8, smbase); + mem_writel_phys(smram_state + 0x128, cr4); + mem_writel_phys(smram_state + 0x130, cpu_state.seg_es.limit); + mem_writel_phys(smram_state + 0x134, cpu_state.seg_es.base); + mem_writel_phys(smram_state + 0x138, cpu_state.seg_es.access); + mem_writel_phys(smram_state + 0x13c, cpu_state.seg_cs.limit); + mem_writel_phys(smram_state + 0x140, cpu_state.seg_cs.base); + mem_writel_phys(smram_state + 0x144, cpu_state.seg_cs.access); + mem_writel_phys(smram_state + 0x148, cpu_state.seg_ss.limit); + mem_writel_phys(smram_state + 0x14c, cpu_state.seg_ss.base); + mem_writel_phys(smram_state + 0x150, cpu_state.seg_ss.access); + mem_writel_phys(smram_state + 0x154, cpu_state.seg_ds.limit); + mem_writel_phys(smram_state + 0x158, cpu_state.seg_ds.base); + mem_writel_phys(smram_state + 0x15c, cpu_state.seg_ds.access); + mem_writel_phys(smram_state + 0x160, cpu_state.seg_fs.limit); + mem_writel_phys(smram_state + 0x164, cpu_state.seg_fs.base); + mem_writel_phys(smram_state + 0x168, cpu_state.seg_fs.access); + mem_writel_phys(smram_state + 0x16c, cpu_state.seg_gs.limit); + mem_writel_phys(smram_state + 0x170, cpu_state.seg_gs.base); + mem_writel_phys(smram_state + 0x174, cpu_state.seg_gs.access); + mem_writel_phys(smram_state + 0x178, ldt.limit); + mem_writel_phys(smram_state + 0x17c, ldt.base); + mem_writel_phys(smram_state + 0x180, ldt.access); + mem_writel_phys(smram_state + 0x184, gdt.limit); + mem_writel_phys(smram_state + 0x188, gdt.base); + mem_writel_phys(smram_state + 0x18c, gdt.access); + mem_writel_phys(smram_state + 0x190, idt.limit); + mem_writel_phys(smram_state + 0x194, idt.base); + mem_writel_phys(smram_state + 0x198, idt.access); + mem_writel_phys(smram_state + 0x19c, tr.limit); + mem_writel_phys(smram_state + 0x1a0, tr.base); + mem_writel_phys(smram_state + 0x1a4, tr.access); + + mem_writel_phys(smram_state + 0x1a8, cpu_state.seg_es.seg); + mem_writel_phys(smram_state + 0x1ac, cpu_state.seg_cs.seg); + mem_writel_phys(smram_state + 0x1b0, cpu_state.seg_ss.seg); + mem_writel_phys(smram_state + 0x1b4, cpu_state.seg_ds.seg); + mem_writel_phys(smram_state + 0x1b8, cpu_state.seg_fs.seg); + mem_writel_phys(smram_state + 0x1bc, cpu_state.seg_gs.seg); + mem_writel_phys(smram_state + 0x1c0, ldt.seg); + mem_writel_phys(smram_state + 0x1c4, tr.seg); + + mem_writel_phys(smram_state + 0x1c8, dr[7]); + mem_writel_phys(smram_state + 0x1cc, dr[6]); + mem_writel_phys(smram_state + 0x1d0, EAX); + mem_writel_phys(smram_state + 0x1d4, ECX); + mem_writel_phys(smram_state + 0x1d8, EDX); + mem_writel_phys(smram_state + 0x1dc, EBX); + mem_writel_phys(smram_state + 0x1e0, ESP); + mem_writel_phys(smram_state + 0x1e4, EBP); + mem_writel_phys(smram_state + 0x1e8, ESI); + mem_writel_phys(smram_state + 0x1ec, EDI); + mem_writel_phys(smram_state + 0x1f0, cpu_state.pc); + mem_writel_phys(smram_state + 0x1d0, old_flags); + mem_writel_phys(smram_state + 0x1f8, cr3); + mem_writel_phys(smram_state + 0x1fc, old_cr0); + + ds = es = fs_seg = gs = ss = 0; + + DS = ES = FS = GS = SS = 0; + + cpu_state.seg_ds.limit = cpu_state.seg_es.limit = cpu_state.seg_fs.limit = cpu_state.seg_gs.limit + = cpu_state.seg_ss.limit = 0xffffffff; + + cpu_state.seg_ds.limit_high = cpu_state.seg_es.limit_high = cpu_state.seg_fs.limit_high + = cpu_state.seg_gs.limit_high = cpu_state.seg_ss.limit_high = 0xffffffff; + + cpu_state.seg_ds.limit_low = cpu_state.seg_es.limit_low = cpu_state.seg_fs.limit_low + = cpu_state.seg_gs.limit_low = cpu_state.seg_ss.limit_low = 0; + + cpu_state.seg_ds.access = cpu_state.seg_es.access = cpu_state.seg_fs.access + = cpu_state.seg_gs.access = cpu_state.seg_ss.access = 0x93; + + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked + = cpu_state.seg_gs.checked = cpu_state.seg_ss.checked = 1; + + CS = 0x3000; + cs = smbase; + cpu_state.seg_cs.limit = cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.access = 0x93; + cpu_state.seg_cs.checked = 1; + + cr4 = 0; + dr[7] = 0x400; + cpu_state.pc = 0x8000; + + nmi_mask = 0; +} + +void leave_smm() +{ + uint32_t smram_state = smbase + 0xfe00; + + smbase = mem_readl_phys(smram_state + 0xf8); + cr4 = mem_readl_phys(smram_state + 0x128); + + cpu_state.seg_es.limit = cpu_state.seg_es.limit_high = mem_readl_phys(smram_state + 0x130); + cpu_state.seg_es.base = mem_readl_phys(smram_state + 0x134); + cpu_state.seg_es.limit_low = cpu_state.seg_es.base; + cpu_state.seg_es.access = mem_readl_phys(smram_state + 0x138); + + cpu_state.seg_cs.limit = cpu_state.seg_cs.limit_high = mem_readl_phys(smram_state + 0x13c); + cpu_state.seg_cs.base = mem_readl_phys(smram_state + 0x140); + cpu_state.seg_cs.limit_low = cpu_state.seg_cs.base; + cpu_state.seg_cs.access = mem_readl_phys(smram_state + 0x144); + + cpu_state.seg_ss.limit = cpu_state.seg_ss.limit_high = mem_readl_phys(smram_state + 0x148); + cpu_state.seg_ss.base = mem_readl_phys(smram_state + 0x14c); + cpu_state.seg_ss.limit_low = cpu_state.seg_ss.base; + cpu_state.seg_ss.access = mem_readl_phys(smram_state + 0x150); + + cpu_state.seg_ds.limit = cpu_state.seg_ds.limit_high = mem_readl_phys(smram_state + 0x154); + cpu_state.seg_ds.base = mem_readl_phys(smram_state + 0x158); + cpu_state.seg_ds.limit_low = cpu_state.seg_ds.base; + cpu_state.seg_ds.access = mem_readl_phys(smram_state + 0x15c); + + cpu_state.seg_fs.limit = cpu_state.seg_fs.limit_high = mem_readl_phys(smram_state + 0x160); + cpu_state.seg_fs.base = mem_readl_phys(smram_state + 0x164); + cpu_state.seg_fs.limit_low = cpu_state.seg_fs.base; + cpu_state.seg_fs.access = mem_readl_phys(smram_state + 0x168); + + cpu_state.seg_gs.limit = cpu_state.seg_gs.limit_high = mem_readl_phys(smram_state + 0x16c); + cpu_state.seg_gs.base = mem_readl_phys(smram_state + 0x170); + cpu_state.seg_gs.limit_low = cpu_state.seg_gs.base; + cpu_state.seg_gs.access = mem_readl_phys(smram_state + 0x174); + + ldt.limit = ldt.limit_high = mem_readl_phys(smram_state + 0x178); + ldt.base = mem_readl_phys(smram_state + 0x17c); + ldt.limit_low = ldt.base; + ldt.access = mem_readl_phys(smram_state + 0x180); + + gdt.limit = gdt.limit_high = mem_readl_phys(smram_state + 0x184); + gdt.base = mem_readl_phys(smram_state + 0x188); + gdt.limit_low = gdt.base; + gdt.access = mem_readl_phys(smram_state + 0x18c); + + idt.limit = idt.limit_high = mem_readl_phys(smram_state + 0x190); + idt.base = mem_readl_phys(smram_state + 0x194); + idt.limit_low = idt.base; + idt.access = mem_readl_phys(smram_state + 0x198); + + tr.limit = tr.limit_high = mem_readl_phys(smram_state + 0x19c); + tr.base = mem_readl_phys(smram_state + 0x1a0); + tr.limit_low = tr.base; + tr.access = mem_readl_phys(smram_state + 0x1a4); + + ES = mem_readl_phys(smram_state + 0x1a8); + CS = mem_readl_phys(smram_state + 0x1ac); + SS = mem_readl_phys(smram_state + 0x1b0); + DS = mem_readl_phys(smram_state + 0x1b4); + FS = mem_readl_phys(smram_state + 0x1b8); + GS = mem_readl_phys(smram_state + 0x1bc); + ldt.seg = mem_readl_phys(smram_state + 0x1c0); + tr.seg = mem_readl_phys(smram_state + 0x1c4); + + dr[7] = mem_readl_phys(smram_state + 0x1c8); + dr[6] = mem_readl_phys(smram_state + 0x1cc); + EAX = mem_readl_phys(smram_state + 0x1d0); + ECX = mem_readl_phys(smram_state + 0x1d4); + EDX = mem_readl_phys(smram_state + 0x1d8); + EBX = mem_readl_phys(smram_state + 0x1dc); + ESP = mem_readl_phys(smram_state + 0x1e0); + EBP = mem_readl_phys(smram_state + 0x1e4); + ESI = mem_readl_phys(smram_state + 0x1e8); + EDI = mem_readl_phys(smram_state + 0x1ec); + + cpu_state.pc = mem_readl_phys(smram_state + 0x1f0); + uint32_t new_flags = mem_readl_phys(smram_state + 0x1f4); + cpu_state.flags = new_flags & 0xffff; + cpu_state.eflags = new_flags >> 16; + cr3 = mem_readl_phys(smram_state + 0x1f8); + cr0 = mem_readl_phys(smram_state + 0x1fc); + + cpu_state.seg_cs.access &= ~0x60; + cpu_state.seg_cs.access |= cpu_state.seg_ss.access & 0x60; //cpl is dpl of ss + + if((cr0 & 1) && !(cpu_state.eflags&VM_FLAG)) + { + cpu_state.seg_cs.checked = CS ? 1 : 0; + cpu_state.seg_ds.checked = DS ? 1 : 0; + cpu_state.seg_es.checked = ES ? 1 : 0; + cpu_state.seg_fs.checked = FS ? 1 : 0; + cpu_state.seg_gs.checked = GS ? 1 : 0; + cpu_state.seg_ss.checked = SS ? 1 : 0; + } + else + { + cpu_state.seg_cs.checked = cpu_state.seg_ds.checked = cpu_state.seg_es.checked + = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = cpu_state.seg_ss.checked = 1; + } + + in_smm = 0; + + nmi_mask = 1; +} + #define OP_TABLE(name) ops_ ## name #define CLOCK_CYCLES(c) cycles -= (c) #define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) @@ -528,14 +716,14 @@ int dontprint=0; #include "386_ops.h" -#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(flags & T_FLAG)) +#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(cpu_state.flags & T_FLAG)) #ifdef USE_DYNAREC static int cycles_main = 0; void exec386_dynarec(int cycs) { - uint8_t temp; + int vector; uint32_t addr; int tempi; int cycdiff; @@ -552,7 +740,6 @@ void exec386_dynarec(int cycs) cycles += cyc_period; cycles_start = cycles; - timer_start_period(cycles << TIMER_SHIFT); while (cycles>0) { oldcs = CS; @@ -571,18 +758,18 @@ void exec386_dynarec(int cycs) { oldcs=CS; cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; + oldcpl = CPL; cpu_state.op32 = use32; - 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; - fetchdat >>= 8; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; cpu_state.pc++; x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); @@ -599,6 +786,10 @@ void exec386_dynarec(int cycs) ss=oldss; ssegs=0; }*/ + + if (in_smm && smi_line && is_pentium) + CPU_BLOCK_END(); + if (cpu_state.abrt) CPU_BLOCK_END(); if (trap) @@ -621,7 +812,7 @@ void exec386_dynarec(int cycs) int hash = HASH(phys_addr); codeblock_t *block = codeblock_hash[hash]; int valid_block = 0; - trap = 0; + trap = 0; if (block && !cpu_state.abrt) { @@ -718,18 +909,18 @@ inrecomp=0; { oldcs=CS; cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; + oldcpl = CPL; cpu_state.op32 = use32; - 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; - fetchdat >>= 8; + { + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; cpu_state.pc++; @@ -749,6 +940,9 @@ inrecomp=0; hit, as host block size is only 2kB*/ if ((cpu_state.pc - start_pc) > 1000) CPU_BLOCK_END(); + + if (in_smm && smi_line && is_pentium) + CPU_BLOCK_END(); if (trap) CPU_BLOCK_END(); @@ -788,20 +982,20 @@ inrecomp=0; { oldcs=CS; cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; + oldcpl = CPL; cpu_state.op32 = use32; - cpu_state.ea_seg = &_ds; + 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) - { - trap = flags & T_FLAG; - opcode = fetchdat & 0xFF; - fetchdat >>= 8; + { + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; cpu_state.pc++; @@ -819,7 +1013,10 @@ inrecomp=0; hit, as host block size is only 2kB*/ if ((cpu_state.pc - start_pc) > 1000) CPU_BLOCK_END(); - + + if (in_smm && smi_line && is_pentium) + CPU_BLOCK_END(); + if (trap) CPU_BLOCK_END(); @@ -858,21 +1055,29 @@ inrecomp=0; cpu_state.abrt = 0; CS = oldcs; cpu_state.pc = cpu_state.oldpc; +#ifdef ENABLE_386_DYNAREC_LOG x386_dynarec_log("Double fault %i\n", ins); +#endif pmodeint(8, 0); if (cpu_state.abrt) { cpu_state.abrt = 0; softresetx86(); cpu_set_edx(); +#ifdef ENABLE_386_DYNAREC_LOG x386_dynarec_log("Triple fault - reset\n"); +#endif } } } + if (in_smm && smi_line && is_pentium) + { + enter_smm(); + } + if (trap) { - flags_rebuild(); if (msw&1) { @@ -880,13 +1085,13 @@ inrecomp=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)); } @@ -903,35 +1108,37 @@ inrecomp=0; nmi = 0; } } - else if ((flags&I_FLAG) && pic_intpending) + else if ((cpu_state.flags&I_FLAG) && pic_intpending) { - temp=picinterrupt(); - if (temp!=0xFF) + vector=picinterrupt(); + if (vector!=-1) { CPU_BLOCK_END(); flags_rebuild(); if (msw&1) { - pmodeint(temp,0); + pmodeint(vector,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; - flags&=~I_FLAG; - flags&=~T_FLAG; - oxpc=cpu_state.pc; + addr=vector<<2; + cpu_state.flags&=~I_FLAG; + cpu_state.flags&=~T_FLAG; + oxpc=cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); } } } } - timer_end_period(cycles << TIMER_SHIFT); - cycles_main -= (cycles_start - cycles); + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); + + cycles_main -= (cycles_start - cycles); } } #endif diff --git a/src/cpu/386_dynarec_ops.c b/src/cpu/386_dynarec_ops.c index d3dd4688d..aa4784ba8 100644 --- a/src/cpu/386_dynarec_ops.c +++ b/src/cpu/386_dynarec_ops.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -23,14 +24,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; @@ -46,7 +43,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; diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index d961bd4ac..fa2ed4d83 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -8,7 +8,7 @@ * * 286/386+ instruction handlers list. * - * Version: @(#)386_ops.h 1.0.3 2018/05/21 + * Version: @(#)386_ops.h 1.0.5 2018/10/17 * * Authors: Fred N. van Kempen, * Sarah Walker, @@ -176,6 +176,14 @@ static int internal_illegal(char *s) } #endif +#ifdef ENABLE_386_DYNAREC_LOG +extern void x386_dynarec_log(const char *fmt, ...); +#else +#ifndef x386_dynarec_log +#define x386_dynarec_log(fmt, ...) +#endif +#endif + #include "x86seg.h" #if defined(DEV_BRANCH) && defined(USE_AMD_K) # include "x86_ops_amd.h" @@ -643,7 +651,7 @@ const 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, @@ -665,7 +673,7 @@ const 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, @@ -687,7 +695,7 @@ const 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, @@ -709,7 +717,7 @@ const 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, @@ -734,7 +742,7 @@ const 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, @@ -756,7 +764,7 @@ const 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, @@ -778,7 +786,7 @@ const 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, @@ -800,7 +808,7 @@ const 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, @@ -826,7 +834,7 @@ const OpFn OP_TABLE(k6_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, @@ -848,7 +856,7 @@ const OpFn OP_TABLE(k6_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, @@ -870,7 +878,7 @@ const OpFn OP_TABLE(k6_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, @@ -892,7 +900,7 @@ const OpFn OP_TABLE(k6_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, @@ -902,6 +910,7 @@ const OpFn OP_TABLE(k6_0f)[1024] = }; #endif +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) const OpFn OP_TABLE(c6x86mx_0f)[1024] = { /*16-bit data, 16-bit addr*/ @@ -918,7 +927,7 @@ const OpFn OP_TABLE(c6x86mx_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, @@ -940,7 +949,7 @@ const OpFn OP_TABLE(c6x86mx_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, @@ -962,7 +971,7 @@ const OpFn OP_TABLE(c6x86mx_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, @@ -984,7 +993,7 @@ const OpFn OP_TABLE(c6x86mx_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, @@ -992,6 +1001,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = /*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, }; +#endif #ifdef DEV_BRANCH #ifdef USE_I686 @@ -1011,7 +1021,7 @@ const OpFn OP_TABLE(pentiumpro_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, @@ -1033,7 +1043,7 @@ const OpFn OP_TABLE(pentiumpro_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, @@ -1055,7 +1065,7 @@ const OpFn OP_TABLE(pentiumpro_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, @@ -1077,7 +1087,7 @@ const OpFn OP_TABLE(pentiumpro_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, @@ -1103,7 +1113,7 @@ const OpFn OP_TABLE(pentium2_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, @@ -1125,7 +1135,7 @@ const OpFn OP_TABLE(pentium2_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, @@ -1147,7 +1157,7 @@ const OpFn OP_TABLE(pentium2_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, @@ -1169,7 +1179,7 @@ const OpFn OP_TABLE(pentium2_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, @@ -1195,7 +1205,7 @@ const OpFn OP_TABLE(pentium2d_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,opFXSAVESTOR_a16,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,opFXSAVESTOR_a16,opIMUL_w_w_a16, /*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, /*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, @@ -1217,7 +1227,7 @@ const OpFn OP_TABLE(pentium2d_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,opFXSAVESTOR_a16,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,opFXSAVESTOR_a16,opIMUL_l_l_a16, /*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, /*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, @@ -1239,7 +1249,7 @@ const OpFn OP_TABLE(pentium2d_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,opFXSAVESTOR_a32,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,opFXSAVESTOR_a32,opIMUL_w_w_a32, /*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, /*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, @@ -1261,7 +1271,7 @@ const OpFn OP_TABLE(pentium2d_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,opFXSAVESTOR_a32,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,opFXSAVESTOR_a32,opIMUL_l_l_a32, /*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, /*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 53e2403cc..bf028eeaa 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1,49 +1,23 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * - * 808x CPU emulation. + * 808x CPU emulation, mostly ported from reenigne's XTCE, which + * is cycle-accurate. * - * SHR AX,1 + * Version: @(#)808x.c 1.0.11 2019/10/21 * - * 4 clocks - fetch opcode - * 4 clocks - fetch mod/rm - * 2 clocks - execute 2 clocks - fetch opcode 1 - * 2 clocks - fetch opcode 2 - * 4 clocks - fetch mod/rm - * 2 clocks - fetch opcode 1 2 clocks - execute - * 2 clocks - fetch opcode 2 etc - * - * Version: @(#)808x.c 1.0.5 2018/04/29 - * - * Authors: Sarah Walker, + * Authors: Andrew Jenner, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * - * 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. + * Copyright 2015-2019 Andrew Jenner. + * Copyright 2016-2019 Miran Grca. */ +#include #include #include #include @@ -60,39 +34,112 @@ #include "../nmi.h" #include "../pic.h" #include "../timer.h" -#include "../plat.h" + +/* The opcode of the instruction currently being executed. */ +uint8_t opcode; + +/* The tables to speed up the setting of the Z, N, and P cpu_state.flags. */ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +/* A 16-bit zero, needed because some speed-up arrays contain pointers to it. */ +uint16_t zero = 0; + +/* MOD and R/M stuff. */ +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; +uint32_t rmdat; + +/* XT CPU multiplier. */ +uint64_t xt_cpu_multi; + +/* Is the CPU 8088 or 8086. */ +int is8086 = 0; + +/* Variables for handling the non-maskable interrupts. */ +int nmi = 0, nmi_auto_clear = 0; +int nmi_enable = 1; + +/* Was the CPU ever reset? */ +int x86_was_reset = 0; + +/* Amount of instructions executed - used to calculate the % shown in the title bar. */ +int ins = 0; + +/* Is the TRAP flag on? */ +int trap = 0; + +/* The current effective address's segment. */ +uint32_t easeg; -int xt_cpu_multi; -int nmi = 0; -int nmi_auto_clear = 0; +/* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */ +static uint8_t pfq[6]; -int nextcyc=0; -int cycdiff; -int is8086=0; +/* Variables to aid with the prefetch queue operation. */ +static int biu_cycles = 0, pfq_pos = 0; -int memcycs; -int nopageerrors=0; +/* The IP equivalent of the current prefetch queue position. */ +static uint16_t pfq_ip; -void FETCHCOMPLETE(); +/* Pointer tables needed for segment overrides. */ +static uint32_t *opseg[4]; +static x86seg *_opseg[4]; -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 noint = 0; +static int in_lock = 0; +static int cpu_alu_op, pfq_size; + +static uint16_t cpu_src = 0, cpu_dest = 0; +static uint16_t cpu_data = 0, last_addr = 0x0000; + +static uint32_t *ovr_seg = NULL; +static int prefetching = 1, completed = 1; +static int in_rep = 0, repeating = 0; +static int oldc, clear_lock = 0; +static int refresh = 0, takeint = 0; +static int cycdiff; + + +/* Various things needed for 8087. */ +#define OP_TABLE(name) ops_ ## name + +#define CPU_BLOCK_END() +#define SEG_CHECK_READ(seg) +#define SEG_CHECK_WRITE(seg) +#define CHECK_READ(a, b, c) +#define CHECK_WRITE(a, b, c) +#define UN_USED(x) (void)(x) +#define fetch_ea_16(val) +#define fetch_ea_32(val) +#define PREFETCH_RUN(a, b, c, d, e, f, g, h) + +#define CYCLES(val) \ + { \ + wait(val, 0); \ + } + +#define CLOCK_CYCLES(val) \ + { \ + wait(val, 0); \ + } + +typedef int (*OpFn)(uint32_t fetchdat); + + +static int tempc_fpu = 0; #ifdef ENABLE_808X_LOG +void dumpregs(int); + int x808x_do_log = ENABLE_808X_LOG; -#endif +int indump = 0; static void x808x_log(const char *fmt, ...) { -#ifdef ENABLE_808X_LOG va_list ap; if (x808x_do_log) { @@ -100,380 +147,558 @@ x808x_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } +} + + +void +dumpregs(int force) +{ + int c; + char *seg_names[4] = { "ES", "CS", "SS", "DS" }; + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) + return; + + x808x_log("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", + cpu_state.pc, CS, DS, ES, SS, cpu_state.flags); + x808x_log("Old CS:EIP: %04X:%08X; %i ins\n", oldcs, cpu_state.oldpc, ins); + for (c = 0; c < 4; c++) { + x808x_log("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_names[c], _opseg[c]->base, _opseg[c]->limit, + _opseg[c]->access, _opseg[c]->limit_low, _opseg[c]->limit_high); + } + if (is386) { + x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_fs, cpu_state.seg_fs.limit, cpu_state.seg_fs.access, cpu_state.seg_fs.limit_low, cpu_state.seg_fs.limit_high); + x808x_log("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); + x808x_log("GDT : base=%06X limit=%04X\n", gdt.base, gdt.limit); + x808x_log("LDT : base=%06X limit=%04X\n", ldt.base, ldt.limit); + x808x_log("IDT : base=%06X limit=%04X\n", idt.base, idt.limit); + x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + x808x_log("386 in %s mode: %i-bit data, %-i-bit stack\n", + (msw & 1) ? ((cpu_state.eflags & VM_FLAG) ? "V86" : "protected") : "real", + (use32) ? 32 : 16, (stack32) ? 32 : 16); + x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); + x808x_log("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 { + x808x_log("808x/286 in %s mode\n", (msw & 1) ? "protected" : "real"); + x808x_log("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); + } + x808x_log("Entries in readlookup : %i writelookup : %i\n", readlnum, writelnum); + x87_dumpregs(); + indump = 0; +} +#else +#define x808x_log(fmt, ...) #endif + + +static void pfq_add(int c, int add); +static void set_pzs(int bits); + + +uint16_t +get_last_addr(void) +{ + return last_addr; +} + + +static int +irq_pending(void) +{ + uint8_t temp; + + if (takeint && !noint) + temp = 1; + else + temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint); + + takeint = (cpu_state.flags & I_FLAG) && (pic.pend &~ pic.mask); + + return temp; +} + + +static void +clock_start(void) +{ + cycdiff = cycles; +} + + +static void +clock_end(void) +{ + int diff = cycdiff - cycles; + + /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ + tsc += (uint64_t)diff * ((uint64_t)xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); +} + + +static void +fetch_and_bus(int c, int bus) +{ + if (refresh > 0) { + /* Finish the current fetch, if any. */ + cycles -= ((4 - (biu_cycles & 3)) & 3); + pfq_add((4 - (biu_cycles & 3)) & 3, 1); + /* Add 4 memory access cycles. */ + cycles -= 4; + pfq_add(4, 0); + + refresh--; + } + + pfq_add(c, !bus); + if (bus < 2) { + clock_end(); + clock_start(); + } +} + + +static void +wait(int c, int bus) +{ + cycles -= c; + + fetch_and_bus(c, bus); +} + + +/* This is for external subtraction of cycles. */ +void +sub_cycles(int c) +{ + if (c <= 0) + return; + + cycles -= c; + + if (!is286) + fetch_and_bus(c, 2); } #undef readmemb #undef readmemw -uint8_t readmemb(uint32_t a) +#undef readmeml +#undef readmemq + +/* Common read function. */ +static uint8_t +readmemb_common(uint32_t a) { - if (a!=(cs+cpu_state.pc)) memcycs+=4; - if (readlookup2 == NULL) return readmembl(a); - if (readlookup2[(a)>>12]==-1) return readmembl(a); - else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); + uint8_t ret; + + if (readlookup2 == NULL) + ret = readmembl(a); + else { + if (readlookup2[(a) >> 12] == ((uintptr_t) -1)) + ret = readmembl(a); + else + ret = *(uint8_t *)(readlookup2[(a) >> 12] + (a)); + } + + return ret; } -uint8_t readmembf(uint32_t a) +/* Reads a byte from the memory and advances the BIU. */ +static uint8_t +readmemb(uint32_t a) { - if (readlookup2 == NULL) return readmembl(a); - if (readlookup2[(a)>>12]==-1) return readmembl(a); - else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); -} + uint8_t ret; -uint16_t readmemw(uint32_t s, uint16_t a) -{ - if (a!=(cs+cpu_state.pc)) memcycs+=(8>>is8086); - if (readlookup2 == NULL) 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); -} + wait(4, 1); + ret = readmemb_common(a); -void refreshread() { FETCHCOMPLETE(); memcycs+=4; } - -#undef fetchea -#define fetchea() { rmdat=FETCH(); \ - cpu_reg=(rmdat>>3)&7; \ - cpu_mod=(rmdat>>6)&3; \ - 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) -{ - memcycs+=4; - if (writelookup2 == NULL) writemembl(a,v); - if (writelookup2[(a)>>12]==-1) writemembl(a,v); - else *(uint8_t *)(writelookup2[a >> 12] + a) = v; -} -void writememwl(uint32_t seg, uint32_t addr, uint16_t val); -void writememw(uint32_t s, uint32_t a, uint16_t v) -{ - memcycs+=(8>>is8086); - if (writelookup2 == NULL) 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 == NULL) writememll(s,a,v); - if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememll(s,a,v); - else *(uint32_t *)(writelookup2[(s + a) >> 12] + s + a) = v; + return ret; } -void dumpregs(int); -uint16_t oldcs; -int oldcpl; - -int tempc; -uint8_t opcode; -uint16_t pc2,pc3; -int noint=0; - -int output=0; - -#if 0 -/* Also in mem.c */ -int shadowbios=0; -#endif - -int ins=0; - -int fetchcycles=0,memcycs,fetchclocks; - -uint8_t prefetchqueue[6]; -uint16_t prefetchpc; -int prefetchw=0; -static __inline uint8_t FETCH() +/* Reads a byte from the memory but does not advance the BIU. */ +static uint8_t +readmembf(uint32_t a) { - uint8_t temp; -/* temp=prefetchqueue[0]; - prefetchqueue[0]=prefetchqueue[1]; - prefetchqueue[1]=prefetchqueue[2]; - prefetchqueue[2]=prefetchqueue[3]; - prefetchqueue[3]=prefetchqueue[4]; - prefetchqueue[4]=prefetchqueue[5]; - if (prefetchw<=((is8086)?4:3)) - { - prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; - if (is8086 && (prefetchpc&1)) - { - prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; - } - }*/ + uint8_t ret; - if (prefetchw==0) - { - cycles-=(4-(fetchcycles&3)); - fetchclocks+=(4-(fetchcycles&3)); - fetchcycles=4; - temp=readmembf(cs+cpu_state.pc); - prefetchpc = cpu_state.pc = cpu_state.pc + 1; - if (is8086 && (cpu_state.pc&1)) - { - prefetchqueue[0]=readmembf(cs+cpu_state.pc); - prefetchpc++; - prefetchw++; - } - } - else - { - temp=prefetchqueue[0]; - prefetchqueue[0]=prefetchqueue[1]; - prefetchqueue[1]=prefetchqueue[2]; - prefetchqueue[2]=prefetchqueue[3]; - prefetchqueue[3]=prefetchqueue[4]; - prefetchqueue[4]=prefetchqueue[5]; - prefetchw--; - fetchcycles-=4; - cpu_state.pc++; - } - return temp; -} + a = cs + (a & 0xffff); + ret = readmemb_common(a); -static __inline void FETCHADD(int c) -{ - int d; - if (c<0) return; - if (prefetchw>((is8086)?4:3)) return; - d=c+(fetchcycles&3); - while (d>3 && prefetchw<((is8086)?6:4)) - { - d-=4; - if (is8086 && !(prefetchpc&1)) - { - prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw++; - } - if (prefetchw<6) - { - prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw++; - } - } - fetchcycles+=c; - if (fetchcycles>16) fetchcycles=16; -} - -void FETCHCOMPLETE() -{ - if (!(fetchcycles&3)) return; - if (prefetchw>((is8086)?4:3)) return; - if (!prefetchw) nextcyc=(4-(fetchcycles&3)); - cycles-=(4-(fetchcycles&3)); - fetchclocks+=(4-(fetchcycles&3)); - if (is8086 && !(prefetchpc&1)) - { - prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw++; - } - if (prefetchw<6) - { - prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); - prefetchpc++; - prefetchw++; - } - fetchcycles+=(4-(fetchcycles&3)); -} - -static __inline void FETCHCLEAR() -{ - prefetchpc=cpu_state.pc; - prefetchw=0; - memcycs=cycdiff-cycles; - fetchclocks=0; -} - -static uint16_t getword() -{ - uint8_t temp=FETCH(); - return temp|(FETCH()<<8); + return ret; } -/*EA calculation*/ - -/*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod - From 386 programmers manual : -r8(/r) AL CL DL BL AH CH DH BH -r16(/r) AX CX DX BX SP BP SI DI -r32(/r) EAX ECX EDX EBX ESP EBP ESI EDI -/digit (Opcode) 0 1 2 3 4 5 6 7 -REG = 000 001 010 011 100 101 110 111 - ����Address -disp8 denotes an 8-bit displacement following the ModR/M byte, to be -sign-extended and added to the index. disp16 denotes a 16-bit displacement -following the ModR/M byte, to be added to the index. Default segment -register is SS for the effective addresses containing a BP index, DS for -other effective addresses. - �Ŀ �Mod R/M� ���������ModR/M Values in Hexadecimal�������Ŀ - -[BX + SI] 000 00 08 10 18 20 28 30 38 -[BX + DI] 001 01 09 11 19 21 29 31 39 -[BP + SI] 010 02 0A 12 1A 22 2A 32 3A -[BP + DI] 011 03 0B 13 1B 23 2B 33 3B -[SI] 00 100 04 0C 14 1C 24 2C 34 3C -[DI] 101 05 0D 15 1D 25 2D 35 3D -disp16 110 06 0E 16 1E 26 2E 36 3E -[BX] 111 07 0F 17 1F 27 2F 37 3F - -[BX+SI]+disp8 000 40 48 50 58 60 68 70 78 -[BX+DI]+disp8 001 41 49 51 59 61 69 71 79 -[BP+SI]+disp8 010 42 4A 52 5A 62 6A 72 7A -[BP+DI]+disp8 011 43 4B 53 5B 63 6B 73 7B -[SI]+disp8 01 100 44 4C 54 5C 64 6C 74 7C -[DI]+disp8 101 45 4D 55 5D 65 6D 75 7D -[BP]+disp8 110 46 4E 56 5E 66 6E 76 7E -[BX]+disp8 111 47 4F 57 5F 67 6F 77 7F - -[BX+SI]+disp16 000 80 88 90 98 A0 A8 B0 B8 -[BX+DI]+disp16 001 81 89 91 99 A1 A9 B1 B9 -[BX+SI]+disp16 010 82 8A 92 9A A2 AA B2 BA -[BX+DI]+disp16 011 83 8B 93 9B A3 AB B3 BB -[SI]+disp16 10 100 84 8C 94 9C A4 AC B4 BC -[DI]+disp16 101 85 8D 95 9D A5 AD B5 BD -[BP]+disp16 110 86 8E 96 9E A6 AE B6 BE -[BX]+disp16 111 87 8F 97 9F A7 AF B7 BF - -EAX/AX/AL 000 C0 C8 D0 D8 E0 E8 F0 F8 -ECX/CX/CL 001 C1 C9 D1 D9 E1 E9 F1 F9 -EDX/DX/DL 010 C2 CA D2 DA E2 EA F2 FA -EBX/BX/BL 011 C3 CB D3 DB E3 EB F3 FB -ESP/SP/AH 11 100 C4 CC D4 DC E4 EC F4 FC -EBP/BP/CH 101 C5 CD D5 DD E5 ED F5 FD -ESI/SI/DH 110 C6 CE D6 DE E6 EE F6 FE -EDI/DI/BH 111 C7 CF D7 DF E7 EF F7 FF - -mod = 11 - register - 10 - address + 16 bit displacement - 01 - address + 8 bit displacement - 00 - address - -reg = If mod=11, (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit registers) - 0=AX/AL 1=CX/CL 2=DX/DL 3=BX/BL - 4=SP/AH 5=BP/CH 6=SI/DH 7=DI/BH - - Otherwise, LSB selects SI/DI (0=SI), NMSB selects BX/BP (0=BX), and MSB - selects whether BX/BP are used at all (0=used). - - mod=00 is an exception though - 6=16 bit displacement only - 7=[BX] - - Usage varies with instructions. - - MOV AL,BL has ModR/M as C3, for example. - mod=11, reg=0, r/m=3 - MOV uses reg as dest, and r/m as src. - reg 0 is AL, reg 3 is BL - - If BP or SP are in address calc, seg is SS, else DS -*/ - -uint32_t easeg; -int rmdat; - -uint16_t zero=0; -uint16_t *mod1add[2][8]; -uint32_t *mod1seg[8]; - -int slowrm[8]; - -void makemod1table() +/* Reads a word from the memory and advances the BIU. */ +static uint16_t +readmemw_common(uint32_t s, uint16_t a) { - mod1add[0][0]=&BX; mod1add[0][1]=&BX; mod1add[0][2]=&BP; mod1add[0][3]=&BP; - mod1add[0][4]=&SI; mod1add[0][5]=&DI; mod1add[0][6]=&BP; mod1add[0][7]=&BX; - mod1add[1][0]=&SI; mod1add[1][1]=&DI; mod1add[1][2]=&SI; mod1add[1][3]=&DI; - mod1add[1][4]=&zero; mod1add[1][5]=&zero; mod1add[1][6]=&zero; mod1add[1][7]=&zero; - slowrm[0]=0; slowrm[1]=1; slowrm[2]=1; slowrm[3]=0; - mod1seg[0]=&ds; mod1seg[1]=&ds; mod1seg[2]=&ss; mod1seg[3]=&ss; - mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds; + uint16_t ret; + + ret = readmemb_common(s + a); + ret |= readmemb_common(s + ((a + 1) & 0xffff)) << 8; + + return ret; } -static void fetcheal() -{ - if (!cpu_mod && cpu_rm==6) { cpu_state.eaaddr=getword(); easeg=ds; FETCHADD(6); } - else - { - switch (cpu_mod) - { - case 0: - cpu_state.eaaddr=0; - if (cpu_rm&4) FETCHADD(5); - else FETCHADD(7+slowrm[cpu_rm]); - break; - case 1: - cpu_state.eaaddr=(uint16_t)(int8_t)FETCH(); - if (cpu_rm&4) FETCHADD(9); - else FETCHADD(11+slowrm[cpu_rm]); - break; - case 2: - cpu_state.eaaddr=getword(); - if (cpu_rm&4) FETCHADD(9); - else FETCHADD(11+slowrm[cpu_rm]); - break; - } - cpu_state.eaaddr+=(*mod1add[0][cpu_rm])+(*mod1add[1][cpu_rm]); - easeg=*mod1seg[cpu_rm]; - cpu_state.eaaddr&=0xFFFF; - } - cpu_state.last_ea = cpu_state.eaaddr; +static uint16_t +readmemw(uint32_t s, uint16_t a) +{ + uint16_t ret; + + if (is8086 && !(a & 1)) + wait(4, 1); + else + wait(8, 1); + ret = readmemw_common(s, a); + + return ret; } -static __inline uint8_t geteab() + +static uint16_t +readmemwf(uint16_t a) { - if (cpu_mod == 3) - return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm & 3].b.l; - return readmemb(easeg+cpu_state.eaaddr); + uint16_t ret; + + ret = readmemw_common(cs, a & 0xffff); + + return ret; } -static __inline uint16_t geteaw() + +static uint16_t +readmem(uint32_t s) { - if (cpu_mod == 3) - return cpu_state.regs[cpu_rm].w; - return readmemw(easeg,cpu_state.eaaddr); + if (opcode & 1) + return readmemw(s, cpu_state.eaaddr); + else + return (uint16_t) readmemb(s + cpu_state.eaaddr); } -#if 0 -static __inline uint16_t geteaw2() -{ - if (cpu_mod == 3) - return cpu_state.regs[cpu_rm].w; - return readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); -} -#endif -static __inline void seteab(uint8_t val) +static uint32_t +readmeml(uint32_t s, uint16_t a) { - if (cpu_mod == 3) - { - if (cpu_rm & 4) - cpu_state.regs[cpu_rm & 3].b.h = val; - else - cpu_state.regs[cpu_rm & 3].b.l = val; - } - else - { - writememb(easeg+cpu_state.eaaddr,val); - } + uint32_t temp; + + temp = (uint32_t) (readmemw(s, a + 2)) << 16; + temp |= readmemw(s, a); + + return temp; } -static __inline void seteaw(uint16_t val) + +static uint64_t +readmemq(uint32_t s, uint16_t a) { - if (cpu_mod == 3) - cpu_state.regs[cpu_rm].w = val; - else - { - writememw(easeg,cpu_state.eaaddr,val); - } + uint64_t temp; + + temp = (uint64_t) (readmeml(s, a + 4)) << 32; + temp |= readmeml(s, a); + + return temp; } + +static void +writememb_common(uint32_t a, uint8_t v) +{ + if (writelookup2 == NULL) + writemembl(a, v); + else { + if (writelookup2[(a) >> 12] == ((uintptr_t) -1)) + writemembl(a, v); + else + *(uint8_t *)(writelookup2[a >> 12] + a) = v; + } + + if ((a >= 0xf0000) && (a <= 0xfffff)) + last_addr = a & 0xffff; +} + + +/* Writes a byte to the memory and advances the BIU. */ +static void +writememb(uint32_t s, uint32_t a, uint8_t v) +{ + wait(4, 1); + writememb_common(s + a, v); +} + + +/* Writes a word to the memory and advances the BIU. */ +static void +writememw(uint32_t s, uint32_t a, uint16_t v) +{ + if (is8086 && !(a & 1)) + wait(4, 1); + else + wait(8, 1); + writememb_common(s + a, v & 0xff); + writememb_common(s + ((a + 1) & 0xffff), v >> 8); +} + + +static void +writemem(uint32_t s, uint16_t v) +{ + if (opcode & 1) + return writememw(s, cpu_state.eaaddr, v); + else + return writememb(s, cpu_state.eaaddr, (uint8_t) (v & 0xff)); +} + + +static void +writememl(uint32_t s, uint32_t a, uint32_t v) +{ + writememw(s, a, v & 0xffff); + writememw(s, a + 2, v >> 16); +} + + +static void +writememq(uint32_t s, uint32_t a, uint64_t v) +{ + writememl(s, a, v & 0xffffffff); + writememl(s, a + 4, v >> 32); +} + + +static void +pfq_write(void) +{ + uint16_t tempw; + + if (is8086 && (pfq_pos < (pfq_size - 1))) { + /* The 8086 fetches 2 bytes at a time, and only if there's at least 2 bytes + free in the queue. */ + tempw = readmemwf(pfq_ip); + *(uint16_t *) &(pfq[pfq_pos]) = tempw; + pfq_ip += 2; + pfq_pos += 2; + } else if (!is8086 && (pfq_pos < pfq_size)) { + /* The 8088 fetches 1 byte at a time, and only if there's at least 1 byte + free in the queue. */ + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } +} + + +static uint8_t +pfq_read(void) +{ + uint8_t temp, i; + + temp = pfq[0]; + for (i = 0; i < (pfq_size - 1); i++) + pfq[i] = pfq[i + 1]; + pfq_pos--; + cpu_state.pc = (cpu_state.pc + 1) & 0xffff; + return temp; +} + + +/* Fetches a byte from the prefetch queue, or from memory if the queue has + been drained. */ +static uint8_t +pfq_fetchb_common(void) +{ + uint8_t temp; + + if (pfq_pos == 0) { + /* Reset prefetch queue internal position. */ + pfq_ip = cpu_state.pc; + /* Fill the queue. */ + wait(4 - (biu_cycles & 3), 0); + } + + /* Fetch. */ + temp = pfq_read(); + return temp; +} + + +static uint8_t +pfq_fetchb(void) +{ + uint8_t ret; + + ret = pfq_fetchb_common(); + wait(1, 0); + return ret; +} + + +/* Fetches a word from the prefetch queue, or from memory if the queue has + been drained. */ +static uint16_t +pfq_fetchw(void) +{ + uint16_t temp; + + temp = pfq_fetchb_common(); + wait(1, 0); + temp |= (pfq_fetchb_common() << 8); + + return temp; +} + + +static uint16_t +pfq_fetch() +{ + if (opcode & 1) + return pfq_fetchw(); + else + return (uint16_t) pfq_fetchb(); +} + + +/* Adds bytes to the prefetch queue based on the instruction's cycle count. */ +static void +pfq_add(int c, int add) +{ + int d; + + if ((c <= 0) || (pfq_pos >= pfq_size)) + return; + + for (d = 0; d < c; d++) { + biu_cycles = (biu_cycles + 1) & 0x03; + if (prefetching && add && (biu_cycles == 0x00)) + pfq_write(); + } +} + + +/* Clear the prefetch queue - called on reset and on anything that affects either CS or IP. */ +static void +pfq_clear() +{ + pfq_pos = 0; + prefetching = 0; +} + + +static void +set_ip(uint16_t new_ip) { + pfq_ip = cpu_state.pc = new_ip; + prefetching = 1; +} + + +/* Memory refresh read - called by reads and writes on DMA channel 0. */ +void +refreshread(void) { + refresh++; +} + + +/* Preparation of the various arrays needed to speed up the MOD and R/M work. */ +static void +makemod1table(void) +{ + mod1add[0][0] = &BX; + mod1add[0][1] = &BX; + mod1add[0][2] = &BP; + mod1add[0][3] = &BP; + mod1add[0][4] = &SI; + mod1add[0][5] = &DI; + mod1add[0][6] = &BP; + mod1add[0][7] = &BX; + mod1add[1][0] = &SI; + mod1add[1][1] = &DI; + mod1add[1][2] = &SI; + mod1add[1][3] = &DI; + mod1add[1][4] = &zero; + mod1add[1][5] = &zero; + mod1add[1][6] = &zero; + mod1add[1][7] = &zero; + mod1seg[0] = &ds; + mod1seg[1] = &ds; + mod1seg[2] = &ss; + mod1seg[3] = &ss; + mod1seg[4] = &ds; + mod1seg[5] = &ds; + mod1seg[6] = &ss; + mod1seg[7] = &ds; + opseg[0] = &es; + opseg[1] = &cs; + opseg[2] = &ss; + opseg[3] = &ds; + _opseg[0] = &cpu_state.seg_es; + _opseg[1] = &cpu_state.seg_cs; + _opseg[2] = &cpu_state.seg_ss; + _opseg[3] = &cpu_state.seg_ds; +} + + +static uint16_t +sign_extend(uint8_t data) +{ + return data + (data < 0x80 ? 0 : 0xff00); +} + + +/* Fetches the effective address from the prefetch queue according to MOD and R/M. */ +static void +do_mod_rm(void) +{ + rmdat = pfq_fetchb(); + cpu_reg = (rmdat >> 3) & 7; + cpu_mod = (rmdat >> 6) & 3; + cpu_rm = rmdat & 7; + + if (cpu_mod == 3) + return; + + wait(1, 0); + if ((rmdat & 0xc7) == 0x06) { + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + easeg = ovr_seg ? *ovr_seg : ds; + wait(1, 0); + return; + } else switch (cpu_rm) { + case 0: + case 3: + wait(2, 0); + break; + case 1: + case 2: + wait(3, 0); + break; + } + cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + easeg = ovr_seg ? *ovr_seg : *mod1seg[cpu_rm]; + switch (rmdat & 0xc0) { + case 0x40: + wait(3, 0); + cpu_state.eaaddr += sign_extend(pfq_fetchb()); + break; + case 0x80: + wait(3, 0); + cpu_state.eaaddr += pfq_fetchw(); + break; + } + cpu_state.eaaddr &= 0xffff; + wait(2, 0); +} + + #undef getr8 #define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) @@ -482,2843 +707,2187 @@ static __inline void seteaw(uint16_t val) else cpu_state.regs[r & 3].b.l = v; -/*Flags*/ -uint8_t znptable8[256]; -uint16_t znptable16[65536]; - -void makeznptable() +/* Reads a byte from the effective address. */ +static uint8_t +geteab(void) { - int c,d; - for (c=0;c<256;c++) - { - d=0; - if (c&1) d++; - if (c&2) d++; - if (c&4) d++; - if (c&8) d++; - if (c&16) d++; - if (c&32) d++; - if (c&64) d++; - if (c&128) d++; - if (d&1) - { - znptable8[c]=0; - } - else - { - znptable8[c]=P_FLAG; - } - if (c == 0xb1) x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); - if (!c) znptable8[c]|=Z_FLAG; - if (c&0x80) znptable8[c]|=N_FLAG; - } - for (c=0;c<65536;c++) - { - d=0; - if (c&1) d++; - if (c&2) d++; - if (c&4) d++; - if (c&8) d++; - if (c&16) d++; - if (c&32) d++; - if (c&64) d++; - if (c&128) d++; - if (d&1) - znptable16[c]=0; - else - znptable16[c]=P_FLAG; - if (c == 0xb1) x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); - if (c == 0x65b1) x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); - if (!c) znptable16[c]|=Z_FLAG; - if (c&0x8000) znptable16[c]|=N_FLAG; - } -} -#if 1 -/* Also in mem.c */ -int timetolive=0; -#endif + if (cpu_mod == 3) + return (getr8(cpu_rm)); -extern uint32_t oldcs2; -extern uint32_t oldpc2; - -int indump = 0; - -void dumpregs(int force) -{ - int c,d=0,e=0; -#ifndef RELEASE_BUILD - FILE *f; -#endif - - /* Only dump when needed, and only once.. */ - if (indump || (!force && !dump_on_exit)) return; - -#ifndef RELEASE_BUILD - indump = 1; - output=0; - (void)plat_chdir(usr_path); - nopageerrors=1; - f=fopen("ram.dmp","wb"); - fwrite(ram,mem_size*1024,1,f); - fclose(f); - x808x_log("Dumping rram.dmp\n"); - f=fopen("rram.dmp","wb"); - for (c=0;c<0x1000000;c++) putc(readmemb(c),f); - fclose(f); - x808x_log("Dumping rram4.dmp\n"); - f=fopen("rram4.dmp","wb"); - for (c=0;c<0x0050000;c++) - { - cpu_state.abrt = 0; - putc(readmemb386l(0,c+0x80000000),f); - } - fclose(f); - x808x_log("Dumping done\n"); -#endif - if (is386) - x808x_log("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 - x808x_log("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); - x808x_log("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,flags); - x808x_log("%04X:%04X %04X:%04X\n",oldcs,cpu_state.oldpc, oldcs2, oldpc2); - x808x_log("%i ins\n",ins); - if (is386) - x808x_log("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); - else - x808x_log("In %s mode\n",(msw&1)?"protected":"real"); - x808x_log("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); - x808x_log("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); - x808x_log("ES : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",es,_es.limit,_es.access, _es.limit_low, _es.limit_high); - if (is386) - { - x808x_log("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); - x808x_log("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); - } - x808x_log("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); - x808x_log("GDT : base=%06X limit=%04X\n",gdt.base,gdt.limit); - x808x_log("LDT : base=%06X limit=%04X\n",ldt.base,ldt.limit); - x808x_log("IDT : base=%06X limit=%04X\n",idt.base,idt.limit); - x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); - if (is386) - { - x808x_log("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); - x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n",cr0,cr2,cr3, cr4); - } - x808x_log("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); - for (c=0;c<1024*1024;c++) - { - if (readlookup2[c]!=0xFFFFFFFF) d++; - if (writelookup2[c]!=0xFFFFFFFF) e++; - } - x808x_log("Entries in readlookup : %i writelookup : %i\n",d,e); - x87_dumpregs(); - indump = 0; + return readmemb(easeg + cpu_state.eaaddr); } -int resets = 0; -int x86_was_reset = 0; -void resetx86() + +/* Reads a word from the effective address. */ +static uint16_t +geteaw(void) { - x808x_log("x86 reset\n"); - resets++; - ins = 0; - use32=0; - cpu_cur_status = 0; - stack32=0; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - msw=0; - if (is486) - cr0 = 1 << 30; - else - cr0 = 0; - cpu_cache_int_enabled = 0; - cpu_update_waitstates(); - cr4 = 0; - eflags=0; - cgate32=0; - 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; - idt.limit = is386 ? 0x03FF : 0xFFFF; - flags=2; - makeznptable(); - resetreadlookup(); - makemod1table(); - resetmcr(); - FETCHCLEAR(); - x87_reset(); - cpu_set_edx(); - EAX = 0; - ESP=0; - mmu_perm=4; - memset(inscounts, 0, sizeof(inscounts)); - x86seg_reset(); + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + + return readmemw(easeg, cpu_state.eaaddr); +} + + +/* Neede for 8087 - memory only. */ +static uint32_t +geteal(void) +{ + if (cpu_mod == 3) { + fatal("808x register geteal()\n"); + return 0xffffffff; + } + + return readmeml(easeg, cpu_state.eaaddr); +} + + +/* Neede for 8087 - memory only. */ +static uint64_t +geteaq(void) +{ + if (cpu_mod == 3) { + fatal("808x register geteaq()\n"); + return 0xffffffff; + } + + return readmemq(easeg, cpu_state.eaaddr); +} + + +static void +read_ea(int memory_only, int bits) +{ + if (cpu_mod != 3) { + if (bits == 16) + cpu_data = readmemw(easeg, cpu_state.eaaddr); + else + cpu_data = readmemb(easeg + cpu_state.eaaddr); + return; + } + if (!memory_only) { + if (bits == 8) { + cpu_data = getr8(cpu_rm); + } else + cpu_data = cpu_state.regs[cpu_rm].w; + } +} + + +static void +read_ea2(int bits) +{ + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + if (bits == 16) + cpu_data = readmemw(easeg, cpu_state.eaaddr); + else + cpu_data = readmemb(easeg + cpu_state.eaaddr); +} + + +/* Writes a byte to the effective address. */ +static void +seteab(uint8_t val) +{ + if (cpu_mod == 3) { + setr8(cpu_rm, val); + } else + writememb(easeg, cpu_state.eaaddr, val); +} + + +/* Writes a word to the effective address. */ +static void +seteaw(uint16_t val) +{ + if (cpu_mod == 3) + cpu_state.regs[cpu_rm].w = val; + else + writememw(easeg, cpu_state.eaaddr, val); +} + + +static void +seteal(uint32_t val) +{ + if (cpu_mod == 3) { + fatal("808x register seteal()\n"); + return; + } else + writememl(easeg, cpu_state.eaaddr, val); +} + + +static void +seteaq(uint64_t val) +{ + if (cpu_mod == 3) { + fatal("808x register seteaq()\n"); + return; + } else + writememq(easeg, cpu_state.eaaddr, val); +} + + +/* Leave out the 686 stuff as it's not needed and + complicates compiling. */ +#define FPU_8087 +#define tempc tempc_fpu +#include "x87.h" +#include "x87_ops.h" +#undef tempc +#undef FPU_8087 + + +/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P cpu_state.flags. */ +static void +makeznptable(void) +{ + int c, d, e; + for (c = 0; c < 256; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable8[c] = 0; + else + znptable8[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); +#endif + if (!c) + znptable8[c] |= Z_FLAG; + if (c & 0x80) + znptable8[c] |= N_FLAG; + } + + for (c = 0; c < 65536; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable16[c] = 0; + else + znptable16[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) + x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); +#endif + if (!c) + znptable16[c] |= Z_FLAG; + if (c & 0x8000) + znptable16[c] |= N_FLAG; + } +} + + +/* Common reset function. */ +static void +reset_common(int hard) +{ + biu_cycles = 0; + in_rep = 0; + in_lock = 0; + completed = 1; + repeating = 0; + clear_lock = 0; + refresh = 0; + + if (hard) { +#ifdef ENABLE_808X_LOG + x808x_log("x86 reset\n"); +#endif + ins = 0; + } + use32 = 0; + cpu_cur_status = 0; + stack32 = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw = 0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + if (isibmcpu) + cpu_cache_int_enabled = 1; + else + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + cpu_state.eflags = 0; + cgate32 = 0; + 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; + idt.limit = is386 ? 0x03FF : 0xFFFF; + cpu_state.flags = 2; + trap = 0; + ovr_seg = NULL; + in_lock = 0; + + EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; + + if (hard) { + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + cpu_set_edx(); + mmu_perm = 4; + pfq_size = (is8086) ? 6 : 4; + } + x86seg_reset(); #ifdef USE_DYNAREC - codegen_reset(); + if (hard) + codegen_reset(); #endif - x86_was_reset = 1; - port_92_clear_reset(); -} + if (!hard) + flushmmucache(); + x86_was_reset = 1; + cpu_alt_reset = 0; -void softresetx86() -{ - use32=0; - stack32=0; - cpu_cur_status = 0; - msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - msw=0; - if (is486) - cr0 = 1 << 30; - else - cr0 = 0; - cpu_cache_int_enabled = 0; - cpu_update_waitstates(); - cr4 = 0; - eflags=0; - cgate32=0; - if(AT) - { - loadcs(0xF000); - cpu_state.pc=0xFFF0; - rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; - } - else - { - loadcs(0xFFFF); - cpu_state.pc=0; - rammask = 0xfffff; - } - flags=2; - idt.base = 0; - idt.limit = is386 ? 0x03FF : 0xFFFF; - x86seg_reset(); - x86_was_reset = 1; - port_92_clear_reset(); -} + pfq_clear(); + prefetching = 1; -static void setznp8(uint8_t val) -{ - flags&=~0xC4; - flags|=znptable8[val]; -} - -static void setznp16(uint16_t val) -{ - flags&=~0xC4; - flags|=znptable16[val]; -} - -static void setadd8(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a+(uint16_t)b; - flags&=~0x8D5; - flags|=znptable8[c&0xFF]; - if (c&0x100) flags|=C_FLAG; - if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadd8nc(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a+(uint16_t)b; - flags&=~0x8D4; - flags|=znptable8[c&0xFF]; - if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadc8(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a+(uint16_t)b+tempc; - flags&=~0x8D5; - flags|=znptable8[c&0xFF]; - if (c&0x100) flags|=C_FLAG; - if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadd16(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a+(uint32_t)b; - flags&=~0x8D5; - flags|=znptable16[c&0xFFFF]; - if (c&0x10000) flags|=C_FLAG; - if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadd16nc(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a+(uint32_t)b; - flags&=~0x8D4; - flags|=znptable16[c&0xFFFF]; - if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} -static void setadc16(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a+(uint32_t)b+tempc; - flags&=~0x8D5; - flags|=znptable16[c&0xFFFF]; - if (c&0x10000) flags|=C_FLAG; - if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; -} - -static void setsub8(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a-(uint16_t)b; - flags&=~0x8D5; - flags|=znptable8[c&0xFF]; - if (c&0x100) flags|=C_FLAG; - if ((a^b)&(a^c)&0x80) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsub8nc(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a-(uint16_t)b; - flags&=~0x8D4; - flags|=znptable8[c&0xFF]; - if ((a^b)&(a^c)&0x80) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsbc8(uint8_t a, uint8_t b) -{ - uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); - flags&=~0x8D5; - flags|=znptable8[c&0xFF]; - if (c&0x100) flags|=C_FLAG; - if ((a^b)&(a^c)&0x80) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsub16(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a-(uint32_t)b; - flags&=~0x8D5; - flags|=znptable16[c&0xFFFF]; - if (c&0x10000) flags|=C_FLAG; - if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsub16nc(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a-(uint32_t)b; - flags&=~0x8D4; - flags|=(znptable16[c&0xFFFF]&~4); - flags|=(znptable8[c&0xFF]&4); - if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} -static void setsbc16(uint16_t a, uint16_t b) -{ - uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); - flags&=~0x8D5; - flags|=(znptable16[c&0xFFFF]&~4); - flags|=(znptable8[c&0xFF]&4); - if (c&0x10000) flags|=C_FLAG; - if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; - if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; -} - -int current_diff = 0; -void clockhardware() -{ - int diff = cycdiff - cycles - current_diff; - - current_diff += diff; - - timer_end_period(cycles*xt_cpu_multi); -} - -static int takeint = 0; - - -int firstrepcycle=1; - -void rep(int fv) -{ - uint8_t temp = 0; - int c=CX; - uint8_t temp2; - uint16_t tempw,tempw2; - uint16_t ipc=cpu_state.oldpc; - int changeds=0; - uint32_t oldds = 0; - startrep: - temp=FETCH(); - - switch (temp) - { - case 0x08: - cpu_state.pc=ipc+1; - cycles-=2; - FETCHCLEAR(); - break; - case 0x26: /*ES:*/ - oldds=ds; - ds=es; - changeds=1; - cycles-=2; - goto startrep; - break; - case 0x2E: /*CS:*/ - oldds=ds; - ds=cs; - changeds=1; - cycles-=2; - goto startrep; - break; - case 0x36: /*SS:*/ - oldds=ds; - ds=ss; - changeds=1; - cycles-=2; - goto startrep; - break; - case 0x6E: /*REP OUTSB*/ - if (c>0) - { - temp2=readmemb(ds+SI); - outb(DX,temp2); - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=5; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - break; - case 0xA4: /*REP MOVSB*/ - while (c>0 && !IRQTEST) - { - temp2=readmemb(ds+SI); - writememb(es+DI,temp2); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - c--; - cycles-=17; - clockhardware(); - FETCHADD(17-memcycs); - } - if (IRQTEST && c>0) cpu_state.pc=ipc; - break; - case 0xA5: /*REP MOVSW*/ - while (c>0 && !IRQTEST) - { - memcycs=0; - tempw=readmemw(ds,SI); - writememw(es,DI,tempw); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - c--; - cycles-=17; - clockhardware(); - FETCHADD(17 - memcycs); - } - if (IRQTEST && c>0) cpu_state.pc=ipc; - break; - case 0xA6: /*REP CMPSB*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) - { - memcycs=0; - temp=readmemb(ds+SI); - temp2=readmemb(es+DI); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - c--; - cycles -= 30; - setsub8(temp,temp2); - clockhardware(); - FETCHADD(30 - memcycs); - } - if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; - break; - case 0xA7: /*REP CMPSW*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) - { - memcycs=0; - tempw=readmemw(ds,SI); - tempw2=readmemw(es,DI); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - c--; - cycles -= 30; - setsub16(tempw,tempw2); - clockhardware(); - FETCHADD(30 - memcycs); - } - if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; - break; - case 0xAA: /*REP STOSB*/ - while (c>0 && !IRQTEST) - { - memcycs=0; - writememb(es+DI,AL); - if (flags&D_FLAG) DI--; - else DI++; - c--; - cycles -= 10; - clockhardware(); - FETCHADD(10 - memcycs); - } - if (IRQTEST && c>0) cpu_state.pc=ipc; - break; - case 0xAB: /*REP STOSW*/ - while (c>0 && !IRQTEST) - { - memcycs=0; - writememw(es,DI,AX); - if (flags&D_FLAG) DI-=2; - else DI+=2; - c--; - cycles -= 10; - clockhardware(); - FETCHADD(10 - memcycs); - } - if (IRQTEST && c>0) cpu_state.pc=ipc; - break; - case 0xAC: /*REP LODSB*/ - if (c>0) - { - temp2=readmemb(ds+SI); - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=4; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - break; - case 0xAD: /*REP LODSW*/ - if (c>0) - { - tempw2=readmemw(ds,SI); - if (flags&D_FLAG) SI-=2; - else SI+=2; - c--; - cycles-=4; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - break; - case 0xAE: /*REP SCASB*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) - { - temp2=readmemb(es+DI); - setsub8(AL,temp2); - if (flags&D_FLAG) DI--; - else DI++; - 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(); } - else firstrepcycle=1; - break; - case 0xAF: /*REP SCASW*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) - { - tempw=readmemw(es,DI); - setsub16(AX,tempw); - if (flags&D_FLAG) DI-=2; - else DI+=2; - c--; - cycles -= 15; - } - if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; - break; - default: - cpu_state.pc = ipc+1; - cycles-=20; - FETCHCLEAR(); - } - CX=c; - if (changeds) ds=oldds; - if (IRQTEST) - takeint = 1; + takeint = 0; } -int inhlt=0; -uint16_t lastpc,lastcs; -int firstrepcycle; -int skipnextprint=0; - -int instime=0; -void execx86(int cycs) +/* Hard reset. */ +void +resetx86(void) { - uint8_t temp = 0,temp2; - uint16_t addr,tempw,tempw2,tempw3,tempw4; - int8_t offset; - int tempws; - uint32_t templ; - unsigned int c; - int tempi; - int trap; - - cycles+=cycs; - while (cycles>0) - { - cycdiff=cycles; - timer_start_period(cycles*xt_cpu_multi); - current_diff = 0; - cycles-=nextcyc; - nextcyc=0; - fetchclocks=0; - oldcs=CS; - cpu_state.oldpc=cpu_state.pc; - opcodestart: - opcode=FETCH(); - tempc=flags&C_FLAG; - trap=flags&T_FLAG; - cpu_state.pc--; - if (output) - { - if (!skipnextprint) x808x_log("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i %p %02X\n",cs,cpu_state.pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ins, ram, ram[0x1a925]); - skipnextprint=0; - } - cpu_state.pc++; - inhlt=0; - switch (opcode) - { - case 0x00: /*ADD 8,reg*/ - fetchea(); - temp=geteab(); - setadd8(temp,getr8(cpu_reg)); - temp+=getr8(cpu_reg); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x01: /*ADD 16,reg*/ - fetchea(); - tempw=geteaw(); - setadd16(tempw, cpu_state.regs[cpu_reg].w); - tempw += cpu_state.regs[cpu_reg].w; - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x02: /*ADD cpu_reg,8*/ - fetchea(); - temp=geteab(); - setadd8(getr8(cpu_reg),temp); - setr8(cpu_reg,getr8(cpu_reg)+temp); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x03: /*ADD cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - setadd16(cpu_state.regs[cpu_reg].w,tempw); - cpu_state.regs[cpu_reg].w+=tempw; - cycles-=((cpu_mod==3)?3:13); - break; - case 0x04: /*ADD AL,#8*/ - temp=FETCH(); - setadd8(AL,temp); - AL+=temp; - cycles-=4; - break; - case 0x05: /*ADD AX,#16*/ - tempw=getword(); - setadd16(AX,tempw); - AX+=tempw; - cycles-=4; - break; - - case 0x06: /*PUSH ES*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),ES); - SP-=2; - cpu_state.last_ea = SP; - cycles-=14; - break; - case 0x07: /*POP ES*/ - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - loadseg(tempw,&_es); - SP+=2; - cpu_state.last_ea = SP; - cycles-=12; - break; - - case 0x08: /*OR 8,reg*/ - fetchea(); - temp=geteab(); - temp|=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x09: /*OR 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw|=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x0A: /*OR cpu_reg,8*/ - fetchea(); - temp=geteab(); - temp|=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x0B: /*OR reg,16*/ - fetchea(); - tempw=geteaw(); - tempw|=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - 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); - cycles-=4; - break; - case 0x0D: /*OR AX,#16*/ - AX|=getword(); - setznp16(AX); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=4; - break; - - case 0x0E: /*PUSH CS*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),CS); - SP-=2; - cpu_state.last_ea = SP; - cycles-=14; - break; - case 0x0F: /*POP CS - 8088/8086 only*/ - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - loadseg(tempw,&_cs); - SP+=2; - cpu_state.last_ea = SP; - cycles-=12; - break; - - case 0x10: /*ADC 8,reg*/ - fetchea(); - temp=geteab(); - temp2=getr8(cpu_reg); - setadc8(temp,temp2); - temp+=temp2+tempc; - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x11: /*ADC 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw2=cpu_state.regs[cpu_reg].w; - setadc16(tempw,tempw2); - tempw+=tempw2+tempc; - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x12: /*ADC cpu_reg,8*/ - fetchea(); - temp=geteab(); - setadc8(getr8(cpu_reg),temp); - setr8(cpu_reg,getr8(cpu_reg)+temp+tempc); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x13: /*ADC cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - setadc16(cpu_state.regs[cpu_reg].w,tempw); - cpu_state.regs[cpu_reg].w+=tempw+tempc; - cycles-=((cpu_mod==3)?3:13); - break; - case 0x14: /*ADC AL,#8*/ - tempw=FETCH(); - setadc8(AL,tempw & 0xff); - AL+=tempw+tempc; - cycles-=4; - break; - case 0x15: /*ADC AX,#16*/ - tempw=getword(); - setadc16(AX,tempw); - AX+=tempw+tempc; - cycles-=4; - break; - - case 0x16: /*PUSH SS*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),SS); - SP-=2; - cycles-=14; - cpu_state.last_ea = SP; - break; - case 0x17: /*POP SS*/ - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - loadseg(tempw,&_ss); - SP+=2; - cpu_state.last_ea = SP; - noint=1; - cycles-=12; - break; - - case 0x18: /*SBB 8,reg*/ - fetchea(); - temp=geteab(); - temp2=getr8(cpu_reg); - setsbc8(temp,temp2); - temp-=(temp2+tempc); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x19: /*SBB 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw2=cpu_state.regs[cpu_reg].w; - setsbc16(tempw,tempw2); - tempw-=(tempw2+tempc); - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x1A: /*SBB cpu_reg,8*/ - fetchea(); - temp=geteab(); - setsbc8(getr8(cpu_reg),temp); - setr8(cpu_reg,getr8(cpu_reg)-(temp+tempc)); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x1B: /*SBB cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - tempw2=cpu_state.regs[cpu_reg].w; - setsbc16(tempw2,tempw); - tempw2-=(tempw+tempc); - cpu_state.regs[cpu_reg].w=tempw2; - cycles-=((cpu_mod==3)?3:13); - break; - case 0x1C: /*SBB AL,#8*/ - temp=FETCH(); - setsbc8(AL,temp); - AL-=(temp+tempc); - cycles-=4; - break; - case 0x1D: /*SBB AX,#16*/ - tempw=getword(); - setsbc16(AX,tempw); - AX-=(tempw+tempc); - cycles-=4; - break; - - case 0x1E: /*PUSH DS*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),DS); - SP-=2; - cpu_state.last_ea = SP; - cycles-=14; - break; - case 0x1F: /*POP DS*/ - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - loadseg(tempw,&_ds); - if (cpu_state.ssegs) oldds=ds; - SP+=2; - cpu_state.last_ea = SP; - cycles-=12; - break; - - case 0x20: /*AND 8,reg*/ - fetchea(); - temp=geteab(); - temp&=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x21: /*AND 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw&=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x22: /*AND cpu_reg,8*/ - fetchea(); - temp=geteab(); - temp&=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x23: /*AND cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - tempw&=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - 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); - cycles-=4; - break; - case 0x25: /*AND AX,#16*/ - AX&=getword(); - setznp16(AX); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=4; - break; - - case 0x26: /*ES:*/ - oldss=ss; - oldds=ds; - ds=ss=es; - cpu_state.ssegs=2; - cycles-=4; - goto opcodestart; - - case 0x27: /*DAA*/ - if ((flags&A_FLAG) || ((AL&0xF)>9)) - { - tempi=((uint16_t)AL)+6; - AL+=6; - flags|=A_FLAG; - if (tempi&0x100) flags|=C_FLAG; - } - if ((flags&C_FLAG) || (AL>0x9F)) - { - AL+=0x60; - flags|=C_FLAG; - } - setznp8(AL); - cycles-=4; - break; - - case 0x28: /*SUB 8,reg*/ - fetchea(); - temp=geteab(); - setsub8(temp,getr8(cpu_reg)); - temp-=getr8(cpu_reg); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x29: /*SUB 16,reg*/ - fetchea(); - tempw=geteaw(); - setsub16(tempw,cpu_state.regs[cpu_reg].w); - tempw-=cpu_state.regs[cpu_reg].w; - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x2A: /*SUB cpu_reg,8*/ - fetchea(); - temp=geteab(); - setsub8(getr8(cpu_reg),temp); - setr8(cpu_reg,getr8(cpu_reg)-temp); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x2B: /*SUB cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - setsub16(cpu_state.regs[cpu_reg].w,tempw); - cpu_state.regs[cpu_reg].w-=tempw; - cycles-=((cpu_mod==3)?3:13); - break; - case 0x2C: /*SUB AL,#8*/ - temp=FETCH(); - setsub8(AL,temp); - AL-=temp; - cycles-=4; - break; - case 0x2D: /*SUB AX,#16*/ - tempw=getword(); - setsub16(AX,tempw); - AX-=tempw; - cycles-=4; - break; - case 0x2E: /*CS:*/ - oldss=ss; - oldds=ds; - ds=ss=cs; - cpu_state.ssegs=2; - cycles-=4; - goto opcodestart; - case 0x2F: /*DAS*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) - { - tempi=((uint16_t)AL)-6; - AL-=6; - flags|=A_FLAG; - if (tempi&0x100) flags|=C_FLAG; - } - if ((flags&C_FLAG)||(AL>0x9F)) - { - AL-=0x60; - flags|=C_FLAG; - } - setznp8(AL); - cycles-=4; - break; - case 0x30: /*XOR 8,reg*/ - fetchea(); - temp=geteab(); - temp^=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x31: /*XOR 16,reg*/ - fetchea(); - tempw=geteaw(); - tempw^=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x32: /*XOR cpu_reg,8*/ - fetchea(); - temp=geteab(); - temp^=getr8(cpu_reg); - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x33: /*XOR cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - tempw^=cpu_state.regs[cpu_reg].w; - setznp16(tempw); - 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); - cycles-=4; - break; - case 0x35: /*XOR AX,#16*/ - AX^=getword(); - setznp16(AX); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=4; - break; - - case 0x36: /*SS:*/ - oldss=ss; - oldds=ds; - ds=ss=ss; - cpu_state.ssegs=2; - cycles-=4; - goto opcodestart; - - case 0x37: /*AAA*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) - { - AL+=6; - AH++; - flags|=(A_FLAG|C_FLAG); - } - else - flags&=~(A_FLAG|C_FLAG); - AL&=0xF; - cycles-=8; - break; - - case 0x38: /*CMP 8,reg*/ - fetchea(); - temp=geteab(); - setsub8(temp,getr8(cpu_reg)); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x39: /*CMP 16,reg*/ - fetchea(); - tempw=geteaw(); - setsub16(tempw,cpu_state.regs[cpu_reg].w); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x3A: /*CMP cpu_reg,8*/ - fetchea(); - temp=geteab(); - setsub8(getr8(cpu_reg),temp); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x3B: /*CMP cpu_reg,16*/ - fetchea(); - tempw=geteaw(); - setsub16(cpu_state.regs[cpu_reg].w,tempw); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x3C: /*CMP AL,#8*/ - temp=FETCH(); - setsub8(AL,temp); - cycles-=4; - break; - case 0x3D: /*CMP AX,#16*/ - tempw=getword(); - setsub16(AX,tempw); - cycles-=4; - break; - - case 0x3E: /*DS:*/ - oldss=ss; - oldds=ds; - ds=ss=ds; - cpu_state.ssegs=2; - cycles-=4; - goto opcodestart; - - case 0x3F: /*AAS*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) - { - AL-=6; - AH--; - flags|=(A_FLAG|C_FLAG); - } - else - flags&=~(A_FLAG|C_FLAG); - AL&=0xF; - cycles-=8; - break; - - case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ - case 0x44: case 0x45: case 0x46: case 0x47: - setadd16nc(cpu_state.regs[opcode&7].w,1); - cpu_state.regs[opcode&7].w++; - cycles-=3; - break; - case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ - case 0x4C: case 0x4D: case 0x4E: case 0x4F: - setsub16nc(cpu_state.regs[opcode&7].w,1); - cpu_state.regs[opcode&7].w--; - cycles-=3; - break; - - case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ - case 0x54: case 0x55: case 0x56: case 0x57: - if (cpu_state.ssegs) ss=oldss; - SP-=2; - cpu_state.last_ea = SP; - writememw(ss,SP,cpu_state.regs[opcode&7].w); - cycles-=15; - break; - case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ - case 0x5C: case 0x5D: case 0x5E: case 0x5F: - if (cpu_state.ssegs) ss=oldss; - SP+=2; - cpu_state.last_ea = SP; - cpu_state.regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); - cycles-=12; - break; + reset_common(1); +} - case 0x60: /*JO alias*/ - case 0x70: /*JO*/ - offset=(int8_t)FETCH(); - if (flags&V_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x61: /*JNO alias*/ - case 0x71: /*JNO*/ - offset=(int8_t)FETCH(); - if (!(flags&V_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x62: /*JB alias*/ - case 0x72: /*JB*/ - offset=(int8_t)FETCH(); - if (flags&C_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x63: /*JNB alias*/ - case 0x73: /*JNB*/ - offset=(int8_t)FETCH(); - if (!(flags&C_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x64: /*JE alias*/ - case 0x74: /*JE*/ - offset=(int8_t)FETCH(); - if (flags&Z_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x65: /*JNE alias*/ - case 0x75: /*JNE*/ - offset=(int8_t)FETCH(); - cycles-=4; - if (!(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - break; - case 0x66: /*JBE alias*/ - case 0x76: /*JBE*/ - offset=(int8_t)FETCH(); - if (flags&(C_FLAG|Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x67: /*JNBE alias*/ - case 0x77: /*JNBE*/ - offset=(int8_t)FETCH(); - if (!(flags&(C_FLAG|Z_FLAG))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x68: /*JS alias*/ - case 0x78: /*JS*/ - offset=(int8_t)FETCH(); - if (flags&N_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x69: /*JNS alias*/ - case 0x79: /*JNS*/ - offset=(int8_t)FETCH(); - if (!(flags&N_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x6A: /*JP alias*/ - case 0x7A: /*JP*/ - offset=(int8_t)FETCH(); - if (flags&P_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x6B: /*JNP alias*/ - case 0x7B: /*JNP*/ - offset=(int8_t)FETCH(); - if (!(flags&P_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x6C: /*JL alias*/ - case 0x7C: /*JL*/ - offset=(int8_t)FETCH(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if (temp!=temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x6D: /*JNL alias*/ - case 0x7D: /*JNL*/ - offset=(int8_t)FETCH(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if (temp==temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x6E: /*JLE alias*/ - case 0x7E: /*JLE*/ - offset=(int8_t)FETCH(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if ((flags&Z_FLAG) || (temp!=temp2)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; - case 0x6F: /*JNLE alias*/ - case 0x7F: /*JNLE*/ - offset=(int8_t)FETCH(); - temp=(flags&N_FLAG)?1:0; - temp2=(flags&V_FLAG)?1:0; - if (!((flags&Z_FLAG) || (temp!=temp2))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=4; - break; +/* Soft reset. */ +void +softresetx86(void) +{ + reset_common(0); +} - case 0x80: case 0x82: - fetchea(); - temp=geteab(); - temp2=FETCH(); - switch (rmdat&0x38) - { - case 0x00: /*ADD b,#8*/ - setadd8(temp,temp2); - seteab(temp+temp2); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x08: /*OR b,#8*/ - temp|=temp2; - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x10: /*ADC b,#8*/ - setadc8(temp,temp2); - seteab(temp+temp2+tempc); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x18: /*SBB b,#8*/ - setsbc8(temp,temp2); - seteab(temp-(temp2+tempc)); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x20: /*AND b,#8*/ - temp&=temp2; - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x28: /*SUB b,#8*/ - setsub8(temp,temp2); - seteab(temp-temp2); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x30: /*XOR b,#8*/ - temp^=temp2; - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteab(temp); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x38: /*CMP b,#8*/ - setsub8(temp,temp2); - cycles-=((cpu_mod==3)?4:14); - break; - } - break; - case 0x81: - fetchea(); - tempw=geteaw(); - tempw2=getword(); - switch (rmdat&0x38) - { - case 0x00: /*ADD w,#16*/ - setadd16(tempw,tempw2); - tempw+=tempw2; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x08: /*OR w,#16*/ - tempw|=tempw2; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x10: /*ADC w,#16*/ - setadc16(tempw,tempw2); - tempw+=tempw2+tempc; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x20: /*AND w,#16*/ - tempw&=tempw2; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x18: /*SBB w,#16*/ - setsbc16(tempw,tempw2); - seteaw(tempw-(tempw2+tempc)); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x28: /*SUB w,#16*/ - setsub16(tempw,tempw2); - tempw-=tempw2; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x30: /*XOR w,#16*/ - tempw^=tempw2; - setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x38: /*CMP w,#16*/ - setsub16(tempw,tempw2); - cycles-=((cpu_mod==3)?4:14); - break; - } - break; +/* Pushes a word to the stack. */ +static void +push(uint16_t *val) +{ + SP -= 2; + cpu_state.eaaddr = (SP & 0xffff); + writememw(ss, cpu_state.eaaddr, *val); +} - case 0x83: - fetchea(); - tempw=geteaw(); - tempw2=FETCH(); - if (tempw2&0x80) tempw2|=0xFF00; - switch (rmdat&0x38) - { - case 0x00: /*ADD w,#8*/ - setadd16(tempw,tempw2); - tempw+=tempw2; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x08: /*OR w,#8*/ - tempw|=tempw2; - setznp16(tempw); - seteaw(tempw); - flags&=~(C_FLAG|A_FLAG|V_FLAG); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x10: /*ADC w,#8*/ - setadc16(tempw,tempw2); - tempw+=tempw2+tempc; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x18: /*SBB w,#8*/ - setsbc16(tempw,tempw2); - tempw-=(tempw2+tempc); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x20: /*AND w,#8*/ - tempw&=tempw2; - setznp16(tempw); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - flags&=~(C_FLAG|A_FLAG|V_FLAG); - break; - case 0x28: /*SUB w,#8*/ - setsub16(tempw,tempw2); - tempw-=tempw2; - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - break; - case 0x30: /*XOR w,#8*/ - tempw^=tempw2; - setznp16(tempw); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:23); - flags&=~(C_FLAG|A_FLAG|V_FLAG); - break; - case 0x38: /*CMP w,#8*/ - setsub16(tempw,tempw2); - cycles-=((cpu_mod==3)?4:14); - break; - } - break; - case 0x84: /*TEST b,reg*/ - fetchea(); - temp=geteab(); - temp2=getr8(cpu_reg); - setznp8(temp&temp2); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x85: /*TEST w,reg*/ - fetchea(); - tempw=geteaw(); - tempw2=cpu_state.regs[cpu_reg].w; - setznp16(tempw&tempw2); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=((cpu_mod==3)?3:13); - break; - case 0x86: /*XCHG b,reg*/ - fetchea(); - temp=geteab(); - seteab(getr8(cpu_reg)); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?4:25); - break; - case 0x87: /*XCHG w,reg*/ - fetchea(); - tempw=geteaw(); - seteaw(cpu_state.regs[cpu_reg].w); - cpu_state.regs[cpu_reg].w=tempw; - cycles-=((cpu_mod==3)?4:25); - break; +/* Pops a word from the stack. */ +static uint16_t +pop(void) +{ + cpu_state.eaaddr = (SP & 0xffff); + SP += 2; + return readmemw(ss, cpu_state.eaaddr); +} - case 0x88: /*MOV b,reg*/ - fetchea(); - seteab(getr8(cpu_reg)); - cycles-=((cpu_mod==3)?2:13); - break; - case 0x89: /*MOV w,reg*/ - fetchea(); - seteaw(cpu_state.regs[cpu_reg].w); - cycles-=((cpu_mod==3)?2:13); - break; - case 0x8A: /*MOV cpu_reg,b*/ - fetchea(); - temp=geteab(); - setr8(cpu_reg,temp); - cycles-=((cpu_mod==3)?2:12); - break; - case 0x8B: /*MOV cpu_reg,w*/ - fetchea(); - tempw=geteaw(); - cpu_state.regs[cpu_reg].w=tempw; - cycles-=((cpu_mod==3)?2:12); - break; - case 0x8C: /*MOV w,sreg*/ - fetchea(); - switch (rmdat&0x38) - { - case 0x00: /*ES*/ - seteaw(ES); - break; - case 0x08: /*CS*/ - seteaw(CS); - break; - case 0x18: /*DS*/ - if (cpu_state.ssegs) ds=oldds; - seteaw(DS); - break; - case 0x10: /*SS*/ - if (cpu_state.ssegs) ss=oldss; - seteaw(SS); - break; - } - cycles-=((cpu_mod==3)?2:13); - break; +static void +access(int num, int bits) +{ + switch (num) { + case 0: case 61: case 63: case 64: + case 67: case 69: case 71: case 72: + default: + break; + case 1: case 6: case 7: case 8: + case 9: case 17: case 20: case 21: + case 24: case 28: case 47: case 48: + case 49: case 50: case 51: case 55: + case 56: case 62: case 66: case 68: + wait(1, 0); + break; + case 3: case 11: case 15: case 22: + case 23: case 25: case 26: case 35: + case 44: case 45: case 46: case 52: + case 53: case 54: + wait(2, 0); + break; + case 16: case 18: case 19: case 27: + case 32: case 37: case 42: + wait(3, 0); + break; + case 10: case 12: case 13: case 14: + case 29: case 30: case 33: case 34: + case 39: case 41: case 60: + wait(4, 0); + break; + case 4: case 70: + wait(5, 0); + break; + case 31: case 38: case 40: + wait(6, 0); + break; + case 5: + if (opcode == 0xcc) + wait(7, 0); + else + wait(4, 0); + break; + case 36: + wait(1, 0); + pfq_clear(); + wait (1, 0); + if (cpu_mod != 3) + wait(1, 0); + wait(3, 0); + break; + case 43: + wait(2, 0); + pfq_clear(); + wait(1, 0); + break; + case 57: + if (cpu_mod != 3) + wait(2, 0); + wait(4, 0); + break; + case 58: + if (cpu_mod != 3) + wait(1, 0); + wait(4, 0); + break; + case 59: + wait(2, 0); + pfq_clear(); + if (cpu_mod != 3) + wait(1, 0); + wait(3, 0); + break; + case 65: + wait(1, 0); + pfq_clear(); + wait(2, 0); + if (cpu_mod != 3) + wait(1, 0); + break; + } +} - case 0x8D: /*LEA*/ - fetchea(); - cpu_state.regs[cpu_reg].w=(cpu_mod == 3)?cpu_state.last_ea:cpu_state.eaaddr; - cycles-=2; - break; - case 0x8E: /*MOV sreg,w*/ - fetchea(); - switch (rmdat&0x38) - { - case 0x00: /*ES*/ - tempw=geteaw(); - loadseg(tempw,&_es); - break; - case 0x08: /*CS - 8088/8086 only*/ - tempw=geteaw(); - loadseg(tempw,&_cs); - break; - case 0x18: /*DS*/ - tempw=geteaw(); - loadseg(tempw,&_ds); - if (cpu_state.ssegs) oldds=ds; - break; - case 0x10: /*SS*/ - tempw=geteaw(); - loadseg(tempw,&_ss); - if (cpu_state.ssegs) oldss=ss; - break; - } - cycles-=((cpu_mod==3)?2:12); - skipnextprint=1; - noint=1; - break; +/* Calls an interrupt. */ +static void +interrupt(uint16_t addr) +{ + uint16_t old_cs, old_ip; + uint16_t new_cs, new_ip; + uint16_t tempf; - case 0x8F: /*POPW*/ - fetchea(); - if (cpu_state.ssegs) ss=oldss; - tempw=readmemw(ss,SP); - SP+=2; - cpu_state.last_ea = SP; - seteaw(tempw); - cycles-=25; - break; + addr <<= 2; + cpu_state.eaaddr = addr; + old_cs = CS; + access(5, 16); + new_ip = readmemw(0, cpu_state.eaaddr); + wait(1, 0); + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + access(6, 16); + new_cs = readmemw(0, cpu_state.eaaddr); + pfq_clear(); + access(39, 16); + tempf = cpu_state.flags & 0x0fd7; + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); + access(40, 16); + push(&old_cs); + old_ip = cpu_state.pc; + loadcs(new_cs); + access(68, 16); + set_ip(new_ip); + access(41, 16); + push(&old_ip); +} - case 0x90: /*NOP*/ - cycles-=3; - break; - case 0x91: case 0x92: case 0x93: /*XCHG AX*/ - case 0x94: case 0x95: case 0x96: case 0x97: - tempw=AX; - AX=cpu_state.regs[opcode&7].w; - cpu_state.regs[opcode&7].w=tempw; - cycles-=3; - break; +static void +check_interrupts(void) +{ + int temp; - case 0x98: /*CBW*/ - AH=(AL&0x80)?0xFF:0; - cycles-=2; - break; - case 0x99: /*CWD*/ - DX=(AX&0x8000)?0xFFFF:0; - cycles-=5; - break; - case 0x9A: /*CALL FAR*/ - tempw=getword(); - tempw2=getword(); - tempw3=CS; - tempw4=cpu_state.pc; - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=tempw; - loadcs(tempw2); - writememw(ss,(SP-2)&0xFFFF,tempw3); - writememw(ss,(SP-4)&0xFFFF,tempw4); - SP-=4; - cpu_state.last_ea = SP; - cycles-=36; - FETCHCLEAR(); - break; - case 0x9B: /*WAIT*/ - cycles-=4; - break; - case 0x9C: /*PUSHF*/ - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),flags|0xF000); - SP-=2; - cpu_state.last_ea = SP; - cycles-=14; - break; - case 0x9D: /*POPF*/ - if (cpu_state.ssegs) ss=oldss; - flags=readmemw(ss,SP)&0xFFF; - SP+=2; - cpu_state.last_ea = SP; - cycles-=12; - break; - case 0x9E: /*SAHF*/ - flags=(flags&0xFF00)|AH; - cycles-=4; - break; - case 0x9F: /*LAHF*/ - AH=flags&0xFF; - cycles-=4; - break; + if (irq_pending()) { + if ((cpu_state.flags & T_FLAG) && !noint) { + interrupt(1); + return; + } + if (nmi && nmi_enable && nmi_mask) { + nmi_enable = 0; + interrupt(2); + return; + } + temp = picinterrupt(); + if (temp != -1) { + repeating = 0; + completed = 1; + ovr_seg = NULL; + in_lock = 0; + clear_lock = 0; + ovr_seg = NULL; + wait(9, 0); + interrupt((uint16_t) (temp & 0xffff)); + } + } +} - case 0xA0: /*MOV AL,(w)*/ - addr=getword(); - AL=readmemb(ds+addr); - cycles-=14; - break; - case 0xA1: /*MOV AX,(w)*/ - addr=getword(); - AX=readmemw(ds,addr); - cycles-=14; - break; - case 0xA2: /*MOV (w),AL*/ - addr=getword(); - writememb(ds+addr,AL); - cycles-=14; - break; - case 0xA3: /*MOV (w),AX*/ - addr=getword(); - writememw(ds,addr,AX); - cycles-=14; - break; - case 0xA4: /*MOVSB*/ - temp=readmemb(ds+SI); - writememb(es+DI,temp); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - cycles-=18; - break; - case 0xA5: /*MOVSW*/ - tempw=readmemw(ds,SI); - writememw(es,DI,tempw); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - cycles-=18; - break; - case 0xA6: /*CMPSB*/ - temp =readmemb(ds+SI); - temp2=readmemb(es+DI); - setsub8(temp,temp2); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - cycles-=30; - break; - case 0xA7: /*CMPSW*/ - tempw =readmemw(ds,SI); - tempw2=readmemw(es,DI); - setsub16(tempw,tempw2); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - cycles-=30; - break; - case 0xA8: /*TEST AL,#8*/ - temp=FETCH(); - setznp8(AL&temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=5; - break; - case 0xA9: /*TEST AX,#16*/ - tempw=getword(); - setznp16(AX&tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=5; - break; - case 0xAA: /*STOSB*/ - writememb(es+DI,AL); - if (flags&D_FLAG) DI--; - else DI++; - cycles-=11; - break; - case 0xAB: /*STOSW*/ - writememw(es,DI,AX); - if (flags&D_FLAG) DI-=2; - else DI+=2; - cycles-=11; - break; - case 0xAC: /*LODSB*/ - AL=readmemb(ds+SI); - if (flags&D_FLAG) SI--; - else SI++; - cycles-=16; - break; - case 0xAD: /*LODSW*/ - AX=readmemw(ds,SI); - if (flags&D_FLAG) SI-=2; - else SI+=2; - cycles-=16; - break; - case 0xAE: /*SCASB*/ - temp=readmemb(es+DI); - setsub8(AL,temp); - if (flags&D_FLAG) DI--; - else DI++; - cycles-=19; - break; - case 0xAF: /*SCASW*/ - tempw=readmemw(es,DI); - setsub16(AX,tempw); - if (flags&D_FLAG) DI-=2; - else DI+=2; - cycles-=19; - break; +static int +rep_action(int bits) +{ + uint16_t t; - case 0xB0: /*MOV AL,#8*/ - AL=FETCH(); - cycles-=4; - break; - case 0xB1: /*MOV CL,#8*/ - CL=FETCH(); - cycles-=4; - break; - case 0xB2: /*MOV DL,#8*/ - DL=FETCH(); - cycles-=4; - break; - case 0xB3: /*MOV BL,#8*/ - BL=FETCH(); - cycles-=4; - break; - case 0xB4: /*MOV AH,#8*/ - AH=FETCH(); - cycles-=4; - break; - case 0xB5: /*MOV CH,#8*/ - CH=FETCH(); - cycles-=4; - break; - case 0xB6: /*MOV DH,#8*/ - DH=FETCH(); - cycles-=4; - break; - case 0xB7: /*MOV BH,#8*/ - BH=FETCH(); - cycles-=4; - break; - case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ - case 0xBC: case 0xBD: case 0xBE: case 0xBF: - cpu_state.regs[opcode&7].w=getword(); - cycles-=4; - break; + if (in_rep == 0) + return 0; + wait(2, 0); + t = CX; + if (irq_pending() && (repeating != 0)) { + access(71, bits); + pfq_clear(); + set_ip(cpu_state.pc - 2); + t = 0; + } + if (t == 0) { + wait(1, 0); + completed = 1; + repeating = 0; + return 1; + } + --CX; + completed = 0; + wait(2, 0); + if (!repeating) + wait(2, 0); + return 0; +} - case 0xC0: /*RET alias*/ - case 0xC2: /*RET*/ - tempw=getword(); - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - SP+=2+tempw; - cycles-=24; - FETCHCLEAR(); - break; - case 0xC1: /*RET alias*/ - case 0xC3: /*RET*/ - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - SP+=2; - cycles-=20; - FETCHCLEAR(); - break; - case 0xC4: /*LES*/ - fetchea(); - cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); - tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); - loadseg(tempw,&_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); - if (cpu_state.ssegs) oldds=ds; - cycles-=24; - break; - case 0xC6: /*MOV b,#8*/ - fetchea(); - temp=FETCH(); - seteab(temp); - cycles-=((cpu_mod==3)?4:14); - break; - case 0xC7: /*MOV w,#16*/ - fetchea(); - tempw=getword(); - seteaw(tempw); - cycles-=((cpu_mod==3)?4:14); - break; - case 0xC8: /*RETF alias*/ - case 0xCA: /*RETF*/ - tempw=getword(); - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - loadcs(readmemw(ss,SP+2)); - SP+=4; - SP+=tempw; - cycles-=33; - FETCHCLEAR(); - break; - case 0xC9: /*RETF alias*/ - case 0xCB: /*RETF*/ - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=readmemw(ss,SP); - loadcs(readmemw(ss,SP+2)); - SP+=4; - cycles-=34; - FETCHCLEAR(); - 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); - SP-=6; - addr=3<<2; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - FETCHCLEAR(); - cycles-=72; - break; - case 0xCD: /*INT*/ - lastpc=cpu_state.pc; - lastcs=CS; - temp=FETCH(); +static uint16_t +jump(uint16_t delta) +{ + uint16_t old_ip; + access(67, 8); + pfq_clear(); + wait(5, 0); + old_ip = cpu_state.pc; + set_ip((cpu_state.pc + delta) & 0xffff); + return old_ip; +} - 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; - SP-=6; - addr=temp<<2; - cpu_state.pc=readmemw(0,addr); - loadcs(readmemw(0,addr+2)); - FETCHCLEAR(); +static void +jump_short(void) +{ + jump(sign_extend((uint8_t) cpu_data)); +} - cycles-=71; - break; - case 0xCF: /*IRET*/ - if (cpu_state.ssegs) ss=oldss; - tempw=CS; - tempw2=cpu_state.pc; - cpu_state.pc=readmemw(ss,SP); - loadcs(readmemw(ss,((SP+2)&0xFFFF))); - flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; - SP+=6; - cycles-=44; - FETCHCLEAR(); - nmi_enable = 1; - break; - case 0xD0: - fetchea(); - temp=geteab(); - switch (rmdat&0x38) - { - case 0x00: /*ROL b,1*/ - if (temp&0x80) flags|=C_FLAG; - else flags&=~C_FLAG; - temp<<=1; - if (flags&C_FLAG) temp|=1; - seteab(temp); - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else 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; - temp>>=1; - if (flags&C_FLAG) temp|=0x80; - seteab(temp); - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else 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; - temp<<=1; - if (temp2) temp|=1; - seteab(temp); - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else 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; - temp>>=1; - if (temp2) temp|=0x80; - seteab(temp); - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else 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; - temp<<=1; - seteab(temp); - setznp8(temp); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - break; - case 0x28: /*SHR b,1*/ - if (temp&1) flags|=C_FLAG; - else flags&=~C_FLAG; - if (temp&0x80) flags|=V_FLAG; - else flags&=~V_FLAG; - temp>>=1; - seteab(temp); - setznp8(temp); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - break; - case 0x38: /*SAR b,1*/ - if (temp&1) flags|=C_FLAG; - else flags&=~C_FLAG; - temp>>=1; - if (temp&0x40) temp|=0x80; - seteab(temp); - setznp8(temp); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - flags&=~V_FLAG; - break; - } - break; - case 0xD1: - fetchea(); - tempw=geteaw(); - switch (rmdat&0x38) - { - case 0x00: /*ROL w,1*/ - if (tempw&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw<<=1; - if (flags&C_FLAG) tempw|=1; - seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else 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; - tempw>>=1; - if (flags&C_FLAG) tempw|=0x8000; - seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else 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; - tempw<<=1; - if (temp2) tempw|=1; - seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else 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; - tempw>>=1; - if (temp2) tempw|=0x8000; - seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else 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; - tempw<<=1; - seteaw(tempw); - setznp16(tempw); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - break; - case 0x28: /*SHR w,1*/ - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - if (tempw&0x8000) flags|=V_FLAG; - else flags&=~V_FLAG; - tempw>>=1; - seteaw(tempw); - setznp16(tempw); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - break; +static uint16_t +jump_near(void) +{ + return jump(pfq_fetchw()); +} - case 0x38: /*SAR w,1*/ - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw>>=1; - if (tempw&0x4000) tempw|=0x8000; - seteaw(tempw); - setznp16(tempw); - cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - flags&=~V_FLAG; - break; - } - break; - case 0xD2: - fetchea(); - temp=geteab(); - c=CL; - if (!c) break; - switch (rmdat&0x38) - { - case 0x00: /*ROL b,CL*/ - temp2=(temp&0x80)?1:0; - if (!c) - { - cycles-=((cpu_mod==3)?8:28); - break; +/* Performs a conditional jump. */ +static void +jcc(uint8_t opcode, int cond) +{ + /* int8_t offset; */ + + wait(1, 0); + cpu_data = pfq_fetchb(); + wait(1, 0); + if ((!cond) == (opcode & 0x01)) + jump_short(); +} + + +static void +set_cf(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~C_FLAG) | (cond ? C_FLAG : 0); +} + + +static void +set_if(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~I_FLAG) | (cond ? I_FLAG : 0); +} + + +static void +set_df(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~D_FLAG) | (cond ? D_FLAG : 0); +} + + +static void +bitwise(int bits, uint16_t data) +{ + cpu_data = data; + cpu_state.flags &= ~(C_FLAG | A_FLAG | V_FLAG); + set_pzs(bits); +} + + +static void +test(int bits, uint16_t dest, uint16_t src) +{ + cpu_dest = dest; + cpu_src = src; + bitwise(bits, (cpu_dest & cpu_src)); +} + + +static void +set_of(int of) +{ + cpu_state.flags = (cpu_state.flags & ~0x800) | (of ? 0x800 : 0); +} + + +static int +top_bit(uint16_t w, int bits) +{ + if (bits == 16) + return ((w & 0x8000) != 0); + else + return ((w & 0x80) != 0); +} + + +static void +set_of_add(int bits) +{ + set_of(top_bit((cpu_data ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_of_sub(int bits) +{ + set_of(top_bit((cpu_dest ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_af(int af) +{ + cpu_state.flags = (cpu_state.flags & ~0x10) | (af ? 0x10 : 0); +} + + +static void +do_af(void) +{ + set_af(((cpu_data ^ cpu_src ^ cpu_dest) & 0x10) != 0); +} + + +static void +set_apzs(int bits) +{ + set_pzs(bits); + do_af(); +} + + +static void +add(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest + cpu_src; + set_apzs(bits); + set_of_add(bits); + + /* Anything - FF with carry on is basically anything + 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 2) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) + cpu_state.flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_data & size_mask)); +} + + +static void +sub(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest - cpu_src; + set_apzs(bits); + set_of_sub(bits); + + /* Anything - FF with carry on is basically anything - 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 3) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) + cpu_state.flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_dest & size_mask)); +} + + +static void +alu_op(int bits) +{ + switch(cpu_alu_op) { + case 1: + bitwise(bits, (cpu_dest | cpu_src)); + break; + case 2: + if (cpu_state.flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 0: + add(bits); + break; + case 3: + if (cpu_state.flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 5: case 7: + sub(bits); + break; + case 4: + test(bits, cpu_dest, cpu_src); + break; + case 6: + bitwise(bits, (cpu_dest ^ cpu_src)); + break; + } +} + + +static void +set_sf(int bits) +{ + cpu_state.flags = (cpu_state.flags & ~0x80) | (top_bit(cpu_data, bits) ? 0x80 : 0); +} + + +static void +set_pf(void) +{ + static uint8_t table[0x100] = { + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4}; + + cpu_state.flags = (cpu_state.flags & ~4) | table[cpu_data & 0xff]; +} + + +static void +mul(uint16_t a, uint16_t b) +{ + int negate = 0; + int bit_count = 8; + int carry, i; + uint16_t high_bit = 0x80; + uint16_t size_mask; + uint16_t c, r; + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd5) { + if (opcode & 1) { + bit_count = 16; + high_bit = 0x8000; + } else + wait(8, 0); + + size_mask = (1 << bit_count) - 1; + + if ((rmdat & 0x38) == 0x28) { + if (!top_bit(a, bit_count)) { + if (top_bit(b, bit_count)) { + wait(1, 0); + if ((b & size_mask) != ((opcode & 1) ? 0x8000 : 0x80)) + wait(1, 0); + b = ~b + 1; + negate = 1; + } + } else { + wait(1, 0); + a = ~a + 1; + negate = 1; + if (top_bit(b, bit_count)) { + b = ~b + 1; + negate = 0; + } else + wait(4, 0); + } + wait(10, 0); + } + wait(3, 0); + } + + c = 0; + a &= size_mask; + carry = (a & 1) != 0; + a >>= 1; + for (i = 0; i < bit_count; ++i) { + wait(7, 0); + if (carry) { + cpu_src = c; + cpu_dest = b; + add(bit_count); + c = cpu_data & size_mask; + wait(1, 0); + carry = !!(cpu_state.flags & C_FLAG); + } + r = (c >> 1) + (carry ? high_bit : 0); + carry = (c & 1) != 0; + c = r; + r = (a >> 1) + (carry ? high_bit : 0); + carry = (a & 1) != 0; + a = r; + } + if (negate) { + c = ~c; + a = (~a + 1) & size_mask; + if (a == 0) + ++c; + wait(9, 0); + } + cpu_data = a; + cpu_dest = c; + + set_sf(bit_count); + set_pf(); +} + + +static void +set_of_rotate(int bits) +{ + set_of(top_bit(cpu_data ^ cpu_dest, bits)); +} + + +static void +set_zf(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_state.flags = (cpu_state.flags & ~0x40) | (((cpu_data & size_mask) == 0) ? 0x40 : 0); +} + + +static void +set_pzs(int bits) +{ + set_pf(); + set_zf(bits); + set_sf(bits); +} + + +static void +set_co_mul(int carry) +{ + set_cf(carry); + set_of(carry); + if (!carry) + wait(1, 0); +} + + +/* Was div(), renamed to avoid conflicts with stdlib div(). */ +static int +x86_div(uint16_t l, uint16_t h) +{ + int b, bit_count = 8; + int negative = 0; + int dividend_negative = 0; + int size_mask, carry; + uint16_t r; + + if (opcode & 1) { + l = AX; + h = DX; + bit_count = 16; + } + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd4) { + if ((rmdat & 0x38) == 0x38) { + if (top_bit(h, bit_count)) { + h = ~h; + l = (~l + 1) & size_mask; + if (l == 0) + ++h; + h &= size_mask; + negative = 1; + dividend_negative = 1; + wait(4, 0); + } + if (top_bit(cpu_src, bit_count)) { + cpu_src = ~cpu_src + 1; + negative = !negative; + } else + wait(1, 0); + wait(9, 0); + } + wait(3, 0); + } + wait(8, 0); + cpu_src &= size_mask; + if (h >= cpu_src) { + if (opcode != 0xd4) + wait(1, 0); + interrupt(0); + return 0; + } + if (opcode != 0xd4) + wait(1, 0); + wait(2, 0); + carry = 1; + for (b = 0; b < bit_count; ++b) { + r = (l << 1) + (carry ? 1 : 0); + carry = top_bit(l, bit_count); + l = r; + r = (h << 1) + (carry ? 1 : 0); + carry = top_bit(h, bit_count); + h = r; + wait(8, 0); + if (carry) { + carry = 0; + h -= cpu_src; + if (b == bit_count - 1) + wait(2, 0); + } else { + carry = cpu_src > h; + if (!carry) { + h -= cpu_src; + wait(1, 0); + if (b == bit_count - 1) + wait(2, 0); + } + } + } + l = ~((l << 1) + (carry ? 1 : 0)); + if (opcode != 0xd4 && (rmdat & 0x38) == 0x38) { + wait(4, 0); + if (top_bit(l, bit_count)) { + if (cpu_mod == 3) + wait(1, 0); + interrupt(0); + return 0; + } + wait(7, 0); + if (negative) + l = ~l + 1; + if (dividend_negative) + h = ~h + 1; + } + if (opcode == 0xd4) { + AL = h & 0xff; + AH = l & 0xff; + } else { + AH = h & 0xff; + AL = l & 0xff; + if (opcode & 1) { + DX = h; + AX = l; + } + } + return 1; +} + + +static uint16_t +string_increment(int bits) +{ + int d = bits >> 3; + if (cpu_state.flags & D_FLAG) + cpu_state.eaaddr -= d; + else + cpu_state.eaaddr += d; + cpu_state.eaaddr &= 0xffff; + return cpu_state.eaaddr; +} + + +static void +lods(int bits) +{ + cpu_state.eaaddr = SI; + if (bits == 16) + cpu_data = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); + else + cpu_data = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); + SI = string_increment(bits); +} + + +static void +stos(int bits) +{ + cpu_state.eaaddr = DI; + if (bits == 16) + writememw(es, cpu_state.eaaddr, cpu_data); + else + writememb(es, cpu_state.eaaddr, (uint8_t) (cpu_data & 0xff)); + DI = string_increment(bits); +} + + +static void +da(void) +{ + set_pzs(8); + wait(2, 0); +} + + +static void +aa(void) +{ + set_of(0); + AL &= 0x0f; + wait(6, 0); +} + + +static void +set_ca(void) +{ + set_cf(1); + set_af(1); +} + + +static void +clear_ca(void) +{ + set_cf(0); + set_af(0); +} + + +static uint16_t +get_ea(void) +{ + if (opcode & 1) + return geteaw(); + else + return (uint16_t) geteab(); +} + + +static uint16_t +get_reg(uint8_t reg) +{ + if (opcode & 1) + return cpu_state.regs[reg].w; + else + return (uint16_t) getr8(reg); +} + + +static void +set_ea(uint16_t val) +{ + if (opcode & 1) + seteaw(val); + else + seteab((uint8_t) (val & 0xff)); +} + + +static void +set_reg(uint8_t reg, uint16_t val) +{ + if (opcode & 1) + cpu_state.regs[reg].w = val; + else + setr8(reg, (uint8_t) (val & 0xff)); +} + + +static void +cpu_data_opff_rm(void) { + if (!(opcode & 1)) { + if (cpu_mod != 3) + cpu_data |= 0xff00; + else + cpu_data = cpu_state.regs[cpu_rm].w; + } +} + + +/* Executes instructions up to the specified number of cycles. */ +void +execx86(int cycs) +{ + uint8_t temp = 0, temp2; + uint16_t addr, tempw; + uint16_t new_cs, new_ip; + int bits; + + cycles += cycs; + + while (cycles > 0) { + clock_start(); + + if (!repeating) { + cpu_state.oldpc = cpu_state.pc; + opcode = pfq_fetchb(); + oldc = cpu_state.flags & C_FLAG; + if (clear_lock) { + in_lock = 0; + clear_lock = 0; + } + wait(1, 0); + } + + completed = 1; + switch (opcode) { + case 0x06: case 0x0E: case 0x16: case 0x1E: /* PUSH seg */ + access(29, 16); + push(&(_opseg[(opcode >> 3) & 0x03]->seg)); + break; + case 0x07: case 0x0F: case 0x17: case 0x1F: /* POP seg */ + access(22, 16); + if (opcode == 0x0F) { + loadcs(pop()); + pfq_pos = 0; + } else + loadseg(pop(), _opseg[(opcode >> 3) & 0x03]); + wait(1, 0); + /* All POP segment instructions suppress interrupts for one instruction. */ + noint = 1; + break; + + case 0x26: /*ES:*/ + case 0x2E: /*CS:*/ + case 0x36: /*SS:*/ + case 0x3E: /*DS:*/ + wait(1, 0); + ovr_seg = opseg[(opcode >> 3) & 0x03]; + completed = 0; + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x38: case 0x39: case 0x3a: case 0x3b: + /* alu rm, r / r, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(46, bits); + tempw = get_ea(); + cpu_alu_op = (opcode >> 3) & 7; + if ((opcode & 2) == 0) { + cpu_dest = tempw; + cpu_src = get_reg(cpu_reg); + } else { + cpu_dest = get_reg(cpu_reg); + cpu_src = tempw; + } + if (cpu_mod != 3) + wait(2, 0); + wait(1, 0); + alu_op(bits); + if (cpu_alu_op != 7) { + if ((opcode & 2) == 0) { + access(10, bits); + set_ea(cpu_data); + if (cpu_mod == 3) + wait(1, 0); + } else { + set_reg(cpu_reg, cpu_data); + wait(1, 0); } - while (c>0) - { - temp2=(temp&0x80)?1:0; - temp=(temp<<1)|temp2; - c--; - cycles-=4; - } - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; - seteab(temp); - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - case 0x08: /*ROR b,CL*/ - temp2=temp&1; - if (!c) - { - cycles-=((cpu_mod==3)?8:28); + } else + wait(1, 0); + break; + + case 0x04: case 0x05: case 0x0c: case 0x0d: + case 0x14: case 0x15: case 0x1c: case 0x1d: + case 0x24: case 0x25: case 0x2c: case 0x2d: + case 0x34: case 0x35: case 0x3c: case 0x3d: + /* alu A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_data = pfq_fetch(); + cpu_dest = get_reg(0); /* AX/AL */ + cpu_src = cpu_data; + cpu_alu_op = (opcode >> 3) & 7; + alu_op(bits); + if (cpu_alu_op != 7) + set_reg(0, cpu_data); + wait(1, 0); + break; + + case 0x27: /*DAA*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || (AL & 0x0f) > 9) { + cpu_data = AL + 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((cpu_state.flags & C_FLAG) || AL > 0x9f) { + AL += 0x60; + set_cf(1); + } + da(); + break; + case 0x2F: /*DAS*/ + wait(1, 0); + temp = AL; + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_data = AL - 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((cpu_state.flags & C_FLAG) || temp > 0x9f) { + AL -= 0x60; + set_cf(1); + } + da(); + break; + case 0x37: /*AAA*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL += 6; + ++AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); + break; + case 0x3F: /*AAS*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL -= 6; + --AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4A: case 0x4B: + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + /* INCDEC rw */ + wait(1, 0); + cpu_dest = cpu_state.regs[opcode & 7].w; + cpu_src = 1; + bits = 16; + if ((opcode & 8) == 0) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(16); + cpu_state.regs[opcode & 7].w = cpu_data; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + access(30, 16); + push(&(cpu_state.regs[opcode & 0x07].w)); + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + access(23, 16); + cpu_state.regs[opcode & 0x07].w = pop(); + wait(1, 0); + break; + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + jcc(opcode, cpu_state.flags & V_FLAG); + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + jcc(opcode, cpu_state.flags & C_FLAG); + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + jcc(opcode, cpu_state.flags & Z_FLAG); + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + jcc(opcode, cpu_state.flags & (C_FLAG | Z_FLAG)); + break; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + jcc(opcode, cpu_state.flags & N_FLAG); + break; + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + jcc(opcode, cpu_state.flags & P_FLAG); + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, temp ^ temp2); + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, (cpu_state.flags & Z_FLAG) || (temp != temp2)); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + /* alu rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(47, bits); + cpu_data = get_ea(); + cpu_dest = cpu_data; + if (cpu_mod != 3) + wait(3, 0); + if (opcode == 0x81) { + if (cpu_mod == 3) + wait(1, 0); + cpu_src = pfq_fetchw(); + } else { + if (cpu_mod == 3) + wait(1, 0); + if (opcode == 0x83) + cpu_src = sign_extend(pfq_fetchb()); + else + cpu_src = pfq_fetchb() | 0xff00; + } + wait(1, 0); + cpu_alu_op = (rmdat & 0x38) >> 3; + alu_op(bits); + if (cpu_alu_op != 7) { + access(11, bits); + set_ea(cpu_data); + } else { + if (cpu_mod != 3) + wait(1, 0); + } + break; + + case 0x84: case 0x85: + /* TEST rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(48, bits); + cpu_data = get_ea(); + test(bits, cpu_data, get_reg(cpu_reg)); + if (cpu_mod == 3) + wait(2, 0); + wait(2, 0); + break; + case 0x86: case 0x87: + /* XCHG rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(49, bits); + cpu_data = get_ea(); + cpu_src = get_reg(cpu_reg); + set_reg(cpu_reg, cpu_data); + wait(3, 0); + access(12, bits); + set_ea(cpu_src); + break; + + case 0x88: case 0x89: + /* MOV rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + access(13, bits); + set_ea(get_reg(cpu_reg)); + break; + case 0x8A: case 0x8B: + /* MOV reg, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(50, bits); + set_reg(cpu_reg, get_ea()); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0x8C: /*MOV w,sreg*/ + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(14, 16); + seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); + break; + + case 0x8D: /*LEA*/ + do_mod_rm(); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0x8E: /*MOV sreg,w*/ + do_mod_rm(); + access(51, 16); + tempw = geteaw(); + if ((rmdat & 0x18) == 0x08) { + loadcs(tempw); + pfq_pos = 0; + } else + loadseg(tempw, _opseg[(rmdat & 0x18) >> 3]); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + if (((rmdat & 0x18) >> 3) == 2) + noint = 1; + break; + + case 0x8F: /*POPW*/ + do_mod_rm(); + wait(1, 0); + cpu_src = cpu_state.eaaddr; + access(24, 16); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pop(); + cpu_state.eaaddr = cpu_src; + wait(2, 0); + access(15, 16); + seteaw(cpu_data); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + /* XCHG AX, rw */ + wait(1, 0); + cpu_data = cpu_state.regs[opcode & 7].w; + cpu_state.regs[opcode & 7].w = AX; + AX = cpu_data; + wait(1, 0); + break; + + case 0x98: /*CBW*/ + wait(1, 0); + AX = sign_extend(AL); + break; + case 0x99: /*CWD*/ + wait(4, 0); + if (!top_bit(AX, 16)) + DX = 0; + else { + wait(1, 0); + DX = 0xffff; + } + break; + case 0x9A: /*CALL FAR*/ + wait(1, 0); + new_ip = pfq_fetchw(); + wait(1, 0); + new_cs = pfq_fetchw(); + pfq_clear(); + access(31, 16); + push(&(CS)); + access(60, 16); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + set_ip(new_ip); + access(32, 16); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x9B: /*WAIT*/ + if (!repeating) + wait(2, 0); + wait(5, 0); +#ifdef NO_HACK + if (irq_pending()) { + wait(7, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } +#else + wait(7, 0); + check_interrupts(); +#endif + break; + case 0x9C: /*PUSHF*/ + access(33, 16); + tempw = (cpu_state.flags & 0x0fd7) | 0xf000; + push(&tempw); + break; + case 0x9D: /*POPF*/ + access(25, 16); + cpu_state.flags = pop() | 2; + wait(1, 0); + break; + case 0x9E: /*SAHF*/ + wait(1, 0); + cpu_state.flags = (cpu_state.flags & 0xff02) | AH; + wait(2, 0); + break; + case 0x9F: /*LAHF*/ + wait(1, 0); + AH = cpu_state.flags & 0xd7; + break; + + case 0xA0: case 0xA1: + /* MOV A, [iw] */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(1, bits); + set_reg(0, readmem((ovr_seg ? *ovr_seg : ds))); + wait(1, 0); + break; + case 0xA2: case 0xA3: + /* MOV [iw], A */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(7, bits); + writemem((ovr_seg ? *ovr_seg : ds), get_reg(0)); + break; + + case 0xA4: case 0xA5: /* MOVS */ + case 0xAC: case 0xAD: /* LODS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1, 0); + if ((opcode & 8) == 0 && in_rep != 0) + wait(1, 0); + } + if (rep_action(bits)) { + wait(1, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + if (in_rep != 0 && (opcode & 8) != 0) + wait(1, 0); + access(20, bits); + lods(bits); + if ((opcode & 8) == 0) { + access(27, bits); + stos(bits); + } else { + set_reg(0, cpu_data); + if (in_rep != 0) + wait(2, 0); + } + if (in_rep == 0) { + wait(3, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xA6: case 0xA7: /* CMPS */ + case 0xAE: case 0xAF: /* SCAS */ + bits = 8 << (opcode & 1); + if (!repeating) + wait(1, 0); + if (rep_action(bits)) { + wait(2, 0); + break; + } + if (in_rep != 0) + wait(1, 0); + wait(1, 0); + cpu_dest = get_reg(0); + if ((opcode & 8) == 0) { + access(21, bits); + lods(bits); + wait(1, 0); + cpu_dest = cpu_data; + } + access(2, bits); + cpu_state.eaaddr = DI; + cpu_data = readmem(es); + DI = string_increment(bits); + cpu_src = cpu_data; + sub(bits); + wait(2, 0); + if (in_rep == 0) { + wait(3, 0); + break; + } + if ((!!(cpu_state.flags & Z_FLAG)) == (in_rep == 1)) { + completed = 1; + wait(4, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xA8: case 0xA9: + /* TEST A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_data = pfq_fetch(); + test(bits, get_reg(0), cpu_data); + wait(1, 0); + break; + + case 0xAA: case 0xAB: /* STOS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1, 0); + if (in_rep != 0) + wait(1, 0); + } + if (rep_action(bits)) { + wait(1, 0); + break; + } + cpu_data = AX; + access(28, bits); + stos(bits); + if (in_rep == 0) { + wait(3, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xB0: case 0xB1: case 0xB2: case 0xB3: /*MOV cpu_reg,#8*/ + case 0xB4: case 0xB5: case 0xB6: case 0xB7: + wait(1, 0); + if (opcode & 0x04) + cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); + else + cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); + wait(1, 0); + break; + + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + wait(1, 0); + cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); + wait(1, 0); + break; + + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + /* RET */ + bits = 8 + (opcode & 0x08); + if ((opcode & 9) != 1) + wait(1, 0); + if (!(opcode & 1)) { + cpu_src = pfq_fetchw(); + wait(1, 0); + } + if ((opcode & 9) == 9) + wait(1, 0); + pfq_clear(); + access(26, bits); + new_ip = pop(); + wait(2, 0); + if ((opcode & 8) == 0) + new_cs = CS; + else { + access(42, bits); + new_cs = pop(); + if (opcode & 1) + wait(1, 0); + } + if (!(opcode & 1)) { + SP += cpu_src; + wait(1, 0); + } + loadcs(new_cs); + access(72, bits); + set_ip(new_ip); + break; + + case 0xC4: case 0xC5: + /* LsS rw, rmd */ + do_mod_rm(); + bits = 16; + access(52, bits); + read_ea(1, bits); + cpu_state.regs[cpu_reg].w = cpu_data; + access(57, bits); + read_ea2(bits); + loadseg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); + wait(1, 0); + break; + + case 0xC6: case 0xC7: + /* MOV rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pfq_fetch(); + if (cpu_mod == 3) + wait(1, 0); + access(16, bits); + set_ea(cpu_data); + break; + + case 0xCC: /*INT 3*/ + interrupt(3); + break; + case 0xCD: /*INT*/ + wait(1, 0); + interrupt(pfq_fetchb()); + break; + case 0xCE: /*INTO*/ + wait(3, 0); + if (cpu_state.flags & V_FLAG) { + wait(2, 0); + interrupt(4); + } + break; + + case 0xCF: /*IRET*/ + access(43, 8); + new_ip = pop(); + wait(3, 0); + access(44, 8); + new_cs = pop(); + loadcs(new_cs); + access(62, 8); + set_ip(new_ip); + access(45, 8); + cpu_state.flags = pop() | 2; + wait(5, 0); + noint = 1; + nmi_enable = 1; + break; + + case 0xD0: case 0xD1: case 0xD2: case 0xD3: + /* rot rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(53, bits); + cpu_data = get_ea(); + if ((opcode & 2) == 0) { + cpu_src = 1; + wait((cpu_mod != 3) ? 4 : 0, 0); + } else { + cpu_src = CL; + wait((cpu_mod != 3) ? 9 : 6, 0); + } + while (cpu_src != 0) { + cpu_dest = cpu_data; + oldc = cpu_state.flags & C_FLAG; + switch (rmdat & 0x38) { + case 0x00: /* ROL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0); + set_of_rotate(bits); + break; + case 0x08: /* ROR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (cpu_state.flags & C_FLAG) + cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); + set_of_rotate(bits); + break; + case 0x10: /* RCL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); + set_of_rotate(bits); + break; + case 0x18: /* RCR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (oldc) + cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); + set_cf((cpu_dest & 1) != 0); + set_of_rotate(bits); + break; + case 0x20: /* SHL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + set_of_rotate(bits); + set_pzs(bits); + break; + case 0x28: /* SHR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + break; + case 0x30: /* SETMO - undocumented? */ + bitwise(bits, 0xffff); + set_cf(0); + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + case 0x38: /* SAR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (!(opcode & 1)) + cpu_data |= (cpu_dest & 0x80); + else + cpu_data |= (cpu_dest & 0x8000); + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + break; + } + if ((opcode & 2) != 0) + wait(4, 0); + --cpu_src; + } + access(17, bits); + set_ea(cpu_data); + break; + + case 0xD4: /*AAM*/ + wait(1, 0); + cpu_src = pfq_fetchb(); + if (x86_div(AL, 0)) + set_pzs(16); + break; + case 0xD5: /*AAD*/ + wait(1, 0); + mul(pfq_fetchb(), AH); + AL += cpu_data; + AH = 0x00; + set_pzs(16); + break; + case 0xD6: /*SALC*/ + wait(1, 0); + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; + wait(1, 0); + break; + case 0xD7: /*XLATB*/ + cpu_state.eaaddr = (BX + AL) & 0xffff; + access(4, 8); + AL = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); + wait(1, 0); + break; + + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDD: case 0xDC: case 0xDE: case 0xDF: + /* esc i, r, rm */ + do_mod_rm(); + access(54, 16); + tempw = cpu_state.pc; + if (!hasfpu) + geteaw(); + else switch(opcode) { + case 0xD8: + ops_fpu_8087_d8[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); break; - } - while (c>0) - { - temp2=temp&1; - temp>>=1; - if (temp2) temp|=0x80; - c--; - cycles-=4; - } - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; - seteab(temp); - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - case 0x10: /*RCL b,CL*/ - while (c>0) - { - templ=flags&C_FLAG; - temp2=temp&0x80; - temp<<=1; - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; - if (templ) temp|=1; - c--; - cycles-=4; - } - seteab(temp); - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - case 0x18: /*RCR b,CL*/ - while (c>0) - { - templ=flags&C_FLAG; - temp2=temp&1; - temp>>=1; - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; - if (templ) temp|=0x80; - c--; - cycles-=4; - } - seteab(temp); - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - case 0x20: case 0x30: /*SHL b,CL*/ - if (c > 8) - { - temp = 0; - flags &= ~C_FLAG; - } - else - { - if ((temp<<(c-1))&0x80) flags|=C_FLAG; - else flags&=~C_FLAG; - temp<<=c; - } - seteab(temp); - setznp8(temp); - cycles-=(c*4); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - case 0x28: /*SHR b,CL*/ - if (c > 8) - { - temp = 0; - flags &= ~C_FLAG; - } - else - { - if ((temp>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - temp>>=c; - } - seteab(temp); - setznp8(temp); - cycles-=(c*4); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - case 0x38: /*SAR b,CL*/ - if ((temp>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - while (c>0) - { - temp>>=1; - if (temp&0x40) temp|=0x80; - c--; - cycles-=4; - } - seteab(temp); - setznp8(temp); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - } - break; - - case 0xD3: - fetchea(); - tempw=geteaw(); - c=CL; - if (!c) break; - switch (rmdat&0x38) - { - case 0x00: /*ROL w,CL*/ - while (c>0) - { - temp=(tempw&0x8000)?1:0; - tempw=(tempw<<1)|temp; - c--; - cycles-=4; - } - if (temp) flags|=C_FLAG; - else flags&=~C_FLAG; - seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - case 0x08: /*ROR w,CL*/ - tempw2=(tempw&1)?0x8000:0; - if (!c) - { - cycles-=((cpu_mod==3)?8:28); - break; - } - while (c>0) - { - tempw2=(tempw&1)?0x8000:0; - tempw=(tempw>>1)|tempw2; - c--; - cycles-=4; - } - if (tempw2) flags|=C_FLAG; - else flags&=~C_FLAG; - seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((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; - tempw=(tempw<<1)|templ; - c--; - cycles-=4; - } - if (temp) flags|=C_FLAG; - else flags&=~C_FLAG; - seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; - case 0x18: /*RCR w,CL*/ - templ=flags&C_FLAG; - tempw2=(templ&1)?0x8000:0; - if (!c) - { - cycles-=((cpu_mod==3)?8:28); + case 0xD9: + ops_fpu_8087_d9[rmdat & 0xff]((uint32_t) rmdat); break; + case 0xDA: + ops_fpu_8087_da[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDB: + ops_fpu_8087_db[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDC: + ops_fpu_8087_dc[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); + break; + case 0xDD: + ops_fpu_8087_dd[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDE: + ops_fpu_8087_de[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDF: + ops_fpu_8087_df[rmdat & 0xff]((uint32_t) rmdat); + break; + } + cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on + the 286+ core, but not here. */ + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0xE0: case 0xE1: case 0xE2: case 0xE3: + /* LOOP */ + wait(3, 0); + cpu_data = pfq_fetchb(); + if (opcode != 0xe2) + wait(1, 0); + if (opcode != 0xe3) { + --CX; + oldc = (CX != 0); + switch (opcode) { + case 0xE0: + if (cpu_state.flags & Z_FLAG) + oldc = 0; + break; + case 0xE1: + if (!(cpu_state.flags & Z_FLAG)) + oldc = 0; + break; } - while (c>0) - { - templ=flags&C_FLAG; - tempw2=(templ&1)?0x8000:0; - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw=(tempw>>1)|tempw2; - c--; - cycles-=4; - } - if (tempw2) flags|=C_FLAG; - else flags&=~C_FLAG; - seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; - cycles-=((cpu_mod==3)?8:28); - break; + } else + oldc = (CX == 0); + if (oldc) + jump_short(); + break; - case 0x20: case 0x30: /*SHL w,CL*/ - if (c>16) - { - tempw=0; - flags&=~C_FLAG; - } - else - { - if ((tempw<<(c-1))&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw<<=c; - } - seteaw(tempw); - setznp16(tempw); - cycles-=(c*4); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; + case 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xEC: case 0xED: case 0xEE: case 0xEF: + bits = 8 << (opcode & 1); + if ((opcode & 0x0e) != 0x0c) + wait(1, 0); + if ((opcode & 8) == 0) + cpu_data = pfq_fetchb(); + else + cpu_data = DX; + cpu_state.eaaddr = cpu_data; + if ((opcode & 2) == 0) { + access(3, bits); + if ((opcode & 1) && is8086 && !(cpu_data & 1)) { + AX = inw(cpu_data); + wait(4, 1); /* I/O access and wait state. */ + } else { + AL = inb(cpu_data); + if (opcode & 1) + AH = inb(cpu_data + 1); + wait(bits >> 1, 1); /* I/O access. */ + } + wait(1, 0); + } else { + if ((opcode & 8) == 0) + access(8, bits); + else + access(9, bits); + if ((opcode & 1) && is8086 && !(cpu_data & 1)) { + outw(cpu_data, AX); + wait(4, 1); + } else { + outb(cpu_data, AL); + if (opcode & 1) + outb(cpu_data + 1, AH); + wait(bits >> 1, 1); /* I/O access. */ + } + } + break; - case 0x28: /*SHR w,CL*/ - if (c > 16) - { - tempw = 0; - flags &= ~C_FLAG; - } - else - { - if ((tempw>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw>>=c; - } - seteaw(tempw); - setznp16(tempw); - cycles-=(c*4); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; + case 0xE8: /*CALL rel 16*/ + wait(1, 0); + cpu_state.oldpc = jump_near(); + access(34, 8); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0xE9: /*JMP rel 16*/ + wait(1, 0); + jump_near(); + break; + case 0xEA: /*JMP far*/ + wait(1, 0); + addr = pfq_fetchw(); + wait(1, 0); + tempw = pfq_fetchw(); + loadcs(tempw); + access(70, 8); + pfq_clear(); + set_ip(addr); + break; + case 0xEB: /*JMP rel*/ + wait(1, 0); + cpu_data = (int8_t) pfq_fetchb(); + jump_short(); + wait(1, 0); + break; - case 0x38: /*SAR w,CL*/ - tempw2=tempw&0x8000; - if ((tempw>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - while (c>0) - { - tempw=(tempw>>1)|tempw2; - c--; - cycles-=4; - } - seteaw(tempw); - setznp16(tempw); - cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; - break; - } - break; + case 0xF0: case 0xF1: /*LOCK - F1 is alias*/ + in_lock = 1; + wait(1, 0); + completed = 0; + break; - case 0xD4: /*AAM*/ - tempws=FETCH(); - AH=AL/tempws; - AL%=tempws; - setznp16(AX); - cycles-=83; - break; - case 0xD5: /*AAD*/ - tempws=FETCH(); - AL=(AH*tempws)+AL; - AH=0; - setznp16(AX); - cycles-=60; - break; - case 0xD6: /*SETALC*/ - AL = (flags & C_FLAG) ? 0xff : 0; - cycles -= 4; - break; - case 0xD7: /*XLAT*/ - addr=BX+AL; - cpu_state.last_ea = addr; - AL=readmemb(ds+addr); - cycles-=11; - break; - case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ - case 0xDC: case 0xDE: case 0xDF: case 0xD8: - fetchea(); - geteab(); - break; + case 0xF2: /*REPNE*/ + case 0xF3: /*REPE*/ + wait(1, 0); + in_rep = (opcode == 0xf2 ? 1 : 2); + completed = 0; + break; - case 0xE0: /*LOOPNE*/ - offset=(int8_t)FETCH(); - CX--; - if (CX && !(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=6; - break; - case 0xE1: /*LOOPE*/ - offset=(int8_t)FETCH(); - CX--; - if (CX && (flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=6; - break; - case 0xE2: /*LOOP*/ - offset=(int8_t)FETCH(); - CX--; - if (CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=5; - break; - case 0xE3: /*JCXZ*/ - offset=(int8_t)FETCH(); - if (!CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } - cycles-=6; - break; + case 0xF4: /*HLT*/ + if (!repeating) { + wait(1, 0); + pfq_clear(); + } + wait(1, 0); + if (irq_pending()) { + wait(cycles & 1, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } + break; + case 0xF5: /*CMC*/ + wait(1, 0); + cpu_state.flags ^= C_FLAG; + break; - case 0xE4: /*IN AL*/ - temp=FETCH(); - AL=inb(temp); - cycles-=14; - break; - case 0xE5: /*IN AX*/ - temp=FETCH(); - AL=inb(temp); - AH=inb(temp+1); - cycles-=14; - break; - case 0xE6: /*OUT AL*/ - temp=FETCH(); - outb(temp,AL); - cycles-=14; - break; - case 0xE7: /*OUT AX*/ - temp=FETCH(); - outb(temp,AL); - outb(temp+1,AH); - cycles-=14; - break; + case 0xF6: case 0xF7: + bits = 8 << (opcode & 1); + do_mod_rm(); + access(55, bits); + cpu_data = get_ea(); + switch (rmdat & 0x38) { + case 0x00: case 0x08: + /* TEST */ + wait(2, 0); + if (cpu_mod != 3) + wait(1, 0); + cpu_src = pfq_fetch(); + wait(1, 0); + test(bits, cpu_data, cpu_src); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x10: /* NOT */ + case 0x18: /* NEG */ + wait(2, 0); + if ((rmdat & 0x38) == 0x10) + cpu_data = ~cpu_data; + else { + cpu_src = cpu_data; + cpu_dest = 0; + sub(bits); + } + access(18, bits); + set_ea(cpu_data); + break; + case 0x20: /* MUL */ + case 0x28: /* IMUL */ + wait(1, 0); + if (opcode & 1) { + mul(AX, cpu_data); + AX = cpu_data; + DX = cpu_dest; + cpu_data |= DX; + set_co_mul(DX != ((AX & 0x8000) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); + } else { + mul(AL, cpu_data); + AL = (uint8_t) cpu_data; + AH = (uint8_t) cpu_dest; + cpu_data |= AH; + set_co_mul(AH != ((AL & 0x80) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xff)); + } + /* NOTE: When implementing the V20, care should be taken to not change + the zero flag. */ + set_zf(bits); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x30: /* DIV */ + case 0x38: /* IDIV */ + if (cpu_mod != 3) + wait(1, 0); + cpu_src = cpu_data; + if (x86_div(AL, AH)) + wait(1, 0); + break; + } + break; - case 0xE8: /*CALL rel 16*/ - tempw=getword(); - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),cpu_state.pc); - SP-=2; - cpu_state.last_ea = SP; - cpu_state.pc+=tempw; - cycles-=23; - FETCHCLEAR(); - break; - case 0xE9: /*JMP rel 16*/ - tempw = getword(); - cpu_state.pc += tempw; - cycles-=15; - FETCHCLEAR(); - break; - case 0xEA: /*JMP far*/ - addr=getword(); - tempw=getword(); - cpu_state.pc=addr; - loadcs(tempw); - cycles-=15; - FETCHCLEAR(); - break; - case 0xEB: /*JMP rel*/ - offset=(int8_t)FETCH(); - cpu_state.pc+=offset; - cycles-=15; - FETCHCLEAR(); - break; - case 0xEC: /*IN AL,DX*/ - AL=inb(DX); - cycles-=12; - break; - case 0xED: /*IN AX,DX*/ - AL=inb(DX); - AH=inb(DX+1); - cycles-=12; - break; - case 0xEE: /*OUT DX,AL*/ - outb(DX,AL); - cycles-=12; - break; - case 0xEF: /*OUT DX,AX*/ - outb(DX,AL); - outb(DX+1,AH); - cycles-=12; - break; + case 0xF8: case 0xF9: + /* CLCSTC */ + wait(1, 0); + set_cf(opcode & 1); + break; + case 0xFA: case 0xFB: + /* CLISTI */ + wait(1, 0); + set_if(opcode & 1); + break; + case 0xFC: case 0xFD: + /* CLDSTD */ + wait(1, 0); + set_df(opcode & 1); + break; - case 0xF0: /*LOCK*/ - case 0xF1: /*LOCK alias*/ - cycles-=4; - break; + case 0xFE: case 0xFF: + /* misc */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(56, bits); + read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); + switch (rmdat & 0x38) { + case 0x00: /* INC rm */ + case 0x08: /* DEC rm */ + cpu_dest = cpu_data; + cpu_src = 1; + if ((rmdat & 0x38) == 0x00) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(bits); + wait(2, 0); + access(19, bits); + set_ea(cpu_data); + break; + case 0x10: /* CALL rm */ + cpu_data_opff_rm(); + access(63, bits); + wait(1, 0); + pfq_clear(); + wait(4, 0); + if (cpu_mod != 3) + wait(1, 0); + wait(1, 0); /* Wait. */ + cpu_state.oldpc = cpu_state.pc; + set_ip(cpu_data); + wait(2, 0); + access(35, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x18: /* CALL rmd */ + new_ip = cpu_data; + access(58, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + access(36, bits); + push(&(CS)); + access(64, bits); + wait(4, 0); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + set_ip(new_ip); + access(37, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x20: /* JMP rm */ + cpu_data_opff_rm(); + access(65, bits); + set_ip(cpu_data); + break; + case 0x28: /* JMP rmd */ + new_ip = cpu_data; + access(59, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + loadcs(new_cs); + access(66, bits); + set_ip(new_ip); + break; + case 0x30: /* PUSH rm */ + case 0x38: + if (cpu_mod != 3) + wait(1, 0); + access(38, bits); + push(&(cpu_data)); + break; + } + break; - case 0xF2: /*REPNE*/ - rep(0); - break; - case 0xF3: /*REPE*/ - rep(1); - break; + default: + x808x_log("Illegal opcode: %02X\n", opcode); + pfq_fetchb(); + wait(8, 0); + break; + } - case 0xF4: /*HLT*/ - inhlt=1; - cpu_state.pc--; - FETCHCLEAR(); - cycles-=2; - break; - case 0xF5: /*CMC*/ - flags^=C_FLAG; - cycles-=2; - break; + if (completed) { + repeating = 0; + ovr_seg = NULL; + in_rep = 0; + if (in_lock) + clear_lock = 1; + clock_end(); + check_interrupts(); - case 0xF6: - fetchea(); - temp=geteab(); - switch (rmdat&0x38) - { - case 0x00: /*TEST b,#8*/ - case 0x08: - temp2=FETCH(); - temp&=temp2; - setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=((cpu_mod==3)?5:11); - break; - case 0x10: /*NOT b*/ - temp=~temp; - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x18: /*NEG b*/ - setsub8(0,temp); - temp=0-temp; - seteab(temp); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x20: /*MUL AL,b*/ - setznp8(AL); - AX=AL*temp; - if (AX) flags&=~Z_FLAG; - else flags|=Z_FLAG; - if (AH) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles-=70; - break; - case 0x28: /*IMUL AL,b*/ - setznp8(AL); - tempws=(int)((int8_t)AL)*(int)((int8_t)temp); - AX=tempws&0xFFFF; - if (AX) flags&=~Z_FLAG; - else flags|=Z_FLAG; - if (AH) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles-=80; - break; - case 0x30: /*DIV AL,b*/ - tempw=AX; - if (temp) - { - tempw2=tempw%temp; - AH=tempw2 & 0xff; - tempw/=temp; - AL=tempw&0xFF; - } - else - { - x808x_log("DIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,0); - loadcs(readmemw(0,2)); - FETCHCLEAR(); - } - cycles-=80; - break; - case 0x38: /*IDIV AL,b*/ - tempws=(int)AX; - if (temp) - { - tempw2=tempws%(int)((int8_t)temp); - AH=tempw2&0xFF; - tempws/=(int)((int8_t)temp); - AL=tempws&0xFF; - } - else - { - x808x_log("IDIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,0); - loadcs(readmemw(0,2)); - FETCHCLEAR(); - } - cycles-=101; - break; - } - break; + if (noint) + noint = 0; + } - case 0xF7: - fetchea(); - tempw=geteaw(); - switch (rmdat&0x38) - { - case 0x00: /*TEST w*/ - case 0x08: - tempw2=getword(); - setznp16(tempw&tempw2); - flags&=~(C_FLAG|V_FLAG|A_FLAG); - cycles-=((cpu_mod==3)?5:11); - break; - case 0x10: /*NOT w*/ - seteaw(~tempw); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x18: /*NEG w*/ - setsub16(0,tempw); - tempw=0-tempw; - seteaw(tempw); - cycles-=((cpu_mod==3)?3:24); - break; - case 0x20: /*MUL AX,w*/ - setznp16(AX); - templ=AX*tempw; - AX=templ&0xFFFF; - DX=templ>>16; - if (AX|DX) flags&=~Z_FLAG; - else flags|=Z_FLAG; - if (DX) flags|=(C_FLAG|V_FLAG); - else flags&=~(C_FLAG|V_FLAG); - cycles-=118; - break; - case 0x28: /*IMUL AX,w*/ - setznp16(AX); - 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); - AX=tempws&0xFFFF; - tempws=(uint16_t)(tempws>>16); - DX=tempws&0xFFFF; - if (AX|DX) flags&=~Z_FLAG; - else flags|=Z_FLAG; - cycles-=128; - break; - case 0x30: /*DIV AX,w*/ - templ=(DX<<16)|AX; - if (tempw) - { - tempw2=templ%tempw; - DX=tempw2; - templ/=tempw; - AX=templ&0xFFFF; - } - else - { - x808x_log("DIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,0); - loadcs(readmemw(0,2)); - FETCHCLEAR(); - } - cycles-=144; - break; - case 0x38: /*IDIV AX,w*/ - tempws=(int)((DX<<16)|AX); - if (tempw) - { - tempw2=tempws%(int)((int16_t)tempw); - DX=tempw2; - tempws/=(int)((int16_t)tempw); - AX=tempws&0xFFFF; - } - else - { - x808x_log("IDIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); - writememw(ss,(SP-4)&0xFFFF,CS); - writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); - SP-=6; - flags&=~I_FLAG; - flags&=~T_FLAG; - cpu_state.pc=readmemw(0,0); - loadcs(readmemw(0,2)); - FETCHCLEAR(); - } - cycles-=165; - break; - } - break; - - case 0xF8: /*CLC*/ - flags&=~C_FLAG; - cycles-=2; - break; - case 0xF9: /*STC*/ - flags|=C_FLAG; - cycles-=2; - break; - case 0xFA: /*CLI*/ - flags&=~I_FLAG; - cycles-=3; - break; - case 0xFB: /*STI*/ - flags|=I_FLAG; - cycles-=2; - break; - case 0xFC: /*CLD*/ - flags&=~D_FLAG; - cycles-=2; - break; - case 0xFD: /*STD*/ - flags|=D_FLAG; - cycles-=2; - break; - - case 0xFE: /*INC/DEC b*/ - fetchea(); - temp=geteab(); - flags&=~V_FLAG; - if (rmdat&0x38) - { - setsub8nc(temp,1); - temp2=temp-1; - if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; - } - else - { - setadd8nc(temp,1); - temp2=temp+1; - if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; - } - seteab(temp2); - cycles-=((cpu_mod==3)?3:23); - break; - - case 0xFF: - fetchea(); - switch (rmdat&0x38) - { - case 0x00: /*INC w*/ - tempw=geteaw(); - setadd16nc(tempw,1); - seteaw(tempw+1); - cycles-=((cpu_mod==3)?3:23); - break; - case 0x08: /*DEC w*/ - tempw=geteaw(); - setsub16nc(tempw,1); - seteaw(tempw-1); - cycles-=((cpu_mod==3)?3:23); - break; - case 0x10: /*CALL*/ - tempw=geteaw(); - if (cpu_state.ssegs) ss=oldss; - writememw(ss,(SP-2)&0xFFFF,cpu_state.pc); - SP-=2; - cpu_state.last_ea = SP; - cpu_state.pc=tempw; - cycles-=((cpu_mod==3)?20:29); - FETCHCLEAR(); - break; - case 0x18: /*CALL far*/ - tempw=readmemw(easeg,cpu_state.eaaddr); - tempw2=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); - tempw3=CS; - tempw4=cpu_state.pc; - if (cpu_state.ssegs) ss=oldss; - cpu_state.pc=tempw; - loadcs(tempw2); - writememw(ss,(SP-2)&0xFFFF,tempw3); - writememw(ss,((SP-4)&0xFFFF),tempw4); - SP-=4; - cpu_state.last_ea = SP; - cycles-=53; - FETCHCLEAR(); - break; - case 0x20: /*JMP*/ - cpu_state.pc=geteaw(); - cycles-=((cpu_mod==3)?11:18); - FETCHCLEAR(); - break; - case 0x28: /*JMP far*/ - cpu_state.pc=readmemw(easeg,cpu_state.eaaddr); - loadcs(readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF)); - cycles-=24; - FETCHCLEAR(); - break; - case 0x30: /*PUSH w*/ - case 0x38: /*PUSH w alias, reported by reenigne*/ - tempw=geteaw(); - if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),tempw); - SP-=2; - cpu_state.last_ea = SP; - cycles-=((cpu_mod==3)?15:24); - break; - } - break; - - default: - FETCH(); - cycles-=8; - break; - } - cpu_state.pc&=0xFFFF; - - if (cpu_state.ssegs) - { - ds=oldds; - ss=oldss; - cpu_state.ssegs=0; - } - - FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); - if ((cycdiff-cycles)checked) return; - if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; if (IS_32_ADDR(&seg->base)) @@ -893,14 +893,14 @@ static inline void CHECK_SEG_READ(x86seg *seg) static inline void CHECK_SEG_WRITE(x86seg *seg) { /*Segments always valid in real/V86 mode*/ - if (!(cr0 & 1) || (eflags & VM_FLAG)) + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) return; /*CS and SS must always be valid*/ - if (seg == &_cs || seg == &_ss) + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) return; if (seg->checked) return; - if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; if (IS_32_ADDR(&seg->base)) @@ -928,7 +928,7 @@ static inline void CHECK_SEG_WRITE(x86seg *seg) } static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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; if (IS_32_ADDR(&seg->base)) @@ -967,7 +967,7 @@ static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1040,7 +1040,7 @@ static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1126,7 +1126,7 @@ static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) } static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1204,7 +1204,7 @@ static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1325,7 +1325,7 @@ static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) addbyte(8); host_reg = 8; } - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1409,7 +1409,7 @@ static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1500,7 +1500,7 @@ static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1589,7 +1589,7 @@ static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -5270,7 +5270,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -5321,7 +5321,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) addbyte(0xc1); /*SHR EDI, 12*/ addbyte(0xef); addbyte(12); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xfe); @@ -5352,7 +5352,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) jump2 = &codeblock[block_current].data[block_pos]; addbyte(0); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; /*slowpath:*/ addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ @@ -5385,7 +5385,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -5433,7 +5433,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) addbyte(0x79); /*JNS +*/ jump1 = &codeblock[block_current].data[block_pos]; addbyte(0); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xfe); @@ -5442,7 +5442,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) addbyte(0x8d); /*LEA ESI, 1[EDI]*/ addbyte(0x77); addbyte(0x01); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x74); /*JE slowpath*/ jump4 = &codeblock[block_current].data[block_pos]; @@ -5498,7 +5498,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) /*slowpath:*/ *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; jump_pos = block_pos; load_param_1_reg_32(REG_EBX); @@ -5534,7 +5534,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -5582,7 +5582,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) addbyte(0x79); /*JNS +*/ jump1 = &codeblock[block_current].data[block_pos]; addbyte(0); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xfe); @@ -5591,7 +5591,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) addbyte(0x8d); /*LEA ESI, 3[EDI]*/ addbyte(0x77); addbyte(0x03); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x74); /*JE slowpath*/ jump4 = &codeblock[block_current].data[block_pos]; @@ -5647,7 +5647,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) /*slowpath:*/ *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; jump_pos = block_pos; load_param_1_reg_32(REG_EBX); @@ -5678,7 +5678,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -5750,7 +5750,7 @@ static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) } static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -5828,7 +5828,7 @@ static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) } static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -5928,7 +5928,7 @@ static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) addbyte(8); host_reg = 8; } - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EBX, EBX*/ addbyte(0xdb); @@ -6005,7 +6005,7 @@ static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EBX, EBX*/ addbyte(0xdb); @@ -6089,7 +6089,7 @@ static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EBX, EBX*/ addbyte(0xdb); diff --git a/src/cpu/codegen_ops_x86.h b/src/cpu/codegen_ops_x86.h index 8f38b3cdf..225490cd3 100644 --- a/src/cpu/codegen_ops_x86.h +++ b/src/cpu/codegen_ops_x86.h @@ -611,14 +611,14 @@ static inline void SAR_L_IMM(int reg, int count) static inline void CHECK_SEG_READ(x86seg *seg) { /*Segments always valid in real/V86 mode*/ - if (!(cr0 & 1) || (eflags & VM_FLAG)) + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) return; /*CS and SS must always be valid*/ - if (seg == &_cs || seg == &_ss) + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) return; if (seg->checked) return; - if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; addbyte(0x83); /*CMP seg->base, -1*/ @@ -634,14 +634,14 @@ static inline void CHECK_SEG_READ(x86seg *seg) static inline void CHECK_SEG_WRITE(x86seg *seg) { /*Segments always valid in real/V86 mode*/ - if (!(cr0 & 1) || (eflags & VM_FLAG)) + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) return; /*CS and SS must always be valid*/ - if (seg == &_cs || seg == &_ss) + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) return; if (seg->checked) return; - if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; addbyte(0x83); /*CMP seg->base, -1*/ @@ -656,7 +656,7 @@ static inline void CHECK_SEG_WRITE(x86seg *seg) } static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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; addbyte(0x3b); /*CMP EAX, seg->limit_low*/ @@ -684,7 +684,7 @@ static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -702,7 +702,7 @@ static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) } static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -722,7 +722,7 @@ static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -740,7 +740,7 @@ static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -761,7 +761,7 @@ static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) } static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -781,7 +781,7 @@ static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -800,7 +800,7 @@ static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) } static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -821,7 +821,7 @@ static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -859,7 +859,7 @@ static inline void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -880,7 +880,7 @@ static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -901,7 +901,7 @@ static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -922,7 +922,7 @@ static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -943,7 +943,7 @@ static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -964,7 +964,7 @@ static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -995,7 +995,7 @@ static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) addbyte(0x89); /*MOV ECX, host_reg2*/ addbyte(0xc0 | REG_ECX | (host_reg2 << 3)); } - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -1087,7 +1087,7 @@ static inline x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_s addlong(0xffff); if (mod1seg[rm] == &ss && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; } return op_ea_seg; } @@ -1154,7 +1154,7 @@ static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_s } } if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (((sib >> 3) & 7) != 4) { switch (sib >> 6) @@ -1199,7 +1199,7 @@ static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_s if (mod) { if (rm == 5 && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (mod == 1) { addbyte(0x83); /*ADD EAX, imm8*/ @@ -3919,7 +3919,7 @@ static inline void LOAD_EA() static inline void MEM_CHECK_WRITE(x86seg *seg) { CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -3937,7 +3937,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) static inline void MEM_CHECK_WRITE_W(x86seg *seg) { CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -3955,7 +3955,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) static inline void MEM_CHECK_WRITE_L(x86seg *seg) { CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + 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))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); diff --git a/src/cpu/codegen_timing_pentium.c b/src/cpu/codegen_timing_pentium.c index 60a6fbea0..88c4e9544 100644 --- a/src/cpu/codegen_timing_pentium.c +++ b/src/cpu/codegen_timing_pentium.c @@ -817,7 +817,7 @@ static inline int COUNT(uint64_t timings, uint64_t deps, 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 %016llx\n", timings); @@ -950,13 +950,13 @@ void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) last_prefix = prefix; return; } - if (cpu_hasMMX && prefix == 0x0f) + 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_offset += 2; @@ -1223,7 +1223,7 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) else has_displacement = 0; - if (!has_displacement && (!cpu_hasMMX || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + 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; @@ -1276,7 +1276,7 @@ nopair: else has_displacement = 0; - if ((!has_displacement || cpu_hasMMX) && (!cpu_hasMMX || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + 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; diff --git a/src/cpu/codegen_x86-64.c b/src/cpu/codegen_x86-64.c index 7f373c163..42136207c 100644 --- a/src/cpu/codegen_x86-64.c +++ b/src/cpu/codegen_x86-64.c @@ -376,7 +376,7 @@ void codegen_block_start_recompile(codeblock_t *block) 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; + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = (cr0 & 1) ? 0 : 1; codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; @@ -692,7 +692,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, addbyte((uint8_t)cpu_state_offset(eaaddr)); if (mod1seg[cpu_rm] == &ss && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; } return op_ea_seg; } @@ -840,7 +840,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, addlong(stack_offset); } if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; addbyte(0x89); /*MOV eaaddr, EAX*/ addbyte(0x45); @@ -864,7 +864,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, if (cpu_mod) { if (cpu_rm == 5 && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (cpu_mod == 1) { addbyte(0x67); /*LEA EAX, base_reg+imm8*/ @@ -904,7 +904,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t codeblock_t *block = &codeblock[block_current]; uint32_t op_32 = use32; uint32_t op_pc = new_pc; - OpFn *op_table = x86_dynarec_opcodes; + const OpFn *op_table = (OpFn *) x86_dynarec_opcodes; RecompOpFn *recomp_op_table = recomp_opcodes; int opcode_shift = 0; int opcode_mask = 0x3ff; @@ -913,7 +913,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t int test_modrm = 1; int c; - op_ea_seg = &_ds; + op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; op_old_pc = old_pc; @@ -935,27 +935,27 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0x26: /*ES:*/ - op_ea_seg = &_es; + op_ea_seg = &cpu_state.seg_es; op_ssegs = 1; break; case 0x2e: /*CS:*/ - op_ea_seg = &_cs; + op_ea_seg = &cpu_state.seg_cs; op_ssegs = 1; break; case 0x36: /*SS:*/ - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; op_ssegs = 1; break; case 0x3e: /*DS:*/ - op_ea_seg = &_ds; + op_ea_seg = &cpu_state.seg_ds; op_ssegs = 1; break; case 0x64: /*FS:*/ - op_ea_seg = &_fs; + op_ea_seg = &cpu_state.seg_fs; op_ssegs = 1; break; case 0x65: /*GS:*/ - op_ea_seg = &_gs; + op_ea_seg = &cpu_state.seg_gs; op_ssegs = 1; break; diff --git a/src/cpu/codegen_x86.c b/src/cpu/codegen_x86.c index e7d53ea9f..a3352943f 100644 --- a/src/cpu/codegen_x86.c +++ b/src/cpu/codegen_x86.c @@ -36,7 +36,7 @@ * Boston, MA 02111-1307 * USA. */ -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32 +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 #include #include @@ -1495,7 +1495,7 @@ void codegen_block_start_recompile(codeblock_t *block) 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; + 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; block->was_recompiled = 1; @@ -1735,7 +1735,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, addlong((uint32_t)&cpu_state.eaaddr); if (mod1seg[cpu_rm] == &ss && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; } return op_ea_seg; } @@ -1791,7 +1791,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, addlong(stack_offset); } if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (((sib >> 3) & 7) != 4) { switch (sib >> 6) @@ -1840,7 +1840,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, if (cpu_mod) { if (cpu_rm == 5 && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (cpu_mod == 1) { addbyte(0x05); @@ -1875,7 +1875,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t int test_modrm = 1; int c; - op_ea_seg = &_ds; + op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; op_old_pc = old_pc; @@ -1898,27 +1898,27 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0x26: /*ES:*/ - op_ea_seg = &_es; + op_ea_seg = &cpu_state.seg_es; op_ssegs = 1; break; case 0x2e: /*CS:*/ - op_ea_seg = &_cs; + op_ea_seg = &cpu_state.seg_cs; op_ssegs = 1; break; case 0x36: /*SS:*/ - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; op_ssegs = 1; break; case 0x3e: /*DS:*/ - op_ea_seg = &_ds; + op_ea_seg = &cpu_state.seg_ds; op_ssegs = 1; break; case 0x64: /*FS:*/ - op_ea_seg = &_fs; + op_ea_seg = &cpu_state.seg_fs; op_ssegs = 1; break; case 0x65: /*GS:*/ - op_ea_seg = &_gs; + op_ea_seg = &cpu_state.seg_gs; op_ssegs = 1; break; @@ -2131,7 +2131,7 @@ generate_call: if (op_ea_seg != last_ea_seg) { last_ea_seg = op_ea_seg; - addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ + addbyte(0xC7); /*MOVL $&cpu_state.seg_ds,(ea_seg)*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(ea_seg)); addlong((uint32_t)op_ea_seg); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index cd5804b71..891790823 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -49,12 +49,20 @@ #include "../io.h" #include "x86_ops.h" #include "../mem.h" +#include "../nmi.h" +#include "../pic.h" #include "../pci.h" #ifdef USE_DYNAREC # include "codegen.h" #endif +#if 1 +static void cpu_write(uint16_t addr, uint8_t val, void *priv); +static uint8_t cpu_read(uint16_t addr, void *priv); +#endif + + enum { CPUID_FPU = (1 << 0), CPUID_VME = (1 << 1), @@ -114,13 +122,15 @@ const OpFn *x86_opcodes_df_a32; const OpFn *x86_opcodes_REPE; const OpFn *x86_opcodes_REPNE; +int in_smm = 0, smi_line = 0, smi_latched = 0; +uint32_t smbase = 0x30000; + CPU *cpu_s; int cpu_effective; int cpu_multi; int cpu_16bitbus; int cpu_busspeed; int cpu_cyrix_alignment; -int cpuspeed; int CPUID; uint64_t cpu_CR4_mask; int isa_cycles; @@ -130,21 +140,19 @@ 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 cpu_pci_speed; +int cpu_pci_speed, cpu_alt_reset; + +uint32_t cpu_features; int is286, is386, is486, cpu_iscyrix, + isibmcpu, israpidcad, is_pentium; -int hasfpu, - cpu_hasrdtsc, - cpu_hasMMX, - cpu_hasMSR, - cpu_hasCR4, - cpu_hasVME; +int hasfpu; uint64_t tsc = 0; @@ -205,6 +213,11 @@ int timing_misaligned; static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; +int cpu_has_feature(int feature) +{ + return cpu_features & feature; +} + void cpu_dynamic_switch(int new_cpu) @@ -236,36 +249,39 @@ cpu_set(void) cpu_manufacturer = 0; cpu = 0; } - + cpu_effective = cpu; cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + cpu_alt_reset = 0; + CPUID = cpu_s->cpuid_model; - cpuspeed = cpu_s->speed; is8086 = (cpu_s->cpu_type > CPU_8088); is286 = (cpu_s->cpu_type >= CPU_286); is386 = (cpu_s->cpu_type >= CPU_386SX); + isibmcpu = (cpu_s->cpu_type == CPU_IBM386SLC || cpu_s->cpu_type == CPU_IBM486SLC || cpu_s->cpu_type == CPU_IBM486BL); israpidcad = (cpu_s->cpu_type == CPU_RAPIDCAD); - is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_RAPIDCAD); - is_pentium= (cpu_s->cpu_type >= CPU_WINCHIP); + is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_RAPIDCAD || cpu_s->cpu_type == CPU_IBM486SLC || cpu_s->cpu_type == CPU_IBM486BL ); + is_pentium = (cpu_s->cpu_type >= CPU_WINCHIP); hasfpu = (cpu_s->cpu_type >= CPU_i486DX) || (cpu_s->cpu_type == CPU_RAPIDCAD); +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) 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; +#else + 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); +#endif + + cpu_16bitbus = (cpu_s->cpu_type == CPU_286 || cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_IBM386SLC || cpu_s->cpu_type == CPU_IBM486SLC ); + + 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; - if ((cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || (cpu_s->cpu_type == CPU_386DX) || (cpu_s->cpu_type == CPU_i486SX)) - { - if (enable_external_fpu) - { - hasfpu = 1; - } + if ((cpu_s->cpu_type == CPU_8088) || (cpu_s->cpu_type == CPU_8086) || + (cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || + (cpu_s->cpu_type == CPU_386DX) || (cpu_s->cpu_type == CPU_i486SX)) { + hasfpu = !!enable_external_fpu; } cpu_update_waitstates(); @@ -289,10 +305,15 @@ cpu_set(void) } if (cpu_iscyrix) - io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); + io_sethandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); else - io_removehandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); - + io_removehandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + + if (hasfpu) + io_sethandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + else + io_removehandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + #ifdef USE_DYNAREC x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); #else @@ -466,6 +487,7 @@ cpu_set(void) timing_jmp_pm_gate = 38; break; + case CPU_IBM386SLC: case CPU_386SX: timing_rr = 2; /*register dest - register src*/ timing_rm = 6; /*register dest - memory src*/ @@ -528,6 +550,80 @@ cpu_set(void) timing_jmp_pm_gate = 45; break; + case CPU_IBM486SLC: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 5; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 4; /*register dest - memory src long*/ + timing_mrl = 5; /*memory dest - register src long*/ + timing_mml = 5; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_IBM486BL: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + case CPU_RAPIDCAD: timing_rr = 1; /*register dest - register src*/ timing_rm = 2; /*register dest - memory src*/ @@ -636,8 +732,7 @@ cpu_set(void) break; case CPU_iDX4: - cpu_hasCR4 = 1; - cpu_hasVME = 1; + cpu_features = CPU_FEATURE_CR4 | CPU_FEATURE_VME; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; case CPU_i486SX: case CPU_i486DX: @@ -807,10 +902,8 @@ cpu_set(void) timing_mml = 3; timing_bt = 3-1; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = cpu_hasMSR = 1; - cpu_hasCR4 = 1; cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; /*unknown*/ timing_int_rm = 26; @@ -873,12 +966,8 @@ cpu_set(void) timing_jmp_pm = 3; timing_jmp_pm_gate = 18; timing_misaligned = 3; - cpu_hasrdtsc = 1; + 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_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_pentium); @@ -920,18 +1009,15 @@ cpu_set(void) timing_jmp_pm = 3; timing_jmp_pm_gate = 18; timing_misaligned = 3; - cpu_hasrdtsc = 1; + 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_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_pentium); #endif break; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) case CPU_Cx6x86: #ifdef USE_DYNAREC x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); @@ -967,11 +1053,8 @@ cpu_set(void) timing_jmp_pm_gate = 14; timing_misaligned = 2; cpu_cyrix_alignment = 1; - cpu_hasrdtsc = 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; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); #endif @@ -1013,11 +1096,8 @@ cpu_set(void) timing_jmp_pm_gate = 14; timing_misaligned = 2; cpu_cyrix_alignment = 1; - cpu_hasrdtsc = 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; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); #endif @@ -1042,11 +1122,8 @@ cpu_set(void) timing_bnt = 1; /*branch not taken*/ timing_misaligned = 2; cpu_cyrix_alignment = 1; - 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; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); @@ -1101,17 +1178,15 @@ cpu_set(void) timing_jmp_pm_gate = 14; timing_misaligned = 2; cpu_cyrix_alignment = 1; - cpu_hasrdtsc = 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; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); #endif ccr4 = 0x80; break; +#endif #if defined(DEV_BRANCH) && defined(USE_AMD_K) case CPU_K5: @@ -1131,11 +1206,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + 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; break; @@ -1155,12 +1227,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + 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_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_pentium); @@ -1197,12 +1265,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + 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_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); @@ -1238,12 +1302,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + 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_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); @@ -1279,12 +1339,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + 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_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE | CR4_OSFXSR; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); @@ -1410,7 +1466,7 @@ cpu_CPUID(void) EAX = 0x540; EBX = ECX = 0; EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; - if (msr.fcr & (1 << 1)) + if (cpu_has_feature(CPU_FEATURE_CX8)) EDX |= CPUID_CMPXCHG8B; if (msr.fcr & (1 << 9)) EDX |= CPUID_MMX; @@ -1590,6 +1646,7 @@ cpu_CPUID(void) break; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) case CPU_Cx6x86: if (!EAX) { @@ -1665,6 +1722,7 @@ cpu_CPUID(void) else EAX = EBX = ECX = EDX = 0; break; +#endif #ifdef DEV_BRANCH #ifdef USE_I686 @@ -1820,6 +1878,7 @@ void cpu_RDMSR() break; } break; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) case CPU_Cx6x86: case CPU_Cx6x86L: case CPU_CxGX1: @@ -1832,6 +1891,7 @@ void cpu_RDMSR() break; } break; +#endif #ifdef DEV_BRANCH #ifdef USE_I686 @@ -1953,6 +2013,7 @@ void cpu_RDMSR() break; default: i686_invalid_rdmsr: + pclog("Invalid MSR read %08X\n", ECX); x86gpf(NULL, 0); break; } @@ -1983,11 +2044,18 @@ void cpu_WRMSR() break; case 0x107: msr.fcr = EAX; - cpu_hasMMX = EAX & (1 << 9); - if (EAX & (1 << 29)) - CPUID = 0; + if (EAX & (1 << 9)) + cpu_features |= CPU_FEATURE_MMX; else - CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpuid_model; + cpu_features &= ~CPU_FEATURE_MMX; + if (EAX & (1 << 1)) + cpu_features |= CPU_FEATURE_CX8; + else + cpu_features &= ~CPU_FEATURE_CX8; + if (EAX & (1 << 29)) + CPUID = 0; + else + CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; break; case 0x108: msr.fcr2 = EAX | ((uint64_t)EDX << 32); @@ -2032,6 +2100,7 @@ void cpu_WRMSR() break; } break; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) case CPU_Cx6x86: case CPU_Cx6x86L: case CPU_CxGX1: @@ -2043,6 +2112,7 @@ void cpu_WRMSR() break; } break; +#endif #ifdef DEV_BRANCH #ifdef USE_I686 @@ -2132,6 +2202,7 @@ void cpu_WRMSR() break; default: i686_invalid_wrmsr: + pclog("Invalid MSR write %08X: %08X%08X\n", ECX, EDX, EAX); x86gpf(NULL, 0); break; } @@ -2143,8 +2214,18 @@ i686_invalid_wrmsr: static int cyrix_addr; -void cyrix_write(uint16_t addr, uint8_t val, void *priv) +static void cpu_write(uint16_t addr, uint8_t val, void *priv) { + if (addr == 0xf0) { + /* Writes to F0 clear FPU error and deassert the interrupt. */ + if (is286) + picintc(1 << 13); + else + nmi = 0; + return; + } else if (addr >= 0xf1) + return; /* FPU stuff */ + if (!(addr & 1)) cyrix_addr = val; else switch (cyrix_addr) @@ -2165,6 +2246,7 @@ void cyrix_write(uint16_t addr, uint8_t val, void *priv) if ((ccr3 & 0xf0) == 0x10) { ccr4 = val; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_Cx6x86) { if (val & 0x80) @@ -2172,6 +2254,7 @@ void cyrix_write(uint16_t addr, uint8_t val, void *priv) else CPUID = 0; } +#endif } break; case 0xe9: /*CCR5*/ @@ -2185,8 +2268,11 @@ void cyrix_write(uint16_t addr, uint8_t val, void *priv) } } -uint8_t cyrix_read(uint16_t addr, void *priv) +static uint8_t cpu_read(uint16_t addr, void *priv) { + if (addr >= 0xf0) + return 0xff; /* FPU stuff */ + if (addr & 1) { switch (cyrix_addr) diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index b4efb8a3c..62557bbd5 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -8,7 +8,7 @@ * * CPU type handler. * - * Version: @(#)cpu.h 1.0.11 2018/03/28 + * Version: @(#)cpu.h 1.0.13 2018/11/14 * * Authors: Sarah Walker, * leilei, @@ -18,6 +18,10 @@ * Copyright 2016-2018 leilei. * Copyright 2016,2018 Miran Grca. */ +#ifdef USE_NEW_DYNAREC +#include "../cpu_new/cpu.h" +#else + #ifndef EMU_CPU_H # define EMU_CPU_H @@ -27,39 +31,42 @@ #define CPU_286 2 /* 286 class CPUs */ #define CPU_386SX 3 /* 386 class CPUs */ #define CPU_386DX 4 -#define CPU_RAPIDCAD 5 -#define CPU_486SLC 6 -#define CPU_486DLC 7 -#define CPU_i486SX 8 /* 486 class CPUs */ -#define CPU_Am486SX 9 -#define CPU_Cx486S 10 -#define CPU_i486DX 11 -#define CPU_Am486DX 12 -#define CPU_Cx486DX 13 -#define CPU_iDX4 14 -#define CPU_Cx5x86 15 -#define CPU_WINCHIP 16 /* 586 class CPUs */ -#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_IBM386SLC 5 +#define CPU_IBM486SLC 6 +#define CPU_IBM486BL 7 +#define CPU_RAPIDCAD 8 +#define CPU_486SLC 9 +#define CPU_486DLC 10 +#define CPU_i486SX 11 /* 486 class CPUs */ +#define CPU_Am486SX 12 +#define CPU_Cx486S 13 +#define CPU_i486DX 14 +#define CPU_Am486DX 15 +#define CPU_Cx486DX 16 +#define CPU_iDX4 17 +#define CPU_Cx5x86 18 +#define CPU_WINCHIP 19 /* 586 class CPUs */ +#define CPU_PENTIUM 20 +#define CPU_PENTIUMMMX 21 +#define CPU_Cx6x86 22 +#define CPU_Cx6x86MX 23 +#define CPU_Cx6x86L 24 +#define CPU_CxGX1 25 #ifdef DEV_BRANCH #ifdef USE_AMD_K -#define CPU_K5 23 -#define CPU_5K86 24 -#define CPU_K6 25 +#define CPU_K5 26 +#define CPU_5K86 27 +#define CPU_K6 28 #endif #endif #ifdef DEV_BRANCH #ifdef USE_I686 -#define CPU_PENTIUMPRO 26 /* 686 class CPUs */ +#define CPU_PENTIUMPRO 29 /* 686 class CPUs */ #if 0 -# define CPU_PENTIUM2 27 -# define CPU_PENTIUM2D 28 +# define CPU_PENTIUM2 30 +# define CPU_PENTIUM2D 31 #else -# define CPU_PENTIUM2D 27 +# define CPU_PENTIUM2D 30 #endif #endif #endif @@ -71,22 +78,22 @@ #define CPU_SUPPORTS_DYNAREC 1 #define CPU_REQUIRES_DYNAREC 2 +#define CPU_ALTERNATE_XTAL 4 typedef struct { - const char *name; - int cpu_type; - int speed; - int rspeed; - int multi; - int pci_speed; - uint32_t edx_reset; - uint32_t cpuid_model; - uint16_t cyrix_id; - int cpu_flags; - int mem_read_cycles, mem_write_cycles; - int cache_read_cycles, cache_write_cycles; - int atclk_div; + const char *name; + int cpu_type; + int rspeed; + double multi; + int pci_speed; + uint32_t edx_reset; + uint32_t cpuid_model; + uint16_t cyrix_id; + uint8_t cpu_flags; + int8_t mem_read_cycles, mem_write_cycles; + int8_t cache_read_cycles, cache_write_cycles; + int8_t atclk_div; } CPU; extern CPU cpus_8088[]; @@ -98,6 +105,12 @@ extern CPU cpus_Am386SX[]; extern CPU cpus_Am386DX[]; extern CPU cpus_486SLC[]; extern CPU cpus_486DLC[]; +extern CPU cpus_IBM386SLC[]; +extern CPU cpus_IBM486SLC[]; +extern CPU cpus_IBM486BL[]; +extern CPU cpus_i486S1[]; +extern CPU cpus_Am486S1[]; +extern CPU cpus_Cx486S1[]; extern CPU cpus_i486[]; extern CPU cpus_Am486[]; extern CPU cpus_Cx486[]; @@ -105,14 +118,20 @@ extern CPU cpus_WinChip[]; extern CPU cpus_Pentium5V[]; extern CPU cpus_Pentium5V50[]; extern CPU cpus_PentiumS5[]; +extern CPU cpus_Pentium3V[]; +extern CPU cpus_Pentium[]; #ifdef DEV_BRANCH #ifdef USE_AMD_K extern CPU cpus_K5[]; extern CPU cpus_K56[]; #endif #endif -extern CPU cpus_Pentium[]; +#ifdef DEV_BRANCH +#ifdef USE_CYRIX_6X86 +extern CPU cpus_6x863V[]; extern CPU cpus_6x86[]; +#endif +#endif #ifdef DEV_BRANCH #ifdef USE_I686 extern CPU cpus_PentiumPro[]; @@ -142,9 +161,9 @@ extern CPU cpus_Pentium2D[]; #define CR4_PVI (1 << 1) #define CR4_PSE (1 << 4) -#define CPL ((_cs.access>>5)&3) +#define CPL ((cpu_state.seg_cs.access>>5)&3) -#define IOPL ((flags>>12)&3) +#define IOPL ((cpu_state.flags>>12)&3) #define IOPLp ((!(msw&1)) || (CPL<=IOPL)) @@ -239,9 +258,18 @@ struct _cpustate_ { uint16_t old_npxc, new_npxc; uint32_t last_ea; + + x86seg seg_cs, + seg_ds, + seg_es, + seg_ss, + seg_fs, + seg_gs; + + uint16_t flags, eflags; } cpu_state; -/*The flags below must match in both cpu_cur_status and block->status for a block +/*The cpu_state.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) @@ -249,7 +277,7 @@ struct _cpustate_ { #define CPU_STATUS_V86 (1 << 3) #define CPU_STATUS_FLAGS 0xffff -/*If the flags below are set in cpu_cur_status, they must be set in block->status. +/*If the cpu_state.flags below are set in cpu_cur_status, they must be set in block->status. Otherwise they are ignored*/ #define CPU_STATUS_NOTFLATDS (1 << 16) #define CPU_STATUS_NOTFLATSS (1 << 17) @@ -316,20 +344,26 @@ extern int cpu_cyrix_alignment; /*Cyrix 5x86/6x86 only has data misalignment penalties when crossing 8-byte boundaries*/ extern int is8086, is286, is386, is486; -extern int is_rapidcad, is_pentium; +extern int isibmcpu; +extern int is_rapidcad; extern int hasfpu; -extern int cpu_hasrdtsc; -extern int cpu_hasMSR; -extern int cpu_hasMMX; -extern int cpu_hasCR4; -extern int cpu_hasVME; +#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) + +extern uint32_t cpu_features; + +extern int in_smm, smi_line, smi_latched; +extern uint32_t smbase; extern uint32_t cpu_cur_status; extern uint64_t cpu_CR4_mask; extern uint64_t tsc; extern msr_t msr; -extern int cpuspeed; -extern int cycles_lost; extern uint8_t opcode; extern int insc; extern int fpucount; @@ -338,16 +372,14 @@ extern int clockrate; extern int cgate16; extern int cpl_override; extern int CPUID; -extern int xt_cpu_multi; +extern uint64_t xt_cpu_multi; extern int isa_cycles; -extern uint16_t flags,eflags; extern uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; extern int ins,output; -extern int cycdiff; extern uint32_t pccache; extern uint8_t *pccache2; -extern float isa_timing, bus_timing; +extern double bus_timing; extern uint64_t pmc[2]; extern uint16_t temp_seg_data[4]; extern uint16_t cs_msr; @@ -371,24 +403,22 @@ extern uint32_t dr[8]; CS,DS,ES,SS is the 16-bit data cs,ds,es,ss are defines to the bases*/ extern x86seg gdt,ldt,idt,tr; -extern x86seg _cs,_ds,_es,_ss,_fs,_gs; extern x86seg _oldds; -#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 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 fs_seg cpu_state.seg_fs.base +#define gs cpu_state.seg_gs.base -#define ISA_CYCLES_SHIFT 6 -#define ISA_CYCLES(x) ((x * isa_cycles) >> ISA_CYCLES_SHIFT) +#define ISA_CYCLES(x) (x * isa_cycles) extern int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; extern int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; @@ -423,8 +453,8 @@ extern CPU cpus_acer[]; // FIXME: should be in machine file! /* Functions. */ -extern void cyrix_write(uint16_t addr, uint8_t val, void *priv); -extern uint8_t cyrix_read(uint16_t addr, void *priv); +extern int cpu_has_feature(int feature); + extern void loadseg(uint16_t seg, x86seg *s); extern void loadcs(uint16_t seg); @@ -442,13 +472,14 @@ extern void codegen_block_end(void); extern void codegen_reset(void); extern void cpu_set_edx(void); extern int divl(uint32_t val); -extern void dumpregs(int __force); extern void execx86(int cycs); +extern void enter_smm(); +extern void leave_smm(); extern void exec386(int cycs); extern void exec386_dynarec(int cycs); extern int idivl(int32_t val); extern void loadcscall(uint16_t seg); -extern void loadcsjmp(uint16_t seg, uint32_t oxpc); +extern void loadcsjmp(uint16_t seg, uint32_t old_pc); extern void pmodeint(int num, int soft); extern void pmoderetf(int is32, uint16_t off); extern void pmodeiret(int is32); @@ -457,17 +488,23 @@ extern void resetx86(void); extern void refreshread(void); extern void resetreadlookup(void); extern void softresetx86(void); +extern void x86_int(int num); extern void x86_int_sw(int num); extern int x86_int_sw_rm(int num); extern void x86gpf(char *s, uint16_t error); extern void x86np(char *s, uint16_t error); extern void x86ss(char *s, uint16_t error); extern void x86ts(char *s, uint16_t error); + +#ifdef ENABLE_808X_LOG +extern void dumpregs(int __force); extern void x87_dumpregs(void); extern void x87_reset(void); +#endif -extern int cpu_effective; +extern int cpu_effective, cpu_alt_reset; extern void cpu_dynamic_switch(int new_cpu); #endif /*EMU_CPU_H*/ +#endif diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 51b28bea0..a0e77f414 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -29,17 +29,17 @@ * 16 = 180 MHz * 17 = 200 MHz * - * Version: @(#)cpu_table.c 1.0.6 2018/07/24 + * Version: @(#)cpu_table.c 1.0.7 2019/10/21 * * Authors: Sarah Walker, * leilei, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 leilei. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 leilei. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -52,397 +52,518 @@ CPU cpus_8088[] = { /*8088 standard*/ - {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, 7159092, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/8", CPU_8088, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/10", CPU_8088, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/12", CPU_8088, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/16", CPU_8088, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,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}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_europc[] = { /*8088 EuroPC*/ - {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/9.54", CPU_8088, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8088/9.54", CPU_8088, 9545456, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,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, 1}, - {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8086/9.54", CPU_8086, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8086/7.16", CPU_8086, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8086/8", CPU_8086, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/9.54", CPU_8086, 9545456, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8086/10", CPU_8086, 10000000, 2, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/12", CPU_8086, 12000000, 3, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/16", CPU_8086, 16000000, 4, 0, 0, 0, 0, 0, 0,0,0,0, 2}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,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}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8086/8", CPU_8086, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_286[] = { /*286*/ - {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, - {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/8", CPU_286, 8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 12500000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_ibmat[] = { /*286*/ - {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, - {"286/8", CPU_286, 0, 8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"286/8", CPU_286, 8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_ibmxt286[] = { /*286*/ - {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,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}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 9} }; CPU cpus_ps2_m30_286[] = { /*286*/ - {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, - {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 12500000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_i386SX[] = { /*i386SX*/ - {"i386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, - {"i386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"i386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, - {"i386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"i386SX/16", CPU_386SX, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"i386SX/20", CPU_386SX, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/25", CPU_386SX, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/33", CPU_386SX, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"i386SX/40", CPU_386SX, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_i386DX[] = { /*i386DX*/ - {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2}, - {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, - {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, - {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, - {"i386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, - {"RapidCAD/25", CPU_RAPIDCAD, 2, 25000000, 1, 0, 0x430, 0, 0, 0, 4,4,3,3, 3}, - {"RapidCAD/33", CPU_RAPIDCAD, 3, 33333333, 1, 0, 0x430, 0, 0, 0, 6,6,3,3, 4}, - {"RapidCAD/40", CPU_RAPIDCAD, 4, 40000000, 1, 0, 0x430, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"i386DX/16", CPU_386DX, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2}, + {"i386DX/20", CPU_386DX, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/25", CPU_386DX, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/33", CPU_386DX, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"i386DX/40", CPU_386DX, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"RapidCAD/25", CPU_RAPIDCAD, 25000000, 1, 0, 0x0430, 0, 0, 0, 4,4,3,3, 3}, + {"RapidCAD/33", CPU_RAPIDCAD, 33333333, 1, 0, 0x0430, 0, 0, 0, 6,6,3,3, 4}, + {"RapidCAD/40", CPU_RAPIDCAD, 40000000, 1, 0, 0x0430, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; -#if 0 -CPU cpus_acer[] = { - /*i386SX*/ - {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,4,4, 3}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} -}; -#endif - CPU cpus_Am386SX[] = { /*Am386*/ - {"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, - {"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, - {"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Am386SX/16", CPU_386SX, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"Am386SX/20", CPU_386SX, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/25", CPU_386SX, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/33", CPU_386SX, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386SX/40", CPU_386SX, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_Am386DX[] = { /*Am386*/ - {"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, - {"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, - {"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Am386DX/25", CPU_386DX, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386DX/33", CPU_386DX, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386DX/40", CPU_386DX, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; +CPU cpus_IBM386SLC[] = { + /*IBM 386SLC*/ + {"386SLC/16", CPU_IBM386SLC, 16000000, 1, 0, 0x300, 0, 0, 0, 3,3,3,3, 2}, + {"386SLC/20", CPU_IBM386SLC, 20000000, 1, 0, 0x300, 0, 0, 0, 4,4,3,3, 3}, + {"386SLC/25", CPU_IBM386SLC, 25000000, 1, 0, 0x300, 0, 0, 0, 4,4,3,3, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; +CPU cpus_IBM486SLC[] = { + /*IBM 486SLC*/ + {"486SLC/33", CPU_IBM486SLC, 33333333, 1, 0, 0x400, 0, 0, 0, 6,6,3,3, 4}, + {"486SLC2/40", CPU_IBM486SLC, 40000000, 2, 0, 0x400, 0, 0, 0, 7,7,6,6, 5}, + {"486SLC2/50", CPU_IBM486SLC, 50000000, 2, 0, 0x400, 0, 0, 0, 8,8,6,6, 6}, + {"486SLC2/66", CPU_IBM486SLC, 66666666, 2, 0, 0x400, 0, 0, 0, 12,12,6,6, 8}, + {"486SLC3/60", CPU_IBM486SLC, 60000000, 3, 0, 0x400, 0, 0, 0, 12,12,9,9, 7}, + {"486SLC3/75", CPU_IBM486SLC, 75000000, 3, 0, 0x400, 0, 0, 0, 12,12,9,9, 9}, + {"486SLC3/100", CPU_IBM486SLC, 100000000, 3, 0, 0x400, 0, 0, 0, 18,18,9,9, 12}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_IBM486BL[] = { + /*IBM Blue Lightning*/ + {"486BL2/50", CPU_IBM486BL, 50000000, 2, 0, 0x400, 0, 0, 0, 8,8,6,6, 6}, + {"486BL2/66", CPU_IBM486BL, 66666666, 2, 0, 0x400, 0, 0, 0, 12,12,6,6, 8}, + {"486BL3/75", CPU_IBM486BL, 75000000, 3, 0, 0x400, 0, 0, 0, 12,12,9,9, 9}, + {"486BL3/100", CPU_IBM486BL, 100000000, 3, 0, 0x400, 0, 0, 0, 18,18,9,9, 12}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; CPU cpus_486SLC[] = { /*Cx486SLC*/ - {"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, - {"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, - {"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, - {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6, 4}, - {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, - {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Cx486SLC/20", CPU_486SLC, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/25", CPU_486SLC, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/33", CPU_486SLC, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, + {"Cx486SRx2/32", CPU_486SLC, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6, 4}, + {"Cx486SRx2/40", CPU_486SLC, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"Cx486SRx2/50", CPU_486SLC, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_486DLC[] = { /*Cx486DLC*/ - {"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4,4,3,3, 3}, - {"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6,6,3,3, 4}, - {"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7,7,3,3, 5}, - {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6,6,6,6, 4}, - {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 6}, - {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 6}, - {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6, 8}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Cx486DLC/25", CPU_486DLC, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4, 4,3,3, 3}, + {"Cx486DLC/33", CPU_486DLC, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6, 6,3,3, 4}, + {"Cx486DLC/40", CPU_486DLC, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7, 7,3,3, 5}, + {"Cx486DRx2/32", CPU_486DLC, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6, 6,6,6, 4}, + {"Cx486DRx2/40", CPU_486DLC, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"Cx486DRx2/50", CPU_486DLC, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"Cx486DRx2/66", CPU_486DLC, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6, 8}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_i486S1[] = { + /*i486*/ + {"i486SX/16", CPU_i486SX, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3, 3,3,3, 2}, + {"i486SX/20", CPU_i486SX, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486SX/25", CPU_i486SX, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486SX/33", CPU_i486SX, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"i486SX2/50", CPU_i486SX, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486SX2/66 (Q0569)", CPU_i486SX, 66666666, 2, 33333333, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 8}, + {"i486DX/25", CPU_i486DX, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486DX/33", CPU_i486DX, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"i486DX/50", CPU_i486DX, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,4,4, 6}, + {"i486DX2/40", CPU_i486DX, 40000000, 2, 20000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 7, 7,6,6, 5}, + {"i486DX2/50", CPU_i486DX, 50000000, 2, 25000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486DX2/66", CPU_i486DX, 66666666, 2, 33333333, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"iDX4 OverDrive 75", CPU_iDX4, 75000000, 3, 25000000, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, /*Only added the DX4 OverDrive as the others would be redundant*/ + {"iDX4 OverDrive 100", CPU_iDX4, 100000000, 3, 33333333, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; +CPU cpus_Am486S1[] = { + /*Am486*/ + {"Am486SX/33", CPU_Am486SX, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Am486SX/40", CPU_Am486SX, 40000000, 1, 40000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Am486SX2/50", CPU_Am486SX, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ + {"Am486SX2/66", CPU_Am486SX, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, /*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, 33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Am486DX/40", CPU_Am486DX, 40000000, 1, 40000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Am486DX2/50", CPU_Am486DX, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"Am486DX2/66", CPU_Am486DX, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Am486DX2/80", CPU_Am486DX, 80000000, 2, 40000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; +CPU cpus_Cx486S1[] = { + /*Cyrix 486*/ + {"Cx486S/25", CPU_Cx486S, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, + {"Cx486S/33", CPU_Cx486S, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Cx486S/40", CPU_Cx486S, 40000000, 1, 40000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Cx486DX/33", CPU_Cx486DX, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Cx486DX/40", CPU_Cx486DX, 40000000, 1, 40000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Cx486DX2/50", CPU_Cx486DX, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"Cx486DX2/66", CPU_Cx486DX, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Cx486DX2/80", CPU_Cx486DX, 80000000, 2, 40000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 2}, - {"i486SX/20", CPU_i486SX, 1, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, - {"i486SX/25", CPU_i486SX, 2, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, - {"i486SX/33", CPU_i486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"i486SX2/66 (Q0569)", CPU_i486SX, 6, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 8}, - {"i486DX/25", CPU_i486DX, 2, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, - {"i486DX/33", CPU_i486DX, 3, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"i486DX/50", CPU_i486DX, 5, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, 6}, - {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 20000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 25000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 33333333, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, - {"iDX4/75", CPU_iDX4, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, /*CPUID available on DX4, >= 75 MHz*/ - {"iDX4/100", CPU_iDX4, 10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, /*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, 15/2}, - {"Pentium OverDrive/83", CPU_PENTIUM, 8, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, 10}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + /*i486/P24T*/ + {"i486SX/16", CPU_i486SX, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3, 3,3,3, 2}, + {"i486SX/20", CPU_i486SX, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486SX/25", CPU_i486SX, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486SX/33", CPU_i486SX, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"i486SX2/50", CPU_i486SX, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486SX2/66 (Q0569)", CPU_i486SX, 66666666, 2, 33333333, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 8}, + {"i486DX/25", CPU_i486DX, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486DX/33", CPU_i486DX, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"i486DX/50", CPU_i486DX, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,4,4, 6}, + {"i486DX2/40", CPU_i486DX, 40000000, 2, 20000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 7, 7,6,6, 5}, + {"i486DX2/50", CPU_i486DX, 50000000, 2, 25000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486DX2/66", CPU_i486DX, 66666666, 2, 33333333, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"iDX4/75", CPU_iDX4, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, /*CPUID available on DX4, >= 75 MHz*/ + {"iDX4/100", CPU_iDX4, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ + {"iDX4 OverDrive 75", CPU_iDX4, 75000000, 3, 25000000, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, + {"iDX4 OverDrive 100", CPU_iDX4, 100000000, 3, 33333333, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, + {"Pentium OverDrive 63", CPU_PENTIUM, 62500000, 5/2, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, 15/2}, + {"Pentium OverDrive 83", CPU_PENTIUM, 83333333, 5/2, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, 10}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,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, 4}, - {"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, - {"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,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, 8}, /*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, 4}, - {"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, - {"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, - {"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14,6,6, 10}, - {"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, - {"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, - {"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, - {"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 15}, - {"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, - {"Am5x86/P75+", CPU_Am486DX, 13, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Am486SX/33", CPU_Am486SX, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Am486SX/40", CPU_Am486SX, 40000000, 1, 40000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Am486SX2/50", CPU_Am486SX, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ + {"Am486SX2/66", CPU_Am486SX, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Am486DX/33", CPU_Am486DX, 33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Am486DX/40", CPU_Am486DX, 40000000, 1, 40000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Am486DX2/50", CPU_Am486DX, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"Am486DX2/66", CPU_Am486DX, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Am486DX2/80", CPU_Am486DX, 80000000, 2, 40000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"Am486DX4/75", CPU_Am486DX, 75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, + {"Am486DX4/90", CPU_Am486DX, 90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"Am486DX4/100", CPU_Am486DX, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"Am486DX4/120", CPU_Am486DX, 120000000, 3, 40000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"Am5x86/P75", CPU_Am486DX, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, + {"Am5x86/P75+", CPU_Am486DX, 150000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*The rare P75+ was indeed a triple-clocked 150 MHz according to research*/ + {"Am5x86/P90", CPU_Am486DX, 160000000, 4, 40000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*160 MHz on a 40 MHz bus was a common overclock and "5x86/P90" was used by a number of BIOSes to refer to that configuration*/ + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 3}, - {"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, - {"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, - {"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, - {"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14,16,16, 10}, - {"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, - {"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, - {"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, - {"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 15}, - {"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + /*Cyrix 486*/ + {"Cx486S/25", CPU_Cx486S, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, + {"Cx486S/33", CPU_Cx486S, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Cx486S/40", CPU_Cx486S, 40000000, 1, 40000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Cx486DX/33", CPU_Cx486DX, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Cx486DX/40", CPU_Cx486DX, 40000000, 1, 40000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Cx486DX2/50", CPU_Cx486DX, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"Cx486DX2/66", CPU_Cx486DX, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Cx486DX2/80", CPU_Cx486DX, 80000000, 2, 40000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"Cx486DX4/75", CPU_Cx486DX, 75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, + {"Cx486DX4/100", CPU_Cx486DX, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + + /*Cyrix 5x86*/ + {"Cx5x86/80", CPU_Cx5x86, 80000000, 2, 40000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, /*If we're including the Pentium 50, might as well include this*/ + {"Cx5x86/100", CPU_Cx5x86, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"Cx5x86/120", CPU_Cx5x86, 120000000, 3, 40000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"Cx5x86/133", CPU_Cx5x86, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; +#ifdef DEV_BRANCH +#ifdef USE_CYRIX_6X86 +CPU cpus_6x863V[] = { + /*Cyrix 6x86*/ + {"Cx6x86/P90", CPU_Cx6x86, 80000000, 2, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, + {"Cx6x86/PR120+", CPU_Cx6x86, 100000000, 2, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"Cx6x86/PR133+", CPU_Cx6x86, 110000000, 2, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"Cx6x86/PR150+", CPU_Cx6x86, 120000000, 2, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Cx6x86/PR166+", CPU_Cx6x86, 133333333, 2, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86/PR200+", CPU_Cx6x86, 150000000, 2, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 10}, - {"6x86-PR120+", CPU_Cx6x86, 17, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, - {"6x86-PR133+", CPU_Cx6x86, 17, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 14}, - {"6x86-PR150+", CPU_Cx6x86, 17, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"6x86-PR166+", CPU_Cx6x86, 17, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"6x86-PR200+", CPU_Cx6x86, 17, 150000000, 3, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 18}, + {"Cx6x86/P90", CPU_Cx6x86, 80000000, 2, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, + {"Cx6x86/PR120+", CPU_Cx6x86, 100000000, 2, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"Cx6x86/PR133+", CPU_Cx6x86, 110000000, 2, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"Cx6x86/PR150+", CPU_Cx6x86, 120000000, 2, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Cx6x86/PR166+", CPU_Cx6x86, 133333333, 2, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86/PR200+", CPU_Cx6x86, 150000000, 2, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, /*Cyrix 6x86L*/ - {"6x86L-PR133+", CPU_Cx6x86L, 19, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 14}, - {"6x86L-PR150+", CPU_Cx6x86L, 19, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"6x86L-PR166+", CPU_Cx6x86L, 19, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"6x86L-PR200+", CPU_Cx6x86L, 19, 150000000, 3, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 18}, + {"Cx6x86L/PR133+", CPU_Cx6x86L, 110000000, 2, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"Cx6x86L/PR150+", CPU_Cx6x86L, 120000000, 2, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Cx6x86L/PR166+", CPU_Cx6x86L, 133333333, 2, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86L/PR200+", CPU_Cx6x86L, 150000000, 2, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, - /*Cyrix 6x86MX*/ - {"6x86MX-PR166", CPU_Cx6x86MX, 18, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"6x86MX-PR200", CPU_Cx6x86MX, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"6x86MX-PR233", CPU_Cx6x86MX, 18, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 45/2}, - {"6x86MX-PR266", CPU_Cx6x86MX, 18, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, 25}, - {"6x86MX-PR300", CPU_Cx6x86MX, 18, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,7,7, 28}, - {"6x86MX-PR333", CPU_Cx6x86MX, 18, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20,9,9, 30}, - {"6x86MX-PR366", CPU_Cx6x86MX, 18, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 30}, - {"6x86MX-PR400", CPU_Cx6x86MX, 18, 285000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 33}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + /*Cyrix 6x86MX/MII*/ + {"Cx6x86MX/PR166", CPU_Cx6x86MX, 133333333, 2, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86MX/PR200", CPU_Cx6x86MX, 166666666, 5/2, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Cx6x86MX/PR233", CPU_Cx6x86MX, 187500000, 5/2, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2}, + {"Cx6x86MX/PR266", CPU_Cx6x86MX, 208333333, 5/2, 41666666, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, + {"MII/PR300", CPU_Cx6x86MX, 233333333, 7/2, 33333333, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,11,11, 28}, + {"MII/PR333", CPU_Cx6x86MX, 250000000, 3, 41666666, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 9, 9, 30}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; +#endif +#endif CPU cpus_WinChip[] = { /*IDT WinChip*/ - {"WinChip 75", CPU_WINCHIP, 7, 75000000, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, 9}, - {"WinChip 90", CPU_WINCHIP, 9, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, 21/2}, - {"WinChip 100", CPU_WINCHIP, 10, 100000000, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, 12}, - {"WinChip 120", CPU_WINCHIP, 11, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 14}, - {"WinChip 133", CPU_WINCHIP, 12, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 16}, - {"WinChip 150", CPU_WINCHIP, 13, 150000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, 35/2}, - {"WinChip 166", CPU_WINCHIP, 15, 166666666, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, 40}, - {"WinChip 180", CPU_WINCHIP, 16, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 21}, - {"WinChip 200", CPU_WINCHIP, 17, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 24}, - {"WinChip 225", CPU_WINCHIP, 17, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 27}, - {"WinChip 240", CPU_WINCHIP, 17, 240000000, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 28}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"WinChip 75", CPU_WINCHIP, 75000000, 3/2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 9}, + {"WinChip 90", CPU_WINCHIP, 90000000, 3/2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 21/2}, + {"WinChip 100", CPU_WINCHIP, 100000000, 3/2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 12}, + {"WinChip 120", CPU_WINCHIP, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 14}, + {"WinChip 133", CPU_WINCHIP, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 16}, + {"WinChip 150", CPU_WINCHIP, 150000000, 5/2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 35/2}, + {"WinChip 166", CPU_WINCHIP, 166666666, 5/2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 40}, + {"WinChip 180", CPU_WINCHIP, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 21}, + {"WinChip 200", CPU_WINCHIP, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, + {"WinChip 225", CPU_WINCHIP, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 27}, + {"WinChip 240", CPU_WINCHIP, 240000000, 4, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 28}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 7}, - {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, - {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Pentium 60", CPU_PENTIUM, 60000000, 1, 30000000, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, + {"Pentium 66", CPU_PENTIUM, 66666666, 1, 33333333, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, + {"Pentium OverDrive 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; CPU cpus_Pentium5V50[] = { /*Intel Pentium (5V, socket 4, including 50 MHz FSB)*/ - {"Pentium 50 (Q0399)",CPU_PENTIUM, 5, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4,4,3,3, 6}, - {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, - {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, - {"Pentium OverDrive 100",CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8,8,6,6, 12}, - {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Pentium 50 (Q0399)", CPU_PENTIUM, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4,3,3, 6}, + {"Pentium 60", CPU_PENTIUM, 60000000, 1, 30000000, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, + {"Pentium 66", CPU_PENTIUM, 66666666, 1, 33333333, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, + {"Pentium OverDrive 100", CPU_PENTIUM, 100000000, 2, 25000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8,6,6, 12}, + {"Pentium OverDrive 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; CPU cpus_PentiumS5[] = { /*Intel Pentium (Socket 5)*/ - {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x522, 0x522, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium OverDrive MMX 75",CPU_PENTIUMMMX,9,75000000,2,25000000,0x1542,0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, - {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 16}, - {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 40}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, - {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Pentium 75", CPU_PENTIUM, 75000000, 3/2, 25000000, 0x522, 0x522, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 3/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"Pentium 90", CPU_PENTIUM, 90000000, 3/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, + {"Pentium 100/50", CPU_PENTIUM, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, + {"Pentium 100/66", CPU_PENTIUM, 100000000, 3/2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, + {"Pentium 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + + /*Intel Pentium OverDrive*/ + {"Pentium OverDrive 125", CPU_PENTIUM, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 16}, + {"Pentium OverDrive 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 40}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 5/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 5/2, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 5/2, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, 180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_Pentium3V[] = { + /*Intel Pentium*/ + {"Pentium 75", CPU_PENTIUM, 75000000, 3/2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 3/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium 90", CPU_PENTIUM, 90000000, 3/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"Pentium 100/50", CPU_PENTIUM, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"Pentium 100/66", CPU_PENTIUM, 100000000, 3/2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"Pentium 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Pentium 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Pentium 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium 200", CPU_PENTIUM, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + + /*Intel Pentium OverDrive*/ + {"Pentium OverDrive 125", CPU_PENTIUM, 125000000, 5/2, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, + {"Pentium OverDrive 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 5/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 5/2, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 5/2, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, 180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 9}, - {"Pentium OverDrive MMX 75",CPU_PENTIUMMMX,9,75000000,2,25000000,0x1542,0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, - {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium 133", CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"Pentium 150", CPU_PENTIUM, 17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium 166", CPU_PENTIUM, 19, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium 200", CPU_PENTIUM, 21, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, 14, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, 16, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, 17, 150000000, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, 26, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, 28, 300000000, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, - {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, - {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Pentium 75", CPU_PENTIUM, 75000000, 3/2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 3/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium 90", CPU_PENTIUM, 90000000, 3/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"Pentium 100/50", CPU_PENTIUM, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"Pentium 100/66", CPU_PENTIUM, 100000000, 3/2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"Pentium 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Pentium 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Pentium 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium 200", CPU_PENTIUM, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"Pentium MMX 166", CPU_PENTIUMMMX, 166666666, 5/2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"Pentium MMX 233", CPU_PENTIUMMMX, 233333333, 7/2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + + /*Mobile Pentium*/ + {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, 150000000, 5/2, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 166666666, 5/2, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, 233333333, 7/2, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, 300000000, 9/2, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + + /*Intel Pentium OverDrive*/ + {"Pentium OverDrive 125", CPU_PENTIUM, 125000000, 5/2, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, + {"Pentium OverDrive 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 5/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 5/2, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 5/2, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, 180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; #ifdef DEV_BRANCH #ifdef USE_AMD_K CPU cpus_K5[] = { /*AMD K5 (Socket 5)*/ - {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 3, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"K5 (5k86) 75 (P75)", CPU_K5, 75000000, 3/2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 3/2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"K5 (5k86) 90 (P90)", CPU_K5, 90000000, 3/2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 90000000, 3/2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, + {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 3/2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, + {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 3/2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 150000000, 5/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 5/2, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; CPU cpus_K56[] = { - /*AMD K5 and K6 (Socket 7)*/ - {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 3, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"K6 (Model 6) 166", CPU_K6, 19, 166666666, 3, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"K6 (Model 6) 200", CPU_K6, 21, 200000000, 3, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"K6 (Model 6) 233", CPU_K6, 24, 233333333, 4, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"K6 (Model 7) 200", CPU_K6, 21, 200000000, 3, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"K6 (Model 7) 233", CPU_K6, 24, 233333333, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"K6 (Model 7) 266", CPU_K6, 26, 266666666, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"K6 (Model 7) 300", CPU_K6, 28, 300000000, 5, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} -}; + /*AMD K5 (Socket 7)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 75000000, 3/2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 3/2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"K5 (5k86) 90 (P90)", CPU_K5, 90000000, 3/2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 90000000, 3/2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 3/2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 3/2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 150000000, 5/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 5/2, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + + /*AMD K6 (Socket 7*/ + {"K6 (Model 6) 166", CPU_K6, 166666666, 5/2, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"K6 (Model 6) 200", CPU_K6, 200000000, 3, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"K6 (Model 6) 233", CPU_K6, 233333333, 7/2, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 10, 10, 28}, + {"K6 (Model 7) 200", CPU_K6, 200000000, 3, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"K6 (Model 7) 233", CPU_K6, 233333333, 7/2, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 10, 10, 28}, + {"K6 (Model 7) 266", CPU_K6, 266666666, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24, 12, 12, 32}, + {"K6 (Model 7) 300", CPU_K6, 300000000, 9/2, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 13, 13, 36}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; #endif #endif #ifdef DEV_BRANCH #ifdef USE_I686 CPU cpus_PentiumPro[] = { - /*Intel Pentium Pro and II Overdrive*/ - {"Pentium Pro 50", CPU_PENTIUMPRO, 5, 50000000, 1, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4,4,3,3, 6}, - {"Pentium Pro 60" , CPU_PENTIUMPRO, 6, 60000000, 1, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, - {"Pentium Pro 66" , CPU_PENTIUMPRO, 6, 66666666, 1, 33333333, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, - {"Pentium Pro 75", CPU_PENTIUMPRO, 9, 75000000, 2, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium Pro 150", CPU_PENTIUMPRO, 17, 150000000, 3, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium Pro 166", CPU_PENTIUMPRO, 19, 166666666, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium Pro 180", CPU_PENTIUMPRO, 20, 180000000, 3, 30000000, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, - {"Pentium Pro 200", CPU_PENTIUMPRO, 21, 200000000, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"Pentium II Overdrive 50", CPU_PENTIUM2D, 5, 50000000, 1, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4,4,3,3, 6}, - {"Pentium II Overdrive 60", CPU_PENTIUM2D, 6, 60000000, 1, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, - {"Pentium II Overdrive 66", CPU_PENTIUM2D, 6, 66666666, 1, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, - {"Pentium II Overdrive 75", CPU_PENTIUM2D, 9, 75000000, 2, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium II Overdrive 210", CPU_PENTIUM2D, 22, 210000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, 25}, - {"Pentium II Overdrive 233", CPU_PENTIUM2D, 24, 233333333, 4, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,1, 28}, - {"Pentium II Overdrive 240", CPU_PENTIUM2D, 25, 240000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 29}, - {"Pentium II Overdrive 266", CPU_PENTIUM2D, 26, 266666666, 4, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Pentium II Overdrive 270", CPU_PENTIUM2D, 27, 270000000, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 33}, - {"Pentium II Overdrive 300/66",CPU_PENTIUM2D, 28, 300000000, 5, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, - {"Pentium II Overdrive 300/60",CPU_PENTIUM2D, 28, 300000000, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"Pentium II Overdrive 333", CPU_PENTIUM2D, 29, 333333333, 5, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + /*Intel Pentium Pro*/ + {"Pentium Pro 50", CPU_PENTIUMPRO, 50000000, 1, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, + {"Pentium Pro 60" , CPU_PENTIUMPRO, 60000000, 1, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, + {"Pentium Pro 66" , CPU_PENTIUMPRO, 66666666, 1, 33333333, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, + {"Pentium Pro 75", CPU_PENTIUMPRO, 75000000, 3/2, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium Pro 150", CPU_PENTIUMPRO, 150000000, 5/2, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium Pro 166", CPU_PENTIUMPRO, 166666666, 5/2, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium Pro 180", CPU_PENTIUMPRO, 180000000, 3, 30000000, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, + {"Pentium Pro 200", CPU_PENTIUMPRO, 200000000, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + + /*Intel Pentium II OverDrive*/ + {"Pentium II Overdrive 50", CPU_PENTIUM2D, 50000000, 1, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, + {"Pentium II Overdrive 60", CPU_PENTIUM2D, 60000000, 1, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, + {"Pentium II Overdrive 66", CPU_PENTIUM2D, 66666666, 1, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, + {"Pentium II Overdrive 75", CPU_PENTIUM2D, 75000000, 3/2, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium II Overdrive 210", CPU_PENTIUM2D, 210000000, 7/2, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, + {"Pentium II Overdrive 233", CPU_PENTIUM2D, 233333333, 7/2, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"Pentium II Overdrive 240", CPU_PENTIUM2D, 240000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 29}, + {"Pentium II Overdrive 266", CPU_PENTIUM2D, 266666666, 4, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"Pentium II Overdrive 270", CPU_PENTIUM2D, 270000000, 9/2, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 33}, + {"Pentium II Overdrive 300/66", CPU_PENTIUM2D, 300000000, 9/2, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, + {"Pentium II Overdrive 300/60", CPU_PENTIUM2D, 300000000, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"Pentium II Overdrive 333", CPU_PENTIUM2D, 333333333, 5, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; #endif #endif diff --git a/src/cpu/x86.h b/src/cpu/x86.h index a49ea9769..cf664a8b1 100644 --- a/src/cpu/x86.h +++ b/src/cpu/x86.h @@ -1,23 +1,33 @@ -uint16_t oldcs; -extern uint32_t rmdat32; -int oldcpl; +#ifdef USE_NEW_DYNAREC +#include "../cpu_new/x86.h" +#else -extern int nmi_enable; +extern uint8_t opcode, opcode2; +extern uint8_t flags_p; +extern uint8_t znptable8[256]; -int tempc; -int output; -int firstrepcycle; +extern uint16_t zero, oldcs; +extern uint16_t lastcs, lastpc; +extern uint16_t *mod1add[2][8]; +extern uint16_t znptable16[65536]; -uint32_t easeg,ealimit,ealimitw; +extern int x86_was_reset, trap; +extern int codegen_flat_ss, codegen_flat_ds; +extern int timetolive, keyboardtimer, trap; +extern int optype, stack32; +extern int oldcpl, cgate32, cpl_override, fpucount; +extern int nmi_enable; +extern int oddeven, inttype; -int skipnextprint; -int inhlt; +extern uint32_t use32; +extern uint32_t rmdat, easeg; +extern uint32_t oxpc, flags_zn; +extern uint32_t abrt_error; +extern uint32_t backupregs[16]; +extern uint32_t *mod1seg[8]; +extern uint32_t *eal_r, *eal_w; -uint8_t opcode; -int noint; - -uint16_t lastcs,lastpc; -extern int timetolive,keyboardtimer; +#define fetchdat rmdat #define setznp168 setznp16 @@ -30,47 +40,21 @@ extern 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]; +#define fetchea() { \ + rmdat = readmemb(cs + pc); \ + pc++; \ + reg = (rmdat >> 3) & 7; \ + mod = (rmdat >> 6) & 3; \ + rm = rmdat & 7; \ + if (mod!=3) \ + fetcheal(); \ + } -int use32; -int stack32; - -#define fetchea() { rmdat=readmemb(cs+pc); pc++; \ - reg=(rmdat>>3)&7; \ - mod=(rmdat>>6)&3; \ - rm=rmdat&7; \ - if (mod!=3) fetcheal(); } - - -int optype; #define JMP 1 #define CALL 2 #define IRET 3 #define OPTYPE_INT 4 -uint32_t oxpc; - -extern uint16_t *mod1add[2][8]; -extern uint32_t *mod1seg[8]; - - -#define IRQTEST ((flags&I_FLAG) && (pic.pend&~pic.mask) && !noint) - -extern int cgate32; - - -extern uint32_t *eal_r, *eal_w; - - -extern uint32_t flags_zn; -extern uint8_t flags_p; -#define FLAG_N (flags_zn>>31) -#define FLAG_Z (flags_zn) -#define FLAG_P (znptable8[flags_p]&P_FLAG) - -extern int gpf; - enum { @@ -83,25 +67,9 @@ enum ABRT_PF = 0xE }; -extern uint32_t abrt_error; -void x86_doabrt(int x86_abrt); - -extern uint8_t opcode2; - -extern uint16_t rds; -extern uint32_t rmdat32; - -extern int inscounts[256]; - -void x86illegal(); - -void x86seg_reset(); -void x86gpf(char *s, uint16_t error); - -extern uint16_t zero; - -extern int x86_was_reset; - -extern int codegen_flat_ds; -extern int codegen_flat_ss; +extern void x86_doabrt(int x86_abrt); +extern void x86illegal(); +extern void x86seg_reset(); +extern void x86gpf(char *s, uint16_t error); +#endif diff --git a/src/cpu/x86_flags.h b/src/cpu/x86_flags.h index dab54dbf6..7068a243d 100644 --- a/src/cpu/x86_flags.h +++ b/src/cpu/x86_flags.h @@ -1,6 +1,8 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ +extern int tempc; + enum { FLAGS_UNKNOWN, @@ -69,7 +71,7 @@ static __inline int ZF_SET() return !cpu_state.flags_res; case FLAGS_UNKNOWN: - return flags & Z_FLAG; + return cpu_state.flags & Z_FLAG; default: return 0; @@ -111,7 +113,7 @@ static __inline int NF_SET() return cpu_state.flags_res & 0x80000000; case FLAGS_UNKNOWN: - return flags & N_FLAG; + return cpu_state.flags & N_FLAG; default: return 0; @@ -149,7 +151,7 @@ static __inline int PF_SET() return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; case FLAGS_UNKNOWN: - return flags & P_FLAG; + return cpu_state.flags & P_FLAG; default: return 0; @@ -171,20 +173,20 @@ static __inline int VF_SET() case FLAGS_ADD8: case FLAGS_INC8: return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); - case FLAGS_ADD16: + case FLAGS_ADD16: case FLAGS_INC16: return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); - case FLAGS_ADD32: + case FLAGS_ADD32: case FLAGS_INC32: return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); - + case FLAGS_SUB8: case FLAGS_DEC8: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); - case FLAGS_SUB16: + case FLAGS_SUB16: case FLAGS_DEC16: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); - case FLAGS_SUB32: + case FLAGS_SUB32: case FLAGS_DEC32: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); @@ -203,7 +205,7 @@ static __inline int VF_SET() return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); case FLAGS_UNKNOWN: - return flags & V_FLAG; + return cpu_state.flags & V_FLAG; default: return 0; @@ -243,9 +245,9 @@ 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_UNKNOWN: - return flags & A_FLAG; + return cpu_state.flags & A_FLAG; default: return 0; @@ -267,7 +269,7 @@ static __inline int CF_SET() case FLAGS_SUB16: case FLAGS_SUB32: return (cpu_state.flags_op1 < cpu_state.flags_op2); - + case FLAGS_SHL8: return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80; case FLAGS_SHL16: @@ -299,7 +301,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; default: return 0; @@ -317,7 +319,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; } } @@ -332,9 +334,9 @@ 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; } } @@ -457,65 +459,68 @@ 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&=~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 __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&=~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 __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; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + cpu_state.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&=~0x8D5; + cpu_state.flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + cpu_state.flags|=(znptable8[c&0xFF]&P_FLAG); + if ((c>a) || (c==a && tempc)) cpu_state.flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) cpu_state.flags|=V_FLAG; + if (((a&0xF)-((b&0xF)+tempc))&0x10) cpu_state.flags|=A_FLAG; } +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); \ No newline at end of file diff --git a/src/cpu/x86_ops.h b/src/cpu/x86_ops.h index 5b30c0747..12a7e96bc 100644 --- a/src/cpu/x86_ops.h +++ b/src/cpu/x86_ops.h @@ -83,7 +83,9 @@ extern const OpFn dynarec_ops_winchip_0f[1024]; extern const OpFn dynarec_ops_pentium_0f[1024]; extern const OpFn dynarec_ops_pentiummmx_0f[1024]; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) extern const OpFn dynarec_ops_c6x86mx_0f[1024]; +#endif #if defined(DEV_BRANCH) && defined(USE_AMD_K) extern const OpFn dynarec_ops_k6_0f[1024]; @@ -175,7 +177,9 @@ extern const OpFn ops_winchip_0f[1024]; extern const OpFn ops_pentium_0f[1024]; extern const OpFn ops_pentiummmx_0f[1024]; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) extern const OpFn ops_c6x86mx_0f[1024]; +#endif #if defined(DEV_BRANCH) && defined(USE_AMD_K) extern const OpFn ops_k6_0f[1024]; diff --git a/src/cpu/x86_ops_amd.h b/src/cpu/x86_ops_amd.h index acd7790ff..8f003e1fb 100644 --- a/src/cpu/x86_ops_amd.h +++ b/src/cpu/x86_ops_amd.h @@ -8,7 +8,7 @@ * * AMD SYSCALL and SYSRET CPU Instructions. * - * Version: @(#)x86_ops_amd.h 1.0.3 2018/04/25 + * Version: @(#)x86_ops_amd.h 1.0.4 2018/10/17 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -40,36 +40,36 @@ static int opSYSCALL(uint32_t fetchdat) if (!AMD_SYSCALL_SB) return internal_illegal("SYSCALL: AMD SYSCALL SB MSR is zero"); /* Set VM, IF, RF to 0. */ - /* eflags &= ~0x00030200; - flags &= ~0x0200; */ + /* cpu_state.eflags &= ~0x00030200; + cpu_state.flags &= ~0x0200; */ /* Let's do this by the AMD spec. */ ECX = cpu_state.pc; - eflags &= ~0x0002; - flags &= ~0x0200; + cpu_state.eflags &= ~0x0002; + cpu_state.flags &= ~0x0200; /* CS */ - _cs.seg = AMD_SYSCALL_SB & ~7; + cpu_state.seg_cs.seg = AMD_SYSCALL_SB & ~7; if (AMD_SYSCALL_SB & 4) { - if (_cs.seg >= ldt.limit) + if (cpu_state.seg_cs.seg >= ldt.limit) { - pclog("Bigger than LDT limit %04X %04X CS\n",AMD_SYSCALL_SB,ldt.limit); + x386_dynarec_log("Bigger than LDT limit %04X %04X CS\n",AMD_SYSCALL_SB,ldt.limit); x86gpf(NULL, AMD_SYSCALL_SB & ~3); return 1; } - _cs.seg +=ldt.base; + cpu_state.seg_cs.seg +=ldt.base; } else { - if (_cs.seg >= gdt.limit) + if (cpu_state.seg_cs.seg >= gdt.limit) { - pclog("Bigger than GDT limit %04X %04X CS\n",AMD_SYSCALL_SB,gdt.limit); + x386_dynarec_log("Bigger than GDT limit %04X %04X CS\n",AMD_SYSCALL_SB,gdt.limit); x86gpf(NULL, AMD_SYSCALL_SB & ~3); return 1; } - _cs.seg += gdt.base; + cpu_state.seg_cs.seg += gdt.base; } cpl_override = 1; @@ -83,27 +83,27 @@ static int opSYSCALL(uint32_t fetchdat) use32 = 0x300; CS = (AMD_SYSCALL_SB & ~3) | 0; - do_seg_load(&_cs, syscall_cs_seg_data); + do_seg_load(&cpu_state.seg_cs, syscall_cs_seg_data); use32 = 0x300; CS = (CS & 0xFFFC) | 0; - _cs.limit = 0xFFFFFFFF; - _cs.limit_high = 0xFFFFFFFF; + cpu_state.seg_cs.limit = 0xFFFFFFFF; + cpu_state.seg_cs.limit_high = 0xFFFFFFFF; /* SS */ syscall_ss_seg_data[0] = 0xFFFF; syscall_ss_seg_data[1] = 0; syscall_ss_seg_data[2] = 0x9300; syscall_ss_seg_data[3] = 0xC0; - do_seg_load(&_ss, syscall_ss_seg_data); - _ss.seg = (AMD_SYSCALL_SB + 8) & 0xFFFC; + do_seg_load(&cpu_state.seg_ss, syscall_ss_seg_data); + cpu_state.seg_ss.seg = (AMD_SYSCALL_SB + 8) & 0xFFFC; stack32 = 1; - _ss.limit = 0xFFFFFFFF; - _ss.limit_high = 0xFFFFFFFF; + cpu_state.seg_ss.limit = 0xFFFFFFFF; + cpu_state.seg_ss.limit_high = 0xFFFFFFFF; - _ss.checked = 0; + cpu_state.seg_ss.checked = 0; cpu_state.pc = AMD_SYSCALL_EIP; @@ -125,29 +125,29 @@ static int opSYSRET(uint32_t fetchdat) cpu_state.pc = ECX; - eflags |= (1 << 1); + cpu_state.eflags |= (1 << 1); /* CS */ - _cs.seg = AMD_SYSRET_SB & ~7; + cpu_state.seg_cs.seg = AMD_SYSRET_SB & ~7; if (AMD_SYSRET_SB & 4) { - if (_cs.seg >= ldt.limit) + if (cpu_state.seg_cs.seg >= ldt.limit) { - pclog("Bigger than LDT limit %04X %04X CS\n",AMD_SYSRET_SB,ldt.limit); + x386_dynarec_log("Bigger than LDT limit %04X %04X CS\n",AMD_SYSRET_SB,ldt.limit); x86gpf(NULL, AMD_SYSRET_SB & ~3); return 1; } - _cs.seg +=ldt.base; + cpu_state.seg_cs.seg +=ldt.base; } else { - if (_cs.seg >= gdt.limit) + if (cpu_state.seg_cs.seg >= gdt.limit) { - pclog("Bigger than GDT limit %04X %04X CS\n",AMD_SYSRET_SB,gdt.limit); + x386_dynarec_log("Bigger than GDT limit %04X %04X CS\n",AMD_SYSRET_SB,gdt.limit); x86gpf(NULL, AMD_SYSRET_SB & ~3); return 1; } - _cs.seg += gdt.base; + cpu_state.seg_cs.seg += gdt.base; } cpl_override = 1; @@ -161,28 +161,28 @@ static int opSYSRET(uint32_t fetchdat) use32 = 0x300; CS = (AMD_SYSRET_SB & ~3) | 3; - do_seg_load(&_cs, sysret_cs_seg_data); + do_seg_load(&cpu_state.seg_cs, sysret_cs_seg_data); flushmmucache_cr3(); use32 = 0x300; CS = (CS & 0xFFFC) | 3; - _cs.limit = 0xFFFFFFFF; - _cs.limit_high = 0xFFFFFFFF; + cpu_state.seg_cs.limit = 0xFFFFFFFF; + cpu_state.seg_cs.limit_high = 0xFFFFFFFF; /* SS */ sysret_ss_seg_data[0] = 0xFFFF; sysret_ss_seg_data[1] = 0; sysret_ss_seg_data[2] = 0xF300; sysret_ss_seg_data[3] = 0xC0; - do_seg_load(&_ss, sysret_ss_seg_data); - _ss.seg = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; + do_seg_load(&cpu_state.seg_ss, sysret_ss_seg_data); + cpu_state.seg_ss.seg = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; stack32 = 1; - _ss.limit = 0xFFFFFFFF; - _ss.limit_high = 0xFFFFFFFF; + cpu_state.seg_ss.limit = 0xFFFFFFFF; + cpu_state.seg_ss.limit_high = 0xFFFFFFFF; - _ss.checked = 0; + cpu_state.seg_ss.checked = 0; CLOCK_CYCLES(20); diff --git a/src/cpu/x86_ops_arith.h b/src/cpu/x86_ops_arith.h index 3c6b67fa6..80a0da788 100644 --- a/src/cpu/x86_ops_arith.h +++ b/src/cpu/x86_ops_arith.h @@ -16,6 +16,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteab(); if (cpu_state.abrt) return 1; \ src = getr8(cpu_reg); \ seteab(operation); if (cpu_state.abrt) return 1; \ @@ -42,6 +43,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteab(); if (cpu_state.abrt) return 1; \ src = getr8(cpu_reg); \ seteab(operation); if (cpu_state.abrt) return 1; \ @@ -69,6 +71,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteaw(); if (cpu_state.abrt) return 1; \ src = cpu_state.regs[cpu_reg].w; \ seteaw(operation); if (cpu_state.abrt) return 1; \ @@ -95,6 +98,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteaw(); if (cpu_state.abrt) return 1; \ src = cpu_state.regs[cpu_reg].w; \ seteaw(operation); if (cpu_state.abrt) return 1; \ @@ -122,6 +126,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteal(); if (cpu_state.abrt) return 1; \ src = cpu_state.regs[cpu_reg].l; \ seteal(operation); if (cpu_state.abrt) return 1; \ @@ -148,6 +153,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteal(); if (cpu_state.abrt) return 1; \ src = cpu_state.regs[cpu_reg].l; \ seteal(operation); if (cpu_state.abrt) return 1; \ @@ -163,6 +169,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; \ @@ -176,6 +184,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; \ @@ -190,6 +200,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; \ @@ -203,6 +215,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; \ @@ -217,6 +231,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; \ @@ -230,6 +246,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; \ @@ -287,6 +305,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); @@ -298,6 +318,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); @@ -310,6 +332,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); @@ -321,6 +345,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); @@ -333,6 +359,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); @@ -344,6 +372,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); @@ -355,7 +385,9 @@ static int opCMP_l_rmw_a32(uint32_t fetchdat) static int opCMP_b_rm_a16(uint32_t fetchdat) { uint8_t src; - fetch_ea_16(fetchdat); + fetch_ea_16(fetchdat); + 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); @@ -365,7 +397,9 @@ static int opCMP_b_rm_a16(uint32_t fetchdat) static int opCMP_b_rm_a32(uint32_t fetchdat) { uint8_t src; - fetch_ea_32(fetchdat); + fetch_ea_32(fetchdat); + 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); @@ -376,7 +410,9 @@ static int opCMP_b_rm_a32(uint32_t fetchdat) static int opCMP_w_rm_a16(uint32_t fetchdat) { uint16_t src; - fetch_ea_16(fetchdat); + fetch_ea_16(fetchdat); + 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); @@ -386,7 +422,9 @@ static int opCMP_w_rm_a16(uint32_t fetchdat) static int opCMP_w_rm_a32(uint32_t fetchdat) { uint16_t src; - fetch_ea_32(fetchdat); + fetch_ea_32(fetchdat); + 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); @@ -395,9 +433,11 @@ static int opCMP_w_rm_a32(uint32_t fetchdat) } static int opCMP_l_rm_a16(uint32_t fetchdat) -{ - uint32_t src; - fetch_ea_16(fetchdat); +{ + uint32_t src; + fetch_ea_16(fetchdat); + 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); @@ -407,7 +447,9 @@ static int opCMP_l_rm_a16(uint32_t fetchdat) static int opCMP_l_rm_a32(uint32_t fetchdat) { uint32_t src; - fetch_ea_32(fetchdat); + fetch_ea_32(fetchdat); + 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); @@ -446,6 +488,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); @@ -458,6 +502,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); @@ -471,6 +517,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); @@ -483,6 +531,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); @@ -496,6 +546,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); @@ -508,6 +560,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); @@ -600,6 +654,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) @@ -614,6 +670,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) @@ -628,6 +686,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) @@ -642,6 +702,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) @@ -670,6 +732,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) @@ -685,6 +749,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); @@ -700,6 +766,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); @@ -716,6 +784,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); @@ -731,6 +801,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/cpu/x86_ops_arith_ex.h b/src/cpu/x86_ops_arith_ex.h new file mode 100644 index 000000000..cc4fcd7c3 --- /dev/null +++ b/src/cpu/x86_ops_arith_ex.h @@ -0,0 +1,752 @@ +#define OP_ARITH(name, operation, setflags, flagops, gettempc) \ + static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + 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); \ + } \ + return 0; \ + } \ + static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + 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, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _b_rm_a16(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = getr8(cpu_reg); \ + src = geteab(); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(cpu_reg, operation); \ + 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); \ + return 0; \ + } \ + static int op ## name ## _b_rm_a32(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = getr8(cpu_reg); \ + src = geteab(); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(cpu_reg, operation); \ + 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); \ + return 0; \ + } \ + \ + static int op ## name ## _w_rm_a16(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[cpu_reg].w; \ + src = geteaw(); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_reg].w = operation; \ + 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); \ + return 0; \ + } \ + static int op ## name ## _w_rm_a32(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[cpu_reg].w; \ + src = geteaw(); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_reg].w = operation; \ + 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); \ + return 0; \ + } \ + \ + static int op ## name ## _l_rm_a16(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[cpu_reg].l; \ + src = geteal(); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_reg].l = operation; \ + 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); \ + return 0; \ + } \ + static int op ## name ## _l_rm_a32(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[cpu_reg].l; \ + src = geteal(); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_reg].l = operation; \ + 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); \ + return 0; \ + } \ + \ + static int op ## name ## _AL_imm(uint32_t fetchdat) \ + { \ + uint8_t dst = AL; \ + uint8_t src = getbytef(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 8 flagops; \ + AL = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _AX_imm(uint32_t fetchdat) \ + { \ + uint16_t dst = AX; \ + uint16_t src = getwordf(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 16 flagops; \ + AX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _EAX_imm(uint32_t fetchdat) \ + { \ + uint32_t dst = EAX; \ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 32 flagops; \ + EAX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); \ + return 0; \ + } + +OP_ARITH(ADD, dst + src, setadd, (dst, src), 0) +OP_ARITH(ADC, dst + src + tempc, setadc, (dst, src), 1) +OP_ARITH(SUB, dst - src, setsub, (dst, src), 0) +OP_ARITH(SBB, dst - (src + tempc), setsbc, (dst, src), 1) +OP_ARITH(OR, dst | src, setznp, (dst | src), 0) +OP_ARITH(AND, dst & src, setznp, (dst & src), 0) +OP_ARITH(XOR, dst ^ src, setznp, (dst ^ src), 0) + +static int opCMP_b_rmw_a16(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_16(fetchdat); + dst = geteab(); if (cpu_state.abrt) return 1; + setsub8(dst, getr8(cpu_reg)); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_b_rmw_a32(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_32(fetchdat); + dst = geteab(); if (cpu_state.abrt) return 1; + setsub8(dst, getr8(cpu_reg)); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_w_rmw_a16(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_16(fetchdat); + 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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_w_rmw_a32(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_32(fetchdat); + 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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_l_rmw_a16(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_16(fetchdat); + 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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opCMP_l_rmw_a32(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_32(fetchdat); + 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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opCMP_b_rm_a16(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_16(fetchdat); + 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); + return 0; +} +static int opCMP_b_rm_a32(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_32(fetchdat); + 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); + return 0; +} + +static int opCMP_w_rm_a16(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_16(fetchdat); + 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); + return 0; +} +static int opCMP_w_rm_a32(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_32(fetchdat); + 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); + return 0; +} + +static int opCMP_l_rm_a16(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_16(fetchdat); + 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); + return 0; +} +static int opCMP_l_rm_a32(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_32(fetchdat); + 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); + return 0; +} + +static int opCMP_AL_imm(uint32_t fetchdat) +{ + uint8_t src = getbytef(); + setsub8(AL, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_AX_imm(uint32_t fetchdat) +{ + uint16_t src = getwordf(); + setsub16(AX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_EAX_imm(uint32_t fetchdat) +{ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; + setsub32(EAX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + +static int opTEST_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + temp2 = getr8(cpu_reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opTEST_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + temp2 = getr8(cpu_reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opTEST_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opTEST_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opTEST_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opTEST_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opTEST_AL(uint32_t fetchdat) +{ + uint8_t temp = getbytef(); + setznp8(AL & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_AX(uint32_t fetchdat) +{ + uint16_t temp = getwordf(); + setznp16(AX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_EAX(uint32_t fetchdat) +{ + uint32_t temp = getlong(); if (cpu_state.abrt) return 1; + setznp32(EAX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + + +#define ARITH_MULTI(ea_width, flag_width, is32) \ + dst = read ## ea_width(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; \ + switch ((rmdat >> 3) & 7) \ + { \ + case 0x00: /*ADD ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + write ## ea_width(easeg, cpu_state.eaaddr, dst + src); if (cpu_state.abrt) return 1; \ + setadd ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x01: /*OR ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + dst |= src; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x02: /*ADC ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + tempc = CF_SET() ? 1 : 0; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst + src + tempc); if (cpu_state.abrt) return 1; \ + setadc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x03: /*SBB ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + tempc = CF_SET() ? 1 : 0; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst - (src + tempc)); if (cpu_state.abrt) return 1; \ + setsbc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x04: /*AND ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + dst &= src; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x05: /*SUB ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + write ## ea_width(easeg, cpu_state.eaaddr, dst - src); if (cpu_state.abrt) return 1; \ + setsub ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x06: /*XOR ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + dst ^= src; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x07: /*CMP ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 0, is32) \ + setsub ## flag_width(dst, src); \ + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); \ + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 7); \ + break; \ + } + + +static int op80_a16(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + ARITH_MULTI(8, 8, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op80_a32(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + ARITH_MULTI(8, 8, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +static int op81_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getword(); if (cpu_state.abrt) return 1; + ARITH_MULTI(16, 16, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op81_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getword(); if (cpu_state.abrt) return 1; + ARITH_MULTI(16, 16, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +static int op81_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getlong(); if (cpu_state.abrt) return 1; + ARITH_MULTI(32, 32, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +static int op81_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getlong(); if (cpu_state.abrt) return 1; + ARITH_MULTI(32, 32, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + +static int op83_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(16, 16, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op83_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(16, 16, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} + +static int op83_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(32, 32, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +static int op83_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(32, 32, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + diff --git a/src/cpu/x86_ops_atomic.h b/src/cpu/x86_ops_atomic.h index 7d90e22d1..c490d747a 100644 --- a/src/cpu/x86_ops_atomic.h +++ b/src/cpu/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/cpu/x86_ops_bcd.h b/src/cpu/x86_ops_bcd.h index 241216b14..cd29b1405 100644 --- a/src/cpu/x86_ops_bcd.h +++ b/src/cpu/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/cpu/x86_ops_bit.h b/src/cpu/x86_ops_bit.h index dc10b4f6c..42d9aa4aa 100644 --- a/src/cpu/x86_ops_bit.h +++ b/src/cpu/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,6 +159,8 @@ 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; @@ -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; @@ -171,14 +185,14 @@ static int opBA_w_a16(uint32_t fetchdat) break; default: - pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + x386_dynarec_log("Bad 0F BA opcode %02X\n", rmdat & 0x38); cpu_state.pc = cpu_state.oldpc; x86illegal(); 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,6 +203,8 @@ 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; @@ -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; @@ -213,14 +229,14 @@ static int opBA_w_a32(uint32_t fetchdat) break; default: - pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + x386_dynarec_log("Bad 0F BA opcode %02X\n", rmdat & 0x38); cpu_state.pc = cpu_state.oldpc; x86illegal(); 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,6 +248,8 @@ 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; @@ -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; @@ -256,14 +274,14 @@ static int opBA_l_a16(uint32_t fetchdat) break; default: - pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + x386_dynarec_log("Bad 0F BA opcode %02X\n", rmdat & 0x38); cpu_state.pc = cpu_state.oldpc; x86illegal(); 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,6 +292,8 @@ 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; @@ -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; @@ -298,14 +318,14 @@ static int opBA_l_a32(uint32_t fetchdat) break; default: - pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + x386_dynarec_log("Bad 0F BA opcode %02X\n", rmdat & 0x38); cpu_state.pc = cpu_state.oldpc; x86illegal(); 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/cpu/x86_ops_bitscan.h b/src/cpu/x86_ops_bitscan.h index 9252b4b87..46f0fc605 100644 --- a/src/cpu/x86_ops_bitscan.h +++ b/src/cpu/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 = 0; 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 = 0; 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 = 0; 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 = 0; 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 = 0; 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 = 0; 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 = 0; 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 = 0; 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/cpu/x86_ops_call.h b/src/cpu/x86_ops_call.h index 30e60410c..8c52e632e 100644 --- a/src/cpu/x86_ops_call.h +++ b/src/cpu/x86_ops_call.h @@ -1,11 +1,11 @@ #define CALL_FAR_w(new_seg, new_pc) \ old_cs = CS; \ old_pc = cpu_state.pc; \ - oxpc = 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); \ else \ { \ loadcs(new_seg); \ @@ -30,11 +30,11 @@ #define CALL_FAR_l(new_seg, new_pc) \ old_cs = CS; \ old_pc = cpu_state.pc; \ - oxpc = 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); \ else \ { \ loadcs(new_seg); \ @@ -104,6 +104,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 +113,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 +122,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 +134,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 +145,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,6 +156,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); oxpc = cpu_state.pc; new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -156,6 +168,8 @@ static int opFF_w_a16(uint32_t fetchdat) 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 +195,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 +204,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 +213,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 +225,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 +236,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,6 +247,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); oxpc = cpu_state.pc; new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -233,6 +259,8 @@ static int opFF_w_a32(uint32_t fetchdat) 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 +287,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 +296,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 +305,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 +317,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 +328,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,6 +339,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); oxpc = cpu_state.pc; new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -311,6 +351,8 @@ static int opFF_l_a16(uint32_t fetchdat) 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 +378,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 +387,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 +396,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 +408,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 +419,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,6 +430,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); oxpc = cpu_state.pc; new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -388,6 +442,8 @@ static int opFF_l_a32(uint32_t fetchdat) 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/cpu/x86_ops_flag.h b/src/cpu/x86_ops_flag.h index 59c692c65..8441b4987 100644 --- a/src/cpu/x86_ops_flag.h +++ b/src/cpu/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,10 +27,10 @@ static int opCLI(uint32_t fetchdat) { if (!IOPLp) { - if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || - ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { - eflags &= ~VIF_FLAG; + cpu_state.eflags &= ~VIF_FLAG; } else { @@ -39,7 +39,7 @@ static int opCLI(uint32_t fetchdat) } } else - flags &= ~I_FLAG; + cpu_state.flags &= ~I_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); @@ -49,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; @@ -65,16 +65,16 @@ static int opSTI(uint32_t fetchdat) { if (!IOPLp) { - if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || - ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { - if (eflags & VIP_FLAG) + if (cpu_state.eflags & VIP_FLAG) { x86gpf(NULL,0); return 1; } else - eflags |= VIF_FLAG; + cpu_state.eflags |= VIF_FLAG; } else { @@ -83,7 +83,7 @@ static int opSTI(uint32_t fetchdat) } } else - flags |= I_FLAG; + cpu_state.flags |= I_FLAG; CPU_BLOCK_END(); @@ -95,7 +95,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); @@ -108,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; @@ -116,15 +116,15 @@ 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)) { if (cr4 & CR4_VME) { uint16_t temp; flags_rebuild(); - temp = (flags & ~I_FLAG) | 0x3000; - if (eflags & VIF_FLAG) + temp = (cpu_state.flags & ~I_FLAG) | 0x3000; + if (cpu_state.eflags & VIF_FLAG) temp |= I_FLAG; PUSH_W(temp); } @@ -137,7 +137,7 @@ static int opPUSHF(uint32_t fetchdat) else { flags_rebuild(); - PUSH_W(flags); + PUSH_W(cpu_state.flags); } CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); @@ -146,16 +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 (cpu_CR4_mask & CR4_VME) tempw = eflags & 0x3c; - else 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; @@ -165,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; @@ -173,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); @@ -192,7 +192,7 @@ static int opPOPF(uint32_t fetchdat) { uint16_t tempw; - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { if (cr4 & CR4_VME) { @@ -206,17 +206,17 @@ static int opPOPF(uint32_t fetchdat) return 1; } - if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (eflags & VIP_FLAG))) + if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (cpu_state.eflags & VIP_FLAG))) { ESP = old_esp; x86gpf(NULL, 0); return 1; } if (tempw & I_FLAG) - eflags |= VIF_FLAG; + cpu_state.eflags |= VIF_FLAG; else - eflags &= ~VIF_FLAG; - flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; } else { @@ -231,11 +231,11 @@ static int opPOPF(uint32_t fetchdat) return 1; if (!(CPL) || !(msw & 1)) - flags = (tempw & 0x7fd5) | 2; + cpu_state.flags = (tempw & 0x7fd5) | 2; else if (IOPLp) - flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; else - flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; } flags_extract(); @@ -252,7 +252,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; @@ -260,16 +260,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 ? 0x3c0000 : 0; - templ |= ((eflags&3) << 16); - if (cpu_CR4_mask & CR4_VME) eflags = (templ >> 16) & 0x3f; - else if (CPUID) eflags = (templ >> 16) & 0x27; - else if (is486) eflags = (templ >> 16) & 7; - else eflags = (templ >> 16) & 3; + 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/cpu/x86_ops_i686.h b/src/cpu/x86_ops_i686.h index d4418bfb4..6d4cf7484 100644 --- a/src/cpu/x86_ops_i686.h +++ b/src/cpu/x86_ops_i686.h @@ -8,7 +8,7 @@ * * x86 i686 (Pentium Pro/Pentium II) CPU Instructions. * - * Version: @(#)x86_ops_i686.h 1.0.4 2018/04/25 + * Version: @(#)x86_ops_i686.h 1.0.5 2018/10/17 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -40,18 +40,18 @@ static int opSYSENTER(uint32_t fetchdat) uint16_t sysenter_ss_seg_data[4]; #ifdef SYSENTER_LOG - pclog("SYSENTER called\n"); + x386_dynarec_log("SYSENTER called\n"); #endif - if (!(cr0 & 1)) return internal_illegal("SYSENTER: CPU not in protected mode"); + if (!(msw & 1)) return internal_illegal("SYSENTER: CPU not in protected mode"); if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSENTER: CS MSR is zero"); #ifdef SYSENTER_LOG - pclog("SYSENTER started:\n"); - pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); - pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); - pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); - pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); + x386_dynarec_log("SYSENTER started:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32); #endif if (cpu_state.abrt) return 1; @@ -63,17 +63,17 @@ static int opSYSENTER(uint32_t fetchdat) cgate16 = cgate32 = 0; \ /* Set VM, RF, and IF to 0. */ - eflags &= ~0x0003; - flags &= ~0x0200; + cpu_state.eflags &= ~(VM_FLAG | 0x0001); + cpu_state.flags &= ~I_FLAG; CS = (cs_msr & 0xFFFC); make_seg_data(sysenter_cs_seg_data, 0, 0xFFFFF, 11, 1, 0, 1, 1, 1, 0); - do_seg_load(&_cs, sysenter_cs_seg_data); + do_seg_load(&cpu_state.seg_cs, sysenter_cs_seg_data); use32 = 0x300; SS = ((cs_msr + 8) & 0xFFFC); make_seg_data(sysenter_ss_seg_data, 0, 0xFFFFF, 3, 1, 0, 1, 1, 1, 0); - do_seg_load(&_ss, sysenter_ss_seg_data); + do_seg_load(&cpu_state.seg_ss, sysenter_ss_seg_data); stack32 = 1; cycles -= timing_call_pm; @@ -83,11 +83,11 @@ static int opSYSENTER(uint32_t fetchdat) CPU_BLOCK_END(); #ifdef SYSENTER_LOG - pclog("SYSENTER completed:\n"); - pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); - pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); - pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); - pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); + x386_dynarec_log("SYSENTER completed:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32); #endif return 0; @@ -99,19 +99,19 @@ static int opSYSEXIT(uint32_t fetchdat) uint16_t sysexit_ss_seg_data[4]; #ifdef SYSEXIT_LOG - pclog("SYSEXIT called\n"); + x386_dynarec_log("SYSEXIT called\n"); #endif if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSEXIT: CS MSR is zero"); - if (!(cr0 & 1)) return internal_illegal("SYSEXIT: CPU not in protected mode"); - if (CS & 3) return internal_illegal("SYSEXIT: CPL not 0"); + if (!(msw & 1)) return internal_illegal("SYSEXIT: CPU not in protected mode"); + if (CPL) return internal_illegal("SYSEXIT: CPL not 0"); #ifdef SYSEXIT_LOG - pclog("SYSEXIT start:\n"); - pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); - pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); - pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); - pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); + x386_dynarec_log("SYSEXIT start:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32, ECX, EDX); #endif if (cpu_state.abrt) return 1; @@ -124,12 +124,12 @@ static int opSYSEXIT(uint32_t fetchdat) CS = ((cs_msr + 16) & 0xFFFC) | 3; make_seg_data(sysexit_cs_seg_data, 0, 0xFFFFF, 11, 1, 3, 1, 1, 1, 0); - do_seg_load(&_cs, sysexit_cs_seg_data); + do_seg_load(&cpu_state.seg_cs, sysexit_cs_seg_data); use32 = 0x300; SS = CS + 8; make_seg_data(sysexit_ss_seg_data, 0, 0xFFFFF, 3, 1, 3, 1, 1, 1, 0); - do_seg_load(&_ss, sysexit_ss_seg_data); + do_seg_load(&cpu_state.seg_ss, sysexit_ss_seg_data); stack32 = 1; flushmmucache_cr3(); @@ -141,11 +141,11 @@ static int opSYSEXIT(uint32_t fetchdat) CPU_BLOCK_END(); #ifdef SYSEXIT_LOG - pclog("SYSEXIT completed:\n"); - pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); - pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); - pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); - pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); + x386_dynarec_log("SYSEXIT completed:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32, ECX, EDX); #endif return 0; @@ -169,7 +169,7 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) if (cpu_state.eaaddr & 0xf) { - pclog("Effective address %04X not on 16-byte boundary\n", cpu_state.eaaddr); + x386_dynarec_log("Effective address %04X not on 16-byte boundary\n", cpu_state.eaaddr); x86gpf(NULL, 0); return cpu_state.abrt; } @@ -202,7 +202,7 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) /* if (cr0 & 1) { x87_pc_seg &= 0xFFFC; - x87_pc_seg |= ((_cs.access >> 5) & 3); + x87_pc_seg |= ((cpu_state.seg_cs.access >> 5) & 3); } */ ftwb = readmemb(easeg, cpu_state.eaaddr + 4); @@ -262,7 +262,7 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) CLOCK_CYCLES((cr0 & 1) ? 34 : 44); - if(cpu_state.abrt) pclog("FXRSTOR: abrt != 0\n"); + if(cpu_state.abrt) x386_dynarec_log("FXRSTOR: abrt != 0\n"); } else { @@ -323,7 +323,7 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) CLOCK_CYCLES((cr0 & 1) ? 56 : 67); - if(cpu_state.abrt) pclog("FXSAVE: abrt != 0\n"); + if(cpu_state.abrt) x386_dynarec_log("FXSAVE: abrt != 0\n"); } return cpu_state.abrt; @@ -347,7 +347,7 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) if (cpu_state.eaaddr & 0xf) { - pclog("Effective address %08X not on 16-byte boundary\n", cpu_state.eaaddr); + x386_dynarec_log("Effective address %08X not on 16-byte boundary\n", cpu_state.eaaddr); x86gpf(NULL, 0); return cpu_state.abrt; } @@ -380,7 +380,7 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) /* if (cr0 & 1) { x87_pc_seg &= 0xFFFC; - x87_pc_seg |= ((_cs.access >> 5) & 3); + x87_pc_seg |= ((cpu_state.seg_cs.access >> 5) & 3); } */ ftwb = readmemb(easeg, cpu_state.eaaddr + 4); @@ -440,7 +440,7 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) CLOCK_CYCLES((cr0 & 1) ? 34 : 44); - if(cpu_state.abrt) pclog("FXRSTOR: abrt != 0\n"); + if(cpu_state.abrt) x386_dynarec_log("FXRSTOR: abrt != 0\n"); } else { @@ -501,7 +501,7 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) CLOCK_CYCLES((cr0 & 1) ? 56 : 67); - if(cpu_state.abrt) pclog("FXSAVE: abrt != 0\n"); + if(cpu_state.abrt) x386_dynarec_log("FXSAVE: abrt != 0\n"); } return cpu_state.abrt; diff --git a/src/cpu/x86_ops_inc_dec.h b/src/cpu/x86_ops_inc_dec.h index 56293c7bf..ff4a4ab73 100644 --- a/src/cpu/x86_ops_inc_dec.h +++ b/src/cpu/x86_ops_inc_dec.h @@ -49,7 +49,9 @@ static int opINCDEC_b_a16(uint32_t fetchdat) { uint8_t temp; - fetch_ea_16(fetchdat); + 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) @@ -70,7 +72,9 @@ static int opINCDEC_b_a32(uint32_t fetchdat) { uint8_t temp; - fetch_ea_32(fetchdat); + 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/cpu/x86_ops_int.h b/src/cpu/x86_ops_int.h index 5aa05fc11..260fcdad5 100644 --- a/src/cpu/x86_ops_int.h +++ b/src/cpu/x86_ops_int.h @@ -1,7 +1,7 @@ static int opINT3(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(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; UN_USED(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; @@ -31,7 +31,7 @@ static int opINT(uint32_t fetchdat) int cycles_old = cycles; UN_USED(cycles_old); uint8_t temp = getbytef(); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { if (cr4 & CR4_VME) { @@ -72,7 +72,7 @@ static int opINTO(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(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/cpu/x86_ops_jump.h b/src/cpu/x86_ops_jump.h index 63ca65ea0..6eb9862af 100644 --- a/src/cpu/x86_ops_jump.h +++ b/src/cpu/x86_ops_jump.h @@ -247,12 +247,12 @@ static int opJMP_r32(uint32_t fetchdat) static int opJMP_far_a16(uint32_t fetchdat) { uint16_t addr, seg; - uint32_t oxpc; + uint32_t old_pc; addr = getwordf(); seg = getword(); if (cpu_state.abrt) return 1; - oxpc = cpu_state.pc; + 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(); @@ -261,12 +261,12 @@ static int opJMP_far_a16(uint32_t fetchdat) static int opJMP_far_a32(uint32_t fetchdat) { uint16_t seg; - uint32_t addr, oxpc; + uint32_t addr, old_pc; addr = getlong(); seg = getword(); if (cpu_state.abrt) return 1; - oxpc = cpu_state.pc; + 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(); diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index 9fa219919..08abe6790 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -1,21 +1,3 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Miscellaneous x86 CPU Instructions. - * - * Version: @(#)x86_ops_misc.h 1.0.1 2018/04/12 - * - * Author: Sarah Walker, - * Miran Grca, - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - */ - static int opCBW(uint32_t fetchdat) { AH = (AL & 0x80) ? 0xff : 0; @@ -70,8 +52,8 @@ static int opF6_a16(uint32_t fetchdat) int8_t temps; fetch_ea_16(fetchdat); - if (cpu_mod != 3) - { + 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; @@ -86,11 +68,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); @@ -99,8 +85,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; @@ -108,8 +94,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; @@ -123,8 +109,8 @@ static int opF6_a16(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags |= 0x8D5; /*Not a Cyrix*/ - flags &= ~1; + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -146,8 +132,8 @@ static int opF6_a16(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags|=0x8D5; /*Not a Cyrix*/ - flags &= ~1; + cpu_state.flags|=0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -160,7 +146,6 @@ static int opF6_a16(uint32_t fetchdat) break; default: - pclog("Bad F6 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -173,11 +158,13 @@ static int opF6_a32(uint32_t fetchdat) 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) { case 0x00: /*TEST b,#8*/ - case 0x08: + case 0x08: src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; setznp8(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -185,11 +172,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); @@ -198,8 +189,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; @@ -207,8 +198,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; @@ -222,8 +213,8 @@ static int opF6_a32(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags |= 0x8D5; /*Not a Cyrix*/ - flags &= ~1; + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -245,8 +236,8 @@ static int opF6_a32(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags|=0x8D5; /*Not a Cyrix*/ - flags &= ~1; + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -259,7 +250,6 @@ static int opF6_a32(uint32_t fetchdat) break; default: - pclog("Bad F6 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -275,11 +265,13 @@ static int opF7_w_a16(uint32_t fetchdat) 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) { case 0x00: /*TEST w*/ - case 0x08: + case 0x08: src = getword(); if (cpu_state.abrt) return 1; setznp16(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -287,11 +279,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); @@ -302,8 +298,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; @@ -312,8 +308,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; @@ -354,7 +350,6 @@ static int opF7_w_a16(uint32_t fetchdat) break; default: - pclog("Bad F7 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -362,16 +357,18 @@ static int opF7_w_a16(uint32_t fetchdat) static int opF7_w_a32(uint32_t fetchdat) { uint32_t templ, templ2; - int tempws, tempws2 = 0; + 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) { case 0x00: /*TEST w*/ - case 0x08: + case 0x08: src = getword(); if (cpu_state.abrt) return 1; setznp16(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -379,11 +376,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); @@ -394,8 +395,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; @@ -404,8 +405,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; @@ -420,6 +421,7 @@ static int opF7_w_a32(uint32_t fetchdat) } else { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); x86_int(0); return 1; } @@ -446,7 +448,6 @@ static int opF7_w_a32(uint32_t fetchdat) break; default: - pclog("Bad F7 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -458,12 +459,14 @@ 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) { case 0x00: /*TEST l*/ - case 0x08: + case 0x08: src = getlong(); if (cpu_state.abrt) return 1; setznp32(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -471,11 +474,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); @@ -486,8 +493,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; @@ -496,8 +503,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; @@ -517,7 +524,6 @@ static int opF7_l_a16(uint32_t fetchdat) break; default: - pclog("Bad F7 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -528,12 +534,14 @@ 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) { case 0x00: /*TEST l*/ - case 0x08: + case 0x08: src = getlong(); if (cpu_state.abrt) return 1; setznp32(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -541,11 +549,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); @@ -556,8 +568,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; @@ -566,8 +578,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; @@ -587,7 +599,6 @@ static int opF7_l_a32(uint32_t fetchdat) break; default: - pclog("Bad F7 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -596,12 +607,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--; @@ -621,8 +632,8 @@ static int opLOCK(uint32_t fetchdat) fetchdat = fastreadl(cs + cpu_state.pc); if (cpu_state.abrt) return 0; cpu_state.pc++; - - ILLEGAL_ON((fetchdat & 0xff) == 0x90); + + ILLEGAL_ON((fetchdat & 0xff) == 0x90); CLOCK_CYCLES(4); PREFETCH_PREFIX(); @@ -637,6 +648,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; @@ -656,6 +668,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; @@ -676,6 +689,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; @@ -695,6 +709,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; @@ -712,9 +727,8 @@ 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); return 1; } @@ -755,7 +769,7 @@ static int opLOADALL(uint32_t fetchdat) return 1; } msw = (msw & 1) | readmemw(0, 0x806); - flags = (readmemw(0, 0x818) & 0xffd5) | 2; + cpu_state.flags = (readmemw(0, 0x818) & 0xffd5) | 2; flags_extract(); tr.seg = readmemw(0, 0x816); cpu_state.pc = readmemw(0, 0x81A); @@ -773,22 +787,22 @@ 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); - if (_ss.base == 0 && _ss.limit_low == 0 && _ss.limit_high == 0xffffffff) + 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); - if (_ds.base == 0 && _ds.limit_low == 0 && _ds.limit_high == 0xffffffff) + 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; @@ -829,8 +843,11 @@ 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; @@ -839,19 +856,19 @@ static void loadall_load_segment(uint32_t addr, x86seg *s) set_segment_limit(s, segdat3); - if (s == &_ds) + 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; + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; } - if (s == &_ss) + 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; + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; } } @@ -860,8 +877,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); @@ -887,14 +904,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; @@ -915,7 +933,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); @@ -928,7 +946,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); @@ -939,3 +957,16 @@ static int opWRMSR(uint32_t fetchdat) return 1; } +static int opRSM(uint32_t fetchdat) +{ + if(!in_smm) + { + leave_smm(); + if(smi_latched) enter_smm(); + CPU_BLOCK_END(); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} \ No newline at end of file diff --git a/src/cpu/x86_ops_mmx.h b/src/cpu/x86_ops_mmx.h index 1af186d0b..107710f77 100644 --- a/src/cpu/x86_ops_mmx.h +++ b/src/cpu/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,7 +32,7 @@ static int opEMMS(uint32_t fetchdat) { - if (!cpu_hasMMX) + if (!cpu_has_feature(CPU_FEATURE_MMX)) { cpu_state.pc = cpu_state.oldpc; x86illegal(); diff --git a/src/cpu/x86_ops_mmx_arith.h b/src/cpu/x86_ops_mmx_arith.h index 302a44eaa..e8e1f31e5 100644 --- a/src/cpu/x86_ops_mmx_arith.h +++ b/src/cpu/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]; @@ -320,7 +321,8 @@ static int opPMULLW_a32(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]; @@ -348,7 +350,8 @@ static int opPMULHW_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] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; @@ -375,7 +378,8 @@ static int opPMULHW_a32(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] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; diff --git a/src/cpu/x86_ops_mmx_cmp.h b/src/cpu/x86_ops_mmx_cmp.h index eb401b83f..0fee95923 100644 --- a/src/cpu/x86_ops_mmx_cmp.h +++ b/src/cpu/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/cpu/x86_ops_mmx_mov.h b/src/cpu/x86_ops_mmx_mov.h index d96df747b..a742941ea 100644 --- a/src/cpu/x86_ops_mmx_mov.h +++ b/src/cpu/x86_ops_mmx_mov.h @@ -13,6 +13,7 @@ static int opMOVD_l_mm_a16(uint32_t fetchdat) { 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; @@ -36,6 +37,7 @@ static int opMOVD_l_mm_a32(uint32_t fetchdat) { 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; @@ -57,7 +59,8 @@ static int opMOVD_mm_l_a16(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(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); } @@ -75,7 +78,8 @@ static int opMOVD_mm_l_a32(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(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 +100,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); @@ -115,7 +120,8 @@ static int opMOVQ_q_mm_a32(uint32_t fetchdat) else { 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,7 +141,8 @@ static int opMOVQ_mm_q_a16(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(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); } @@ -153,7 +160,8 @@ static int opMOVQ_mm_q_a32(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(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/cpu/x86_ops_mmx_pack.h b/src/cpu/x86_ops_mmx_pack.h index 50b813cb3..170aa0e42 100644 --- a/src/cpu/x86_ops_mmx_pack.h +++ b/src/cpu/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; @@ -33,6 +34,7 @@ static int opPUNPCKLDQ_a32(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; diff --git a/src/cpu/x86_ops_mmx_shift.h b/src/cpu/x86_ops_mmx_shift.h index 429347598..edfe16276 100644 --- a/src/cpu/x86_ops_mmx_shift.h +++ b/src/cpu/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); \ } @@ -52,7 +53,7 @@ static int opPSxxW_imm(uint32_t fetchdat) } break; default: - pclog("Bad PSxxW (0F 71) instruction %02X\n", op); + x386_dynarec_log("Bad PSxxW (0F 71) instruction %02X\n", op); cpu_state.pc = cpu_state.oldpc; x86illegal(); return 0; @@ -223,7 +224,7 @@ static int opPSxxD_imm(uint32_t fetchdat) } break; default: - pclog("Bad PSxxD (0F 72) instruction %02X\n", op); + x386_dynarec_log("Bad PSxxD (0F 72) instruction %02X\n", op); cpu_state.pc = cpu_state.oldpc; x86illegal(); return 0; @@ -375,7 +376,7 @@ static int opPSxxQ_imm(uint32_t fetchdat) cpu_state.MM[reg].q <<= shift; break; default: - pclog("Bad PSxxQ (0F 73) instruction %02X\n", op); + x386_dynarec_log("Bad PSxxQ (0F 73) instruction %02X\n", op); cpu_state.pc = cpu_state.oldpc; x86illegal(); return 0; diff --git a/src/cpu/x86_ops_mov.h b/src/cpu/x86_ops_mov.h index 1eadee54f..cf9bb82c0 100644 --- a/src/cpu/x86_ops_mov.h +++ b/src/cpu/x86_ops_mov.h @@ -181,9 +181,9 @@ static int opMOV_b_imm_a16(uint32_t fetchdat) { uint8_t temp; fetch_ea_16(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + 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); CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 3, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 0); @@ -193,9 +193,9 @@ static int opMOV_b_imm_a32(uint32_t fetchdat) { uint8_t temp; fetch_ea_32(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getbyte(); if (cpu_state.abrt) return 1; - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); seteab(temp); CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 3, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 1); @@ -206,9 +206,9 @@ static int opMOV_w_imm_a16(uint32_t fetchdat) { uint16_t temp; fetch_ea_16(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getword(); if (cpu_state.abrt) return 1; - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); seteaw(temp); CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 4, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 0); @@ -218,9 +218,9 @@ static int opMOV_w_imm_a32(uint32_t fetchdat) { uint16_t temp; fetch_ea_32(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getword(); if (cpu_state.abrt) return 1; - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); seteaw(temp); CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 4, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 1); @@ -230,9 +230,9 @@ static int opMOV_l_imm_a16(uint32_t fetchdat) { uint32_t temp; fetch_ea_16(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getlong(); if (cpu_state.abrt) return 1; - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); seteal(temp); CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 6, rmdat, 0,0,0,(cpu_mod == 3) ? 1:0, 0); @@ -242,9 +242,9 @@ static int opMOV_l_imm_a32(uint32_t fetchdat) { uint32_t temp; fetch_ea_32(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getlong(); if (cpu_state.abrt) return 1; - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); seteal(temp); CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 6, rmdat, 0,0,0,(cpu_mod == 3) ? 1:0, 1); @@ -256,6 +256,7 @@ static int opMOV_AL_a16(uint32_t fetchdat) { uint8_t temp; uint16_t addr = getwordf(); + 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; @@ -267,6 +268,7 @@ static int opMOV_AL_a32(uint32_t fetchdat) { uint8_t temp; uint32_t addr = getlong(); + 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; @@ -278,7 +280,8 @@ static int opMOV_AX_a16(uint32_t fetchdat) { uint16_t temp; uint16_t addr = getwordf(); - CHECK_READ(cpu_state.ea_seg, addr, addr + 1); + 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); @@ -289,7 +292,8 @@ static int opMOV_AX_a32(uint32_t fetchdat) { uint16_t temp; uint32_t addr = getlong(); - CHECK_READ(cpu_state.ea_seg, addr, addr + 1); + 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); @@ -300,7 +304,8 @@ static int opMOV_EAX_a16(uint32_t fetchdat) { uint32_t temp; uint16_t addr = getwordf(); - CHECK_READ(cpu_state.ea_seg, addr, addr + 3); + 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); @@ -311,7 +316,8 @@ static int opMOV_EAX_a32(uint32_t fetchdat) { uint32_t temp; uint32_t addr = getlong(); - CHECK_READ(cpu_state.ea_seg, addr, addr + 3); + 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); @@ -322,7 +328,8 @@ static int opMOV_EAX_a32(uint32_t fetchdat) static int opMOV_a16_AL(uint32_t fetchdat) { uint16_t addr = getwordf(); - CHECK_WRITE(cpu_state.ea_seg, addr, addr); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr); writememb(cpu_state.ea_seg->base, addr, AL); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); @@ -331,7 +338,8 @@ static int opMOV_a16_AL(uint32_t fetchdat) static int opMOV_a32_AL(uint32_t fetchdat) { uint32_t addr = getlong(); - CHECK_WRITE(cpu_state.ea_seg, addr, addr); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr); writememb(cpu_state.ea_seg->base, addr, AL); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); @@ -340,7 +348,8 @@ static int opMOV_a32_AL(uint32_t fetchdat) static int opMOV_a16_AX(uint32_t fetchdat) { uint16_t addr = getwordf(); - CHECK_WRITE(cpu_state.ea_seg, addr, addr + 1); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 1); writememw(cpu_state.ea_seg->base, addr, AX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); @@ -349,7 +358,8 @@ 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; - CHECK_WRITE(cpu_state.ea_seg, addr, addr + 1); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 1); writememw(cpu_state.ea_seg->base, addr, AX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); @@ -358,7 +368,8 @@ static int opMOV_a32_AX(uint32_t fetchdat) static int opMOV_a16_EAX(uint32_t fetchdat) { uint16_t addr = getwordf(); - CHECK_WRITE(cpu_state.ea_seg, addr, addr + 3); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 3); writememl(cpu_state.ea_seg->base, addr, EAX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0); @@ -367,7 +378,8 @@ 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; - CHECK_WRITE(cpu_state.ea_seg, addr, addr + 3); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 3); writememl(cpu_state.ea_seg->base, addr, EAX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 5, -1, 0,0,0,1, 1); @@ -378,8 +390,8 @@ static int opMOV_a32_EAX(uint32_t fetchdat) static int opLEA_w_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - /* ILLEGAL_ON(cpu_mod == 3); */ - cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? (cpu_state.last_ea & 0xffff) : cpu_state.eaaddr; + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); return 0; @@ -387,8 +399,8 @@ static int opLEA_w_a16(uint32_t fetchdat) static int opLEA_w_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - /* ILLEGAL_ON(cpu_mod == 3); */ - cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? (cpu_state.last_ea & 0xffff) : cpu_state.eaaddr; + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); return 0; @@ -397,8 +409,8 @@ static int opLEA_w_a32(uint32_t fetchdat) static int opLEA_l_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - /* ILLEGAL_ON(cpu_mod == 3); */ - cpu_state.regs[cpu_reg].l = ((cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr) & 0xffff; + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].l = cpu_state.eaaddr & 0xffff; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); return 0; @@ -406,8 +418,8 @@ static int opLEA_l_a16(uint32_t fetchdat) static int opLEA_l_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - /* ILLEGAL_ON(cpu_mod == 3); */ - cpu_state.regs[cpu_reg].l = (cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr; + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].l = cpu_state.eaaddr; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); return 0; @@ -419,9 +431,9 @@ static int opXLAT_a16(uint32_t fetchdat) { uint32_t addr = (BX + AL)&0xFFFF; uint8_t temp; - cpu_state.last_ea = addr; - temp = readmemb(cpu_state.ea_seg->base, addr); - if (cpu_state.abrt) return 1; + + 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); @@ -431,9 +443,9 @@ static int opXLAT_a32(uint32_t fetchdat) { uint32_t addr = EBX + AL; uint8_t temp; - cpu_state.last_ea = addr; - temp = readmemb(cpu_state.ea_seg->base, addr); - if (cpu_state.abrt) return 1; + + 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); @@ -451,7 +463,7 @@ static int opMOV_b_r_a16(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(getr8(cpu_reg)); CLOCK_CYCLES(is486 ? 1 : 2); PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 0); @@ -469,7 +481,7 @@ static int opMOV_b_r_a32(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(getr8(cpu_reg)); CLOCK_CYCLES(is486 ? 1 : 2); PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 1); @@ -487,7 +499,7 @@ static int opMOV_w_r_a16(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.regs[cpu_reg].w); CLOCK_CYCLES(is486 ? 1 : 2); PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 0); @@ -505,7 +517,7 @@ static int opMOV_w_r_a32(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.regs[cpu_reg].w); CLOCK_CYCLES(is486 ? 1 : 2); PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 1); @@ -523,7 +535,7 @@ static int opMOV_l_r_a16(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(cpu_state.regs[cpu_reg].l); CLOCK_CYCLES(is486 ? 1 : 2); PREFETCH_RUN(2, 2, rmdat, 0,0,0,1, 0); @@ -541,7 +553,7 @@ static int opMOV_l_r_a32(uint32_t fetchdat) } else { - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(cpu_state.regs[cpu_reg].l); CLOCK_CYCLES(is486 ? 1 : 2); PREFETCH_RUN(2, 2, rmdat, 0,0,0,1, 1); @@ -561,6 +573,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); @@ -581,6 +594,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); @@ -601,6 +615,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; @@ -621,6 +636,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; @@ -641,6 +657,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; @@ -661,6 +678,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; @@ -670,6 +688,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) return 0; } +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) #define opCMOV(condition) \ static int opCMOV ## condition ## _w_a16(uint32_t fetchdat) \ { \ @@ -681,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; \ @@ -699,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; \ @@ -717,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; \ @@ -736,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; \ } \ @@ -760,3 +783,4 @@ opCMOV(L) opCMOV(NL) opCMOV(LE) opCMOV(NLE) +#endif diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index 3a522a652..becb0e095 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -1,8 +1,8 @@ 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"); + x386_dynarec_log("Can't load from CRx\n"); x86gpf(NULL, 0); return 1; } @@ -21,13 +21,13 @@ 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; } default: - pclog("Bad read of CR%i %i\n",rmdat&7,cpu_reg); + x386_dynarec_log("Bad read of CR%i %i\n",rmdat&7,cpu_reg); cpu_state.pc = cpu_state.oldpc; x86illegal(); break; @@ -38,9 +38,9 @@ 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"); + x386_dynarec_log("Can't load from CRx\n"); x86gpf(NULL, 0); return 1; } @@ -59,13 +59,13 @@ 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; } default: - pclog("Bad read of CR%i %i\n",rmdat&7,cpu_reg); + x386_dynarec_log("Bad read of CR%i %i\n",rmdat&7,cpu_reg); cpu_state.pc = cpu_state.oldpc; x86illegal(); break; @@ -77,9 +77,9 @@ 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"); + x386_dynarec_log("Can't load from DRx\n"); x86gpf(NULL, 0); return 1; } @@ -91,9 +91,9 @@ 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"); + x386_dynarec_log("Can't load from DRx\n"); x86gpf(NULL, 0); return 1; } @@ -108,9 +108,9 @@ 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"); + x386_dynarec_log("Can't load CRx\n"); x86gpf(NULL,0); return 1; } @@ -127,7 +127,9 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) mmu_perm=4; if (is486 && !(cr0 & (1 << 30))) cpu_cache_int_enabled = 1; - else + else if (isibmcpu) + cpu_cache_int_enabled = 1; + else cpu_cache_int_enabled = 0; if (is486 && ((cr0 ^ old_cr0) & (1 << 30))) cpu_update_waitstates(); @@ -144,14 +146,14 @@ 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; } default: - pclog("Bad load CR%i\n", cpu_reg); + x386_dynarec_log("Bad load CR%i\n", cpu_reg); cpu_state.pc = cpu_state.oldpc; x86illegal(); break; @@ -164,9 +166,9 @@ 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"); + x386_dynarec_log("Can't load CRx\n"); x86gpf(NULL,0); return 1; } @@ -200,14 +202,14 @@ 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; } default: - pclog("Bad load CR%i\n", cpu_reg); + x386_dynarec_log("Bad load CR%i\n", cpu_reg); cpu_state.pc = cpu_state.oldpc; x86illegal(); break; @@ -219,9 +221,9 @@ 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"); + x386_dynarec_log("Can't load DRx\n"); x86gpf(NULL, 0); return 1; } @@ -233,9 +235,9 @@ 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"); + x386_dynarec_log("Can't load DRx\n"); x86gpf(NULL, 0); return 1; } @@ -248,9 +250,9 @@ 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"); + x386_dynarec_log("Can't load from TRx\n"); x86gpf(NULL, 0); return 1; } @@ -262,9 +264,9 @@ 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"); + x386_dynarec_log("Can't load from TRx\n"); x86gpf(NULL, 0); return 1; } @@ -277,9 +279,9 @@ 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"); + x386_dynarec_log("Can't load TRx\n"); x86gpf(NULL, 0); return 1; } @@ -290,9 +292,9 @@ 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"); + x386_dynarec_log("Can't load TRx\n"); x86gpf(NULL, 0); return 1; } diff --git a/src/cpu/x86_ops_mov_seg.h b/src/cpu/x86_ops_mov_seg.h index 1e2f654b1..da7727143 100644 --- a/src/cpu/x86_ops_mov_seg.h +++ b/src/cpu/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/cpu/x86_ops_movx.h b/src/cpu/x86_ops_movx.h index 2175a63c3..2e4fa2001 100644 --- a/src/cpu/x86_ops_movx.h +++ b/src/cpu/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/cpu/x86_ops_msr.h b/src/cpu/x86_ops_msr.h index a73316745..2a8bdcf4c 100644 --- a/src/cpu/x86_ops_msr.h +++ b/src/cpu/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/cpu/x86_ops_mul.h b/src/cpu/x86_ops_mul.h index 98cf254cc..a96ce54a2 100644 --- a/src/cpu/x86_ops_mul.h +++ b/src/cpu/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,6 +94,8 @@ 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; @@ -93,8 +103,8 @@ static int opIMUL_w_ib_a16(uint32_t fetchdat) 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,6 +117,8 @@ 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; @@ -114,8 +126,8 @@ static int opIMUL_w_ib_a32(uint32_t fetchdat) 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/cpu/x86_ops_pmode.h b/src/cpu/x86_ops_pmode.h index 46e324322..cdf89d98d 100644 --- a/src/cpu/x86_ops_pmode.h +++ b/src/cpu/x86_ops_pmode.h @@ -4,7 +4,10 @@ static int opARPL_a16(uint32_t fetchdat) NOTRM fetch_ea_16(fetchdat); - /* pclog("ARPL_a16\n"); */ + /* x386_dynarec_log("ARPL_a16\n"); */ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp_seg = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); @@ -12,10 +15,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 +30,10 @@ static int opARPL_a32(uint32_t fetchdat) NOTRM fetch_ea_32(fetchdat); - /* pclog("ARPL_a32\n"); */ + /* x386_dynarec_log("ARPL_a32\n"); */ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp_seg = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); @@ -35,10 +41,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 +59,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 +73,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 +85,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 +111,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 +135,7 @@ opLAR(l_a32, fetch_ea_32, 1, 1) } \ if (valid) \ { \ - flags |= Z_FLAG; \ + cpu_state.flags |= Z_FLAG; \ cpl_override = 1; \ if (is32) \ { \ @@ -159,26 +169,32 @@ static int op0F00_common(uint32_t fetchdat, int ea32) uint16_t desc, sel; uint8_t access; - /* pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); */ + /* x386_dynarec_log("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"); + x386_dynarec_log("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); @@ -199,12 +215,14 @@ 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"); + x386_dynarec_log("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); @@ -228,9 +246,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); @@ -243,14 +263,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); @@ -261,13 +283,13 @@ 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; default: - pclog("Bad 0F 00 opcode %02X\n", rmdat & 0x38); + x386_dynarec_log("Bad 0F 00 opcode %02X\n", rmdat & 0x38); cpu_state.pc -= 3; x86illegal(); break; @@ -296,10 +318,12 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) { uint32_t base; uint16_t limit, tempw; - /* pclog("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); */ + /* x386_dynarec_log("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); */ 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) @@ -309,6 +333,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) @@ -318,16 +344,18 @@ 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"); + x386_dynarec_log("Invalid LGDT!\n"); x86gpf(NULL,0); break; } - /* pclog("LGDT %08X:%08X\n", easeg, eaaddr); */ + /* x386_dynarec_log("LGDT %08X:%08X\n", easeg, eaaddr); */ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); limit = geteaw(); base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - /* pclog(" %08X %04X\n", base, limit); */ + /* x386_dynarec_log(" %08X %04X\n", base, limit); */ gdt.limit = limit; gdt.base = base; if (!is32) gdt.base &= 0xffffff; @@ -335,16 +363,18 @@ 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"); + x386_dynarec_log("Invalid LIDT!\n"); x86gpf(NULL,0); break; } - /* pclog("LIDT %08X:%08X\n", easeg, eaaddr); */ + /* x386_dynarec_log("LIDT %08X:%08X\n", easeg, eaaddr); */ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); limit = geteaw(); base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - /* pclog(" %08X %04X\n", base, limit); */ + /* x386_dynarec_log(" %08X %04X\n", base, limit); */ idt.limit = limit; idt.base = base; if (!is32) idt.base &= 0xffffff; @@ -353,6 +383,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); @@ -360,12 +392,14 @@ 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"); + x386_dynarec_log("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) @@ -385,12 +419,13 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) 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"); + x386_dynarec_log("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); @@ -398,7 +433,7 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) } default: - pclog("Bad 0F 01 opcode %02X\n", rmdat & 0x38); + x386_dynarec_log("Bad 0F 01 opcode %02X\n", rmdat & 0x38); cpu_state.pc -= 3; x86illegal(); break; diff --git a/src/cpu/x86_ops_prefix.h b/src/cpu/x86_ops_prefix.h index 8265c19f1..8d191103d 100644 --- a/src/cpu/x86_ops_prefix.h +++ b/src/cpu/x86_ops_prefix.h @@ -63,26 +63,26 @@ static int op ## name ## _l_a32(uint32_t fetchdat) \ return normal_opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ } -op_seg(CS, _cs, x86_opcodes, x86_opcodes) -op_seg(DS, _ds, x86_opcodes, x86_opcodes) -op_seg(ES, _es, x86_opcodes, x86_opcodes) -op_seg(FS, _fs, x86_opcodes, x86_opcodes) -op_seg(GS, _gs, x86_opcodes, x86_opcodes) -op_seg(SS, _ss, x86_opcodes, x86_opcodes) +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, _cs, x86_opcodes_REPE, x86_opcodes) -op_seg(DS_REPE, _ds, x86_opcodes_REPE, x86_opcodes) -op_seg(ES_REPE, _es, x86_opcodes_REPE, x86_opcodes) -op_seg(FS_REPE, _fs, x86_opcodes_REPE, x86_opcodes) -op_seg(GS_REPE, _gs, x86_opcodes_REPE, x86_opcodes) -op_seg(SS_REPE, _ss, x86_opcodes_REPE, 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, _cs, x86_opcodes_REPNE, x86_opcodes) -op_seg(DS_REPNE, _ds, x86_opcodes_REPNE, x86_opcodes) -op_seg(ES_REPNE, _es, x86_opcodes_REPNE, x86_opcodes) -op_seg(FS_REPNE, _fs, x86_opcodes_REPNE, x86_opcodes) -op_seg(GS_REPNE, _gs, x86_opcodes_REPNE, x86_opcodes) -op_seg(SS_REPNE, _ss, x86_opcodes_REPNE, 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*/ { diff --git a/src/cpu/x86_ops_rep.h b/src/cpu/x86_ops_rep.h index 065695706..efbb088ef 100644 --- a/src/cpu/x86_ops_rep.h +++ b/src/cpu/x86_ops_rep.h @@ -1,5 +1,3 @@ -extern int trap; - #define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \ static int opREP_INSB_ ## size(uint32_t fetchdat) \ { \ @@ -9,11 +7,13 @@ static int opREP_INSB_ ## size(uint32_t fetchdat) { \ uint8_t temp; \ \ - check_io_perm(DX); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \ temp = inb(DX); \ writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) DEST_REG--; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ else DEST_REG++; \ CNT_REG--; \ cycles -= 15; \ @@ -36,12 +36,14 @@ static int opREP_INSW_ ## size(uint32_t fetchdat) { \ uint16_t temp; \ \ - check_io_perm(DX); \ - check_io_perm(DX+1); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ temp = inw(DX); \ - writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) DEST_REG -= 2; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ else DEST_REG += 2; \ CNT_REG--; \ cycles -= 15; \ @@ -64,14 +66,16 @@ static int opREP_INSL_ ## size(uint32_t fetchdat) { \ uint32_t temp; \ \ - check_io_perm(DX); \ - check_io_perm(DX+1); \ - check_io_perm(DX+2); \ - check_io_perm(DX+3); \ + 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); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ temp = inl(DX); \ - writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) DEST_REG -= 4; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ else DEST_REG += 4; \ CNT_REG--; \ cycles -= 15; \ @@ -93,10 +97,13 @@ static int opREP_OUTSB_ ## size(uint32_t fetchdat) \ if (CNT_REG > 0) \ { \ - uint8_t temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + uint8_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ check_io_perm(DX); \ outb(DX, temp); \ - if (flags & D_FLAG) SRC_REG--; \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ else SRC_REG++; \ CNT_REG--; \ cycles -= 14; \ @@ -117,11 +124,14 @@ static int opREP_OUTSW_ ## size(uint32_t fetchdat) \ if (CNT_REG > 0) \ { \ - uint16_t temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + 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 (flags & D_FLAG) SRC_REG -= 2; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ else SRC_REG += 2; \ CNT_REG--; \ cycles -= 14; \ @@ -142,13 +152,16 @@ static int opREP_OUTSL_ ## size(uint32_t fetchdat) \ if (CNT_REG > 0) \ { \ - uint32_t temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + uint32_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + 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 (flags & D_FLAG) SRC_REG -= 4; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ else SRC_REG += 4; \ CNT_REG--; \ cycles -= 14; \ @@ -170,15 +183,21 @@ static int opREP_MOVSB_ ## size(uint32_t fetchdat) 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(&_es, DEST_REG, DEST_REG); \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + 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; \ + writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ else { DEST_REG++; SRC_REG++; } \ CNT_REG--; \ cycles -= is486 ? 3 : 4; \ @@ -203,15 +222,21 @@ static int opREP_MOVSW_ ## size(uint32_t fetchdat) 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(&_es, DEST_REG, DEST_REG); \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ 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; \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + 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; \ @@ -236,15 +261,21 @@ static int opREP_MOVSL_ ## size(uint32_t fetchdat) 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(&_es, DEST_REG, DEST_REG); \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ 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; \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + 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; \ @@ -271,11 +302,13 @@ static int opREP_STOSB_ ## size(uint32_t fetchdat) 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(&_es, DEST_REG, DEST_REG); \ - writememb(es, DEST_REG, AL); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) DEST_REG--; \ + 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; \ @@ -299,11 +332,13 @@ static int opREP_STOSW_ ## size(uint32_t fetchdat) 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(&_es, DEST_REG, DEST_REG+1); \ - writememw(es, DEST_REG, AX); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) DEST_REG -= 2; \ + 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; \ @@ -327,11 +362,13 @@ static int opREP_STOSL_ ## size(uint32_t fetchdat) 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(&_es, DEST_REG, DEST_REG+3); \ - writememl(es, DEST_REG, EAX); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) DEST_REG -= 4; \ + 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; \ @@ -356,10 +393,13 @@ static int opREP_LODSB_ ## size(uint32_t fetchdat) 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) \ { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ AL = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) SRC_REG--; \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ else SRC_REG++; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ @@ -383,10 +423,13 @@ static int opREP_LODSW_ ## size(uint32_t fetchdat) 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) \ { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ AX = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) SRC_REG -= 2; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ else SRC_REG += 2; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ @@ -410,10 +453,13 @@ static int opREP_LODSL_ ## size(uint32_t fetchdat) 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) \ { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) SRC_REG -= 4; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ else SRC_REG += 4; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ @@ -441,10 +487,15 @@ static int opREP_CMPSB_ ## size(uint32_t fetchdat) tempz = FV; \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ - uint8_t temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ - uint8_t temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1; \ + uint8_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ else { DEST_REG++; SRC_REG++; } \ CNT_REG--; \ cycles -= is486 ? 7 : 9; \ @@ -468,10 +519,15 @@ static int opREP_CMPSW_ ## size(uint32_t fetchdat) tempz = FV; \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ - uint16_t temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ - uint16_t temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1; \ + uint16_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + 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; \ @@ -495,10 +551,15 @@ static int opREP_CMPSL_ ## size(uint32_t fetchdat) tempz = FV; \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ - uint32_t temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ - uint32_t temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1; \ + uint32_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + 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; \ @@ -523,12 +584,15 @@ static int opREP_SCASB_ ## size(uint32_t fetchdat) 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)) \ { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ uint8_t temp = readmemb(es, DEST_REG); if (cpu_state.abrt) break;\ setsub8(AL, temp); \ tempz = (ZF_SET()) ? 1 : 0; \ - if (flags & D_FLAG) DEST_REG--; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ else DEST_REG++; \ CNT_REG--; \ cycles -= is486 ? 5 : 8; \ @@ -554,12 +618,15 @@ static int opREP_SCASW_ ## size(uint32_t fetchdat) 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)) \ { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ uint16_t temp = readmemw(es, DEST_REG); if (cpu_state.abrt) break;\ setsub16(AX, temp); \ tempz = (ZF_SET()) ? 1 : 0; \ - if (flags & D_FLAG) DEST_REG -= 2; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ else DEST_REG += 2; \ CNT_REG--; \ cycles -= is486 ? 5 : 8; \ @@ -585,12 +652,15 @@ static int opREP_SCASL_ ## size(uint32_t fetchdat) 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)) \ { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ uint32_t temp = readmeml(es, DEST_REG); if (cpu_state.abrt) break;\ setsub32(EAX, temp); \ tempz = (ZF_SET()) ? 1 : 0; \ - if (flags & D_FLAG) DEST_REG -= 4; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ else DEST_REG += 4; \ CNT_REG--; \ cycles -= is486 ? 5 : 8; \ diff --git a/src/cpu/x86_ops_ret.h b/src/cpu/x86_ops_ret.h index 95872588c..75419e6d8 100644 --- a/src/cpu/x86_ops_ret.h +++ b/src/cpu/x86_ops_ret.h @@ -1,10 +1,10 @@ #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; \ + oxpc = cpu_state.pc; \ if (stack32) \ { \ cpu_state.pc = readmemw(ss, ESP); \ @@ -21,12 +21,12 @@ 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; \ + oxpc = cpu_state.pc; \ if (stack32) \ { \ cpu_state.pc = readmeml(ss, ESP); \ @@ -94,7 +94,7 @@ static int opIRET_286(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(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 +108,19 @@ static int opIRET_286(uint32_t fetchdat) else { uint16_t new_cs; - oxpc = cpu_state.pc; + 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,7 +139,7 @@ static int opIRET(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { if (cr4 & CR4_VME) { @@ -151,17 +151,17 @@ static int opIRET(uint32_t fetchdat) if (cpu_state.abrt) return 1; - if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (eflags & VIP_FLAG))) + 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) - eflags |= VIF_FLAG; + cpu_state.eflags |= VIF_FLAG; else - eflags &= ~VIF_FLAG; - flags = (flags & 0x3300) | (new_flags & 0x4cd5) | 2; + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags = (cpu_state.flags & 0x3300) | (new_flags & 0x4cd5) | 2; loadcs(new_cs); cpu_state.pc = new_pc; @@ -184,19 +184,19 @@ static int opIRET(uint32_t fetchdat) else { uint16_t new_cs; - oxpc = cpu_state.pc; + oxpc = cpu_state.pc; if (stack32) { cpu_state.pc = readmemw(ss, ESP); new_cs = readmemw(ss, ESP + 2); - flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + 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)); - flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + cpu_state.flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; SP += 6; } loadcs(new_cs); @@ -216,7 +216,7 @@ static int opIRETD(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(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; @@ -230,21 +230,21 @@ static int opIRETD(uint32_t fetchdat) else { uint16_t new_cs; - oxpc = cpu_state.pc; + 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/cpu/x86_ops_set.h b/src/cpu/x86_ops_set.h index 0094b85d4..f6fd50e69 100644 --- a/src/cpu/x86_ops_set.h +++ b/src/cpu/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/cpu/x86_ops_shift.h b/src/cpu/x86_ops_shift.h index 5f0f57631..5cf44943d 100644 --- a/src/cpu/x86_ops_shift.h +++ b/src/cpu/x86_ops_shift.h @@ -6,36 +6,25 @@ 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; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 1) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 7)) & 1) cpu_state.flags |= V_FLAG; \ 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; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 0x80) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) cpu_state.flags |= V_FLAG; \ 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; \ + 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 +34,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 +51,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 +87,25 @@ 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; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 1) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 15)) & 1) cpu_state.flags |= V_FLAG; \ + 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; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 0x8000) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) cpu_state.flags |= V_FLAG; \ + 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 +115,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 +132,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 +168,22 @@ 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; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 1) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 31)) & 1) cpu_state.flags |= V_FLAG; \ + 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; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 0x80000000) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) cpu_state.flags |= V_FLAG; \ + 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 +196,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 +213,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 +248,8 @@ static int opC0_a16(uint32_t fetchdat) uint8_t temp, temp2 = 0; 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 +263,8 @@ static int opC0_a32(uint32_t fetchdat) uint8_t temp, temp2 = 0; 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 +278,8 @@ static int opC1_w_a16(uint32_t fetchdat) uint16_t temp, temp2 = 0; 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 +293,8 @@ static int opC1_w_a32(uint32_t fetchdat) uint16_t temp, temp2 = 0; 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 +308,8 @@ static int opC1_l_a16(uint32_t fetchdat) uint32_t temp, temp2 = 0; 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 +323,8 @@ static int opC1_l_a32(uint32_t fetchdat) uint32_t temp, temp2 = 0; 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 +339,8 @@ static int opD0_a16(uint32_t fetchdat) uint8_t temp, temp2 = 0; 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 +352,8 @@ static int opD0_a32(uint32_t fetchdat) uint8_t temp, temp2 = 0; 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 +365,8 @@ static int opD1_w_a16(uint32_t fetchdat) uint16_t temp, temp2 = 0; 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 +378,8 @@ static int opD1_w_a32(uint32_t fetchdat) uint16_t temp, temp2 = 0; 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 +391,8 @@ static int opD1_l_a16(uint32_t fetchdat) uint32_t temp, temp2 = 0; 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 +404,8 @@ static int opD1_l_a32(uint32_t fetchdat) uint32_t temp, temp2 = 0; 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 +418,8 @@ static int opD2_a16(uint32_t fetchdat) uint8_t temp, temp2 = 0; 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 +432,8 @@ static int opD2_a32(uint32_t fetchdat) uint8_t temp, temp2 = 0; 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 +446,8 @@ static int opD3_w_a16(uint32_t fetchdat) uint16_t temp, temp2 = 0; 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 +460,8 @@ static int opD3_w_a32(uint32_t fetchdat) uint16_t temp, temp2 = 0; 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 +474,8 @@ static int opD3_l_a16(uint32_t fetchdat) uint32_t temp, temp2 = 0; 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 +488,8 @@ static int opD3_l_a32(uint32_t fetchdat) uint32_t temp, temp2 = 0; 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); @@ -507,7 +510,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() \ @@ -520,7 +523,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; \ } @@ -536,7 +539,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() \ @@ -549,7 +552,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) \ @@ -558,6 +561,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() \ \ @@ -570,6 +575,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() \ \ @@ -582,6 +589,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() \ \ @@ -594,6 +603,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/cpu/x86_ops_stack.h b/src/cpu/x86_ops_stack.h index 621f602b3..20b0aa766 100644 --- a/src/cpu/x86_ops_stack.h +++ b/src/cpu/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) { @@ -274,7 +278,9 @@ static int opPOPL_a16(uint32_t fetchdat) temp = POP_L(); if (cpu_state.abrt) return 1; - fetch_ea_16(fetchdat); + 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) { @@ -469,10 +477,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) @@ -480,14 +488,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; @@ -500,14 +508,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/cpu/x86_ops_string.h b/src/cpu/x86_ops_string.h index 8c8ba6816..41e368cc7 100644 --- a/src/cpu/x86_ops_string.h +++ b/src/cpu/x86_ops_string.h @@ -1,8 +1,12 @@ 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--; } + if (cpu_state.flags & D_FLAG) { DI--; SI--; } else { DI++; SI++; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0); @@ -10,9 +14,13 @@ static int opMOVSB_a16(uint32_t fetchdat) } 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--; } + if (cpu_state.flags & D_FLAG) { EDI--; ESI--; } else { EDI++; ESI++; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1); @@ -21,9 +29,13 @@ 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; } + 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); @@ -31,9 +43,13 @@ static int opMOVSW_a16(uint32_t fetchdat) } 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; } + 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); @@ -42,9 +58,13 @@ 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; } + 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); @@ -52,9 +72,13 @@ static int opMOVSL_a16(uint32_t fetchdat) } 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; } + 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); @@ -64,10 +88,14 @@ 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--; } + 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); @@ -75,10 +103,14 @@ static int opCMPSB_a16(uint32_t fetchdat) } 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--; } + 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); @@ -87,10 +119,14 @@ 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; } + 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); @@ -98,10 +134,14 @@ static int opCMPSW_a16(uint32_t fetchdat) } 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; } + 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); @@ -110,10 +150,14 @@ 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; } + 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); @@ -121,10 +165,14 @@ static int opCMPSL_a16(uint32_t fetchdat) } 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; } + 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); @@ -133,8 +181,9 @@ 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--; + if (cpu_state.flags & D_FLAG) DI--; else DI++; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); @@ -142,8 +191,9 @@ static int opSTOSB_a16(uint32_t fetchdat) } 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--; + if (cpu_state.flags & D_FLAG) EDI--; else EDI++; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); @@ -152,8 +202,9 @@ 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; + if (cpu_state.flags & D_FLAG) DI -= 2; else DI += 2; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); @@ -161,8 +212,9 @@ static int opSTOSW_a16(uint32_t fetchdat) } 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; + if (cpu_state.flags & D_FLAG) EDI -= 2; else EDI += 2; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); @@ -171,8 +223,9 @@ 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; + if (cpu_state.flags & D_FLAG) DI -= 4; else DI += 4; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); @@ -180,8 +233,9 @@ static int opSTOSL_a16(uint32_t fetchdat) } 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; + if (cpu_state.flags & D_FLAG) EDI -= 4; else EDI += 4; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,1, 1); @@ -191,9 +245,12 @@ 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--; + if (cpu_state.flags & D_FLAG) SI--; else SI++; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); @@ -201,9 +258,12 @@ static int opLODSB_a16(uint32_t fetchdat) } 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--; + if (cpu_state.flags & D_FLAG) ESI--; else ESI++; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); @@ -212,9 +272,12 @@ 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; + if (cpu_state.flags & D_FLAG) SI -= 2; else SI += 2; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); @@ -222,9 +285,12 @@ static int opLODSW_a16(uint32_t fetchdat) } 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; + if (cpu_state.flags & D_FLAG) ESI -= 2; else ESI += 2; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); @@ -233,9 +299,12 @@ 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; + if (cpu_state.flags & D_FLAG) SI -= 4; else SI += 4; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0); @@ -243,9 +312,12 @@ static int opLODSL_a16(uint32_t fetchdat) } 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; + if (cpu_state.flags & D_FLAG) ESI -= 4; else ESI += 4; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 0,1,0,0, 1); @@ -255,9 +327,12 @@ 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--; + if (cpu_state.flags & D_FLAG) DI--; else DI++; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); @@ -265,9 +340,12 @@ static int opSCASB_a16(uint32_t fetchdat) } 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--; + if (cpu_state.flags & D_FLAG) EDI--; else EDI++; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); @@ -276,9 +354,12 @@ 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; + if (cpu_state.flags & D_FLAG) DI -= 2; else DI += 2; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); @@ -286,9 +367,12 @@ static int opSCASW_a16(uint32_t fetchdat) } 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; + if (cpu_state.flags & D_FLAG) EDI -= 2; else EDI += 2; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); @@ -297,9 +381,12 @@ 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; + if (cpu_state.flags & D_FLAG) DI -= 4; else DI += 4; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,0, 0); @@ -307,9 +394,12 @@ static int opSCASL_a16(uint32_t fetchdat) } 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; + if (cpu_state.flags & D_FLAG) EDI -= 4; else EDI += 4; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,0, 1); @@ -319,10 +409,12 @@ 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--; + if (cpu_state.flags & D_FLAG) DI--; else DI++; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); @@ -331,10 +423,12 @@ 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--; + if (cpu_state.flags & D_FLAG) EDI--; else EDI++; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); @@ -344,11 +438,13 @@ 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; + if (cpu_state.flags & D_FLAG) DI -= 2; else DI += 2; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); @@ -357,11 +453,13 @@ 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; + if (cpu_state.flags & D_FLAG) EDI -= 2; else EDI += 2; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); @@ -371,13 +469,15 @@ 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; + if (cpu_state.flags & D_FLAG) DI -= 4; else DI += 4; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 0,1,0,1, 0); @@ -386,13 +486,15 @@ 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; + if (cpu_state.flags & D_FLAG) EDI -= 4; else EDI += 4; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 0,1,0,1, 1); @@ -401,9 +503,12 @@ 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--; + if (cpu_state.flags & D_FLAG) SI--; else SI++; outb(DX, temp); CLOCK_CYCLES(14); @@ -412,9 +517,12 @@ 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--; + if (cpu_state.flags & D_FLAG) ESI--; else ESI++; outb(DX, temp); CLOCK_CYCLES(14); @@ -424,10 +532,13 @@ 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; + if (cpu_state.flags & D_FLAG) SI -= 2; else SI += 2; outw(DX, temp); CLOCK_CYCLES(14); @@ -436,10 +547,13 @@ 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; + if (cpu_state.flags & D_FLAG) ESI -= 2; else ESI += 2; outw(DX, temp); CLOCK_CYCLES(14); @@ -449,12 +563,15 @@ 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; + if (cpu_state.flags & D_FLAG) SI -= 4; else SI += 4; outl(EDX, temp); CLOCK_CYCLES(14); @@ -463,12 +580,15 @@ 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; + if (cpu_state.flags & D_FLAG) ESI -= 4; else ESI += 4; outl(EDX, temp); CLOCK_CYCLES(14); diff --git a/src/cpu/x86_ops_xchg.h b/src/cpu/x86_ops_xchg.h index 77191ae43..3880f70e7 100644 --- a/src/cpu/x86_ops_xchg.h +++ b/src/cpu/x86_ops_xchg.h @@ -2,6 +2,8 @@ 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); @@ -13,6 +15,8 @@ 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); @@ -25,6 +29,8 @@ 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; @@ -36,6 +42,8 @@ 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; @@ -48,6 +56,8 @@ 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; @@ -59,6 +69,8 @@ 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/cpu/x86seg.c b/src/cpu/x86seg.c index 3447a2628..d2dd5e8ad 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -8,7 +8,7 @@ * * x86 CPU segment emulation. * - * Version: @(#)x86seg.c 1.0.7 2018/04/29 + * Version: @(#)x86seg.c 1.0.9 2018/11/14 * * Authors: Sarah Walker, * Miran Grca, @@ -27,11 +27,12 @@ #include "../86box.h" #include "cpu.h" #include "../device.h" +#include "../timer.h" #include "../machine/machine.h" #include "../mem.h" #include "../nvr.h" #include "x86.h" -#include "386.h" +#include "x86_flags.h" #include "386_common.h" @@ -46,7 +47,7 @@ int dtimes = 0; int btimes = 0; uint32_t abrt_error; -int cgate16,cgate32; +int cgate16, cgate32; #define breaknullsegs 0 @@ -55,7 +56,6 @@ int intgatesize; void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); void taskswitch386(uint16_t seg, uint16_t *segdat); -int output; void pmodeint(int num, int soft); /*NOT PRESENT is INT 0B GPF is INT 0D*/ @@ -63,13 +63,11 @@ void pmodeint(int num, int soft); #ifdef ENABLE_X86SEG_LOG int x86seg_do_log = ENABLE_X86SEG_LOG; -#endif static void x86seg_log(const char *fmt, ...) { -#ifdef ENABLE_X86SEG_LOG va_list ap; if (x86seg_do_log) { @@ -77,19 +75,24 @@ x86seg_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define x86seg_log(fmt, ...) +#endif -void x86abort(const char *format, ...) +void x86abort(const char *fmt, ...) { va_list ap; - va_start(ap, format); - vfprintf(stdlog, format, ap); + + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); - fflush(stdlog); + nvr_save(); +#ifdef ENABLE_808X_LOG dumpregs(1); +#endif fflush(stdlog); exit(-1); } @@ -102,7 +105,7 @@ static void seg_reset(x86seg *s) s->limit = 0xFFFF; s->limit_low = 0; s->limit_high = 0xffff; - if(s == &_cs) + 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; @@ -119,19 +122,19 @@ static void seg_reset(x86seg *s) 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) { CS = oldcs; cpu_state.pc = cpu_state.oldpc; - _cs.access = (oldcpl << 5) | 0x80; + cpu_state.seg_cs.access = (oldcpl << 5) | 0x80; if (msw & 1) pmodeint(x86_abrt, 0); @@ -140,22 +143,22 @@ 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; + oxpc=cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); return; @@ -256,14 +259,14 @@ void do_seg_load(x86seg *s, uint16_t *segdat) s->limit_low = s->limit + 1; } - if (s == &_ds) + 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 == &_ss) + if (s == &cpu_state.seg_ss) { if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; @@ -330,11 +333,11 @@ void loadseg(uint16_t seg, x86seg *s) uint32_t addr; int dpl; - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { if (!(seg&~3)) { - if (s==&_ss) + if (s==&cpu_state.seg_ss) { x86ss(NULL,0); return; @@ -342,14 +345,18 @@ void loadseg(uint16_t seg, x86seg *s) s->seg=0; s->access = 0x80; s->base=-1; - if (s == &_ds) + if (s == &cpu_state.seg_ds) cpu_cur_status |= CPU_STATUS_NOTFLATDS; return; } addr=seg&~7; if (seg&4) { +#if 0 if (addr>=ldt.limit) +#else + if ((addr+7)>ldt.limit) +#endif { x86gpf("loadseg(): Bigger than LDT limit",seg&~3); return; @@ -358,7 +365,11 @@ void loadseg(uint16_t seg, x86seg *s) } else { +#if 0 if (addr>=gdt.limit) +#else + if ((addr+7)>gdt.limit) +#endif { x86gpf("loadseg(): Bigger than GDT limit",seg&~3); return; @@ -371,7 +382,7 @@ void loadseg(uint16_t seg, x86seg *s) segdat[2]=readmemw(0,addr+4); segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; dpl=(segdat[2]>>13)&3; - if (s==&_ss) + if (s==&cpu_state.seg_ss) { if (!(seg&~3)) { @@ -398,7 +409,7 @@ void loadseg(uint16_t seg, x86seg *s) } set_stack32((segdat[3] & 0x40) ? 1 : 0); } - else if (s!=&_cs) + else if (s!=&cpu_state.seg_cs) { x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); x86seg_log("Seg type %03X\n",segdat[2]&0x1F00); @@ -430,7 +441,7 @@ void loadseg(uint16_t seg, x86seg *s) do_seg_load(s, segdat); #ifndef CS_ACCESSED - if (s != &_cs) + if (s != &cpu_state.seg_cs) { #endif #ifdef SEL_ACCESSED @@ -443,9 +454,9 @@ void loadseg(uint16_t seg, x86seg *s) #endif s->checked = 0; #ifdef USE_DYNAREC - if (s == &_ds) + if (s == &cpu_state.seg_ds) codegen_flat_ds = 0; - if (s == &_ss) + if (s == &cpu_state.seg_ss) codegen_flat_ss = 0; #endif } @@ -454,25 +465,25 @@ void loadseg(uint16_t seg, x86seg *s) s->access = (3 << 5) | 2 | 0x80; s->base = seg << 4; s->seg = seg; - if (s == &_ss) - set_stack32(0); s->checked = 1; #ifdef USE_DYNAREC - if (s == &_ds) + if (s == &cpu_state.seg_ds) codegen_flat_ds = 0; - if (s == &_ss) + if (s == &cpu_state.seg_ss) codegen_flat_ss = 0; #endif + if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG)) + set_stack32(0); } - if (s == &_ds) + 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 == &_ss) + if (s == &cpu_state.seg_ss) { if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; @@ -490,7 +501,7 @@ void loadcs(uint16_t seg) uint16_t segdat[4]; uint32_t addr; x86seg_log("Load CS %04X\n",seg); - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { if (!(seg&~3)) { @@ -548,10 +559,10 @@ void loadcs(uint16_t seg) } 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(); - + #ifdef CS_ACCESSED cpl_override = 1; writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ @@ -575,24 +586,24 @@ 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 & 0xFFFF; - if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; - else _cs.access=(0<<5) | 2 | 0x80; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); } } -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; - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { if (!(seg&~3)) { @@ -660,7 +671,7 @@ 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(); cycles -= timing_jmp_pm; } @@ -756,8 +767,9 @@ 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(); + set_use32(segdat[3]&0x40); cpu_state.pc=newpc; @@ -778,11 +790,11 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) case 0x100: /*286 Task gate*/ case 0x900: /*386 Task gate*/ - 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; return; @@ -794,13 +806,13 @@ 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 | 0x80; - else _cs.access=(0<<5) | 2 | 0x80; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); cycles -= timing_jmp_rm; } @@ -884,7 +896,7 @@ void loadcscall(uint16_t seg) int csout = output; - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { if (csout) x86seg_log("Protected mode CS load! %04X\n",seg); if (!(seg&~3)) @@ -963,8 +975,9 @@ 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(); + if (csout) x86seg_log("Complete\n"); cycles -= timing_call_pm; } @@ -1079,7 +1092,11 @@ void loadcscall(uint16_t seg) addr=newss&~7; if (newss&4) { +#if 0 if (addr>=ldt.limit) +#else + if ((addr+7)>ldt.limit) +#endif { x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); x86ts(NULL,newss&~3); @@ -1089,7 +1106,11 @@ void loadcscall(uint16_t seg) } else { +#if 0 if (addr>=gdt.limit) +#else + if ((addr+7)>gdt.limit) +#endif { x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); x86ts(NULL,newss&~3); @@ -1125,7 +1146,7 @@ void loadcscall(uint16_t seg) if (stack32) ESP=newsp; else SP=newsp; - do_seg_load(&_ss, segdat2); + do_seg_load(&cpu_state.seg_ss, segdat2); x86seg_log("Set access 1\n"); @@ -1136,8 +1157,9 @@ 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(); + set_use32(segdat[3]&0x40); cpu_state.pc=newpc; @@ -1215,7 +1237,7 @@ void loadcscall(uint16_t seg) } 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(); set_use32(segdat[3]&0x40); cpu_state.pc=newpc; @@ -1250,13 +1272,13 @@ 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 | 0x80; - else _cs.access=(0<<5) | 2 | 0x80; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); } } @@ -1268,7 +1290,7 @@ void pmoderetf(int is32, uint16_t off) uint32_t addr, oaddr; uint16_t segdat[4],segdat2[4],seg,newss; uint32_t oldsp=ESP; - x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,eflags); + x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,cpu_state.eflags); if (is32) { newpc=POPL(); @@ -1366,8 +1388,8 @@ 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(); set_use32(segdat[3] & 0x40); @@ -1480,7 +1502,7 @@ void pmoderetf(int is32, uint16_t off) 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; @@ -1497,24 +1519,24 @@ 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(); 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); cycles -= timing_retf_pm_outer; } } void restore_stack() { - ss=oldss; _ss.limit=oldsslimit; + ss=oldss; cpu_state.seg_ss.limit=oldsslimit; } void pmodeint(int num, int soft) @@ -1528,7 +1550,7 @@ void pmodeint(int num, int soft) uint16_t seg = 0; int new_cpl; - if (eflags&VM_FLAG && IOPL!=3 && soft) + if (cpu_state.eflags&VM_FLAG && IOPL!=3 && soft) { x86seg_log("V86 banned int\n"); x86gpf(NULL,0); @@ -1627,7 +1649,7 @@ void pmodeint(int num, int soft) x86np("Int gate CS not present\n", segdat[1] & 0xfffc); return; } - if ((eflags&VM_FLAG) && DPL2) + if ((cpu_state.eflags&VM_FLAG) && DPL2) { x86gpf(NULL,segdat[1]&0xFFFC); return; @@ -1697,7 +1719,7 @@ void pmodeint(int num, int soft) set_stack32((segdat3[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; - do_seg_load(&_ss, segdat3); + do_seg_load(&cpu_state.seg_ss, segdat3); #ifdef CS_ACCESSED cpl_override = 1; @@ -1709,20 +1731,20 @@ void pmodeint(int num, int soft) cpl_override=1; if (type>=0x800) { - 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)); PUSHL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; } @@ -1730,12 +1752,12 @@ void pmodeint(int num, int soft) { PUSHW(oldss); PUSHW(oldsp); - PUSHW(flags); + PUSHW(cpu_state.flags); PUSHW(CS); PUSHW(cpu_state.pc); if (cpu_state.abrt) return; } cpl_override=0; - _cs.access=0 | 0x80; + cpu_state.seg_cs.access=0 | 0x80; cycles -= timing_int_pm_outer - timing_int_pm; break; } @@ -1750,20 +1772,20 @@ 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)); PUSHL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; } else { - PUSHW(flags); + PUSHW(cpu_state.flags); PUSHW(CS); PUSHW(cpu_state.pc); if (cpu_state.abrt) return; } @@ -1773,9 +1795,9 @@ 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); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); else cpu_state.pc=segdat[0]; @@ -1787,13 +1809,13 @@ 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; } - flags&=~(T_FLAG|NT_FLAG); + cpu_state.flags&=~(T_FLAG|NT_FLAG); cycles -= timing_int_pm; break; @@ -1852,14 +1874,14 @@ void pmodeiret(int is32) uint16_t seg; uint32_t addr, oaddr; uint32_t oldsp=ESP; - if (is386 && (eflags&VM_FLAG)) + if (is386 && (cpu_state.eflags&VM_FLAG)) { if (IOPL!=3) { x86gpf(NULL,0); return; } - oxpc=cpu_state.pc; + oxpc=cpu_state.pc; if (is32) { newpc=POPL(); @@ -1872,19 +1894,19 @@ void pmodeiret(int is32) seg=POPW(); 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; - _cs.access |= 0x80; + cpu_state.pc = newpc; + 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; + cpu_state.seg_cs.access |= 0x80; CS=seg; - flags=(flags&0x3000)|(tempflags&0xCFD5)|2; + cpu_state.flags=(cpu_state.flags&0x3000)|(tempflags&0xCFD5)|2; cycles -= timing_iret_rm; return; } - if (flags&NT_FLAG) + if (cpu_state.flags&NT_FLAG) { seg=readmemw(tr.base,0); addr=seg&~7; @@ -1912,7 +1934,7 @@ void pmodeiret(int is32) cpl_override=0; return; } - oxpc=cpu_state.pc; + oxpc=cpu_state.pc; flagmask=0xFFFF; if (CPL) flagmask&=~0x3000; if (IOPL>16; + cpu_state.eflags=tempflags>>16; cpu_cur_status |= CPU_STATUS_V86; - loadseg(segs[0],&_es); - do_seg_v86_init(&_es); - loadseg(segs[1],&_ds); - do_seg_v86_init(&_ds); + 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],&_fs); - do_seg_v86_init(&_fs); - loadseg(segs[3],&_gs); - do_seg_v86_init(&_gs); + 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); 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; - _cs.access=(3<<5) | 2 | 0x80; + cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - + 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; cpu_cur_status &= ~CPU_STATUS_USE32; - flags=(tempflags&0xFFD5)|2; + cpu_state.flags=(tempflags&0xFFD5)|2; cycles -= timing_iret_v86; return; } @@ -2039,8 +2061,8 @@ void pmodeiret(int is32) if ((seg&3) == CPL) { 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(); set_use32(segdat[3]&0x40); @@ -2128,7 +2150,7 @@ void pmodeiret(int is32) 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; @@ -2144,20 +2166,20 @@ 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(); 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; } void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) @@ -2204,12 +2226,12 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } if (cpu_state.abrt) return; - if (optype==IRET) flags&=~NT_FLAG; + if (optype==IRET) cpu_state.flags&=~NT_FLAG; 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); @@ -2275,8 +2297,8 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) flushmmucache(); cpu_state.pc=new_pc; - flags=new_flags; - eflags=new_flags>>16; + cpu_state.flags=new_flags; + cpu_state.eflags=new_flags>>16; cpu_386_flags_extract(); ldt.seg=new_ldt; @@ -2289,7 +2311,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); - if (eflags & VM_FLAG) + if (cpu_state.eflags & VM_FLAG) { loadcs(new_cs); set_use32(0); @@ -2352,7 +2374,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } CS=new_cs; - do_seg_load(&_cs, segdat2); + do_seg_load(&cpu_state.seg_cs, segdat2); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); set_use32(segdat2[3] & 0x40); cpu_cur_status &= ~CPU_STATUS_V86; @@ -2367,11 +2389,11 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) ESI=new_esi; EDI=new_edi; - loadseg(new_es,&_es); - loadseg(new_ss,&_ss); - loadseg(new_ds,&_ds); - loadseg(new_fs,&_fs); - loadseg(new_gs,&_gs); + loadseg(new_es,&cpu_state.seg_es); + loadseg(new_ss,&cpu_state.seg_ss); + loadseg(new_ds,&cpu_state.seg_ds); + loadseg(new_fs,&cpu_state.seg_fs); + loadseg(new_gs,&cpu_state.seg_gs); } else { @@ -2392,11 +2414,11 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } if (cpu_state.abrt) return; - if (optype==IRET) flags&=~NT_FLAG; + if (optype==IRET) cpu_state.flags&=~NT_FLAG; cpu_386_flags_rebuild(); writememw(tr.base,0x0E,cpu_state.pc); - writememw(tr.base,0x10,flags); + writememw(tr.base,0x10,cpu_state.flags); writememw(tr.base,0x12,AX); writememw(tr.base,0x14,CX); @@ -2453,7 +2475,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) msw |= 8; cpu_state.pc=new_pc; - flags=new_flags; + cpu_state.flags=new_flags; cpu_386_flags_extract(); ldt.seg=new_ldt; @@ -2525,7 +2547,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } CS=new_cs; - do_seg_load(&_cs, segdat2); + do_seg_load(&cpu_state.seg_cs, segdat2); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); set_use32(0); @@ -2538,13 +2560,13 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) ESI=new_esi | 0xFFFF0000; EDI=new_edi | 0xFFFF0000; - loadseg(new_es,&_es); - loadseg(new_ss,&_ss); - loadseg(new_ds,&_ds); + loadseg(new_es,&cpu_state.seg_es); + loadseg(new_ss,&cpu_state.seg_ss); + loadseg(new_ds,&cpu_state.seg_ds); if (is386) { - loadseg(0,&_fs); - loadseg(0,&_gs); + loadseg(0,&cpu_state.seg_fs); + loadseg(0,&cpu_state.seg_gs); } } diff --git a/src/cpu/x87.c b/src/cpu/x87.c index d85cd54ce..abc2f48a4 100644 --- a/src/cpu/x87.c +++ b/src/cpu/x87.c @@ -1,9 +1,11 @@ -#include +#include #include +#include #include #include #define fplog 0 #include +#define HAVE_STDARG_H #include "../86box.h" #include "cpu.h" #include "../mem.h" @@ -15,6 +17,26 @@ #include "386_common.h" +#ifdef ENABLE_FPU_LOG +int fpu_do_log = ENABLE_FPU_LOG; + + +static void +fpu_log(const char *fmt, ...) +{ + va_list ap; + + if (fpu_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define fpu_log(fmt, ...) +#endif + + uint16_t x87_gettag() { uint16_t ret = 0; @@ -43,35 +65,20 @@ void x87_settag(uint16_t new_tag) cpu_state.tag[7] = (new_tag >> 14) & 3; } + +#ifdef ENABLE_808X_LOG void x87_dumpregs() { if (cpu_state.ismmx) { - pclog("MM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\n", cpu_state.MM[0].q, cpu_state.MM[1].q, cpu_state.MM[2].q, cpu_state.MM[3].q); - pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", cpu_state.MM[4].q, cpu_state.MM[5].q, cpu_state.MM[6].q, cpu_state.MM[7].q); + fpu_log("MM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\n", cpu_state.MM[0].q, cpu_state.MM[1].q, cpu_state.MM[2].q, cpu_state.MM[3].q); + fpu_log("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", cpu_state.MM[4].q, cpu_state.MM[5].q, cpu_state.MM[6].q, cpu_state.MM[7].q); } 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(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]); + fpu_log("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]); + fpu_log("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()); -} - -void x87_print() -{ - if (cpu_state.ismmx) - { - pclog("\tMM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\t", cpu_state.MM[0].q, cpu_state.MM[1].q, cpu_state.MM[2].q, cpu_state.MM[3].q); - pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", cpu_state.MM[4].q, cpu_state.MM[5].q, cpu_state.MM[6].q, cpu_state.MM[7].q); - } - else - { - pclog("\tST(0)=%.20f\tST(1)=%.20f\tST(2)=%f\tST(3)=%f\t",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\tTOP=%i CR=%04X SR=%04X TAG=%04X\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], cpu_state.TOP, cpu_state.npxc, cpu_state.npxs, x87_gettag()); - } -} - -void x87_reset() -{ + fpu_log("Status = %04X Control = %04X Tag = %04X\n", cpu_state.npxs, cpu_state.npxc, x87_gettag()); } +#endif diff --git a/src/cpu/x87.h b/src/cpu/x87.h index 5e3db1960..6d2cb3ca9 100644 --- a/src/cpu/x87.h +++ b/src/cpu/x87.h @@ -1,6 +1,24 @@ uint32_t x87_pc_off,x87_op_off; uint16_t x87_pc_seg,x87_op_seg; +static __inline void x87_set_mmx() +{ + uint64_t *p; + cpu_state.TOP = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0; + cpu_state.ismmx = 1; +} + +static __inline void x87_emms() +{ + uint64_t *p; + p = (uint64_t *)cpu_state.tag; + *p = 0; + cpu_state.ismmx = 0; +} + + uint16_t x87_gettag(); void x87_settag(uint16_t new_tag); diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index d1fd0b464..bf54afa40 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -1,42 +1,24 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * x87 FPU instructions core. * - * Version: @(#)x87_ops.h 1.0.5 2018/05/05 + * Version: @(#)x87_ops.h 1.0.8 2019/06/11 * * Authors: Fred N. van Kempen, * Sarah Walker, * leilei, * Miran Grca, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 leilei. - * Copyright 2016-2018 Miran Grca. - * - * 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. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 leilei. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #include #include @@ -44,7 +26,13 @@ # include #endif -#define fplog 0 +#ifdef ENABLE_FPU_LOG +extern void fpu_log(const char *fmt, ...); +#else +#ifndef fpu_log +#define fpu_log(fmt, ...) +#endif +#endif static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}; @@ -57,41 +45,47 @@ static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZ #define STATUS_ZERODIVIDE 4 +#ifdef FPU_8087 #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); \ + fpu_log("FPU : divide by zero\n"); \ + if (!(cpu_state.npxc & 0x80)) { \ + cpu_state.npxs |= 0x80; \ + nmi = 1; \ + } \ + return 1; \ } \ - return 1; \ } \ else \ dst = src1 / (double)src2; \ } while (0) +#else +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + fpu_log("FPU : divide by zero\n"); \ + picint(1 << 13); \ + return 1; \ + } \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) +#endif -static __inline void x87_set_mmx() -{ - uint64_t *p; - cpu_state.TOP = 0; - p = (uint64_t *)cpu_state.tag; - *p = 0; - cpu_state.ismmx = 1; -} - -static __inline void x87_emms() -{ - uint64_t *p; - p = (uint64_t *)cpu_state.tag; - *p = 0x0303030303030303ll; - cpu_state.ismmx = 0; -} - static __inline void x87_checkexceptions() { } @@ -280,44 +274,24 @@ static __inline void x87_stmmx(MMX_REG r) writememw(easeg, cpu_state.eaaddr + 8, 0xffff); } +#include + static __inline uint16_t x87_compare(double a, double b) { -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32 +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 uint32_t result; + double ea = a, eb = b; + const uint64_t ia = 0x3fec1a6ff866a936ull; + const uint64_t ib = 0x3fec1a6ff866a938ull; - if (!is386) - { - if (((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) - { - /* pclog("Comparing infinity\n"); */ -#ifndef _MSC_VER - __asm volatile ("" : : : "memory"); - - __asm( - "fldl %2\n" - "fldl %1\n" - "fclex\n" - "fcompp\n" - "fnstsw %0\n" - : "=m" (result) - : "m" (a), "m" (a) - ); -#else - _ReadWriteBarrier(); - __asm - { - fld a - fld a - fclex - fcompp - fnstsw result - } -#endif + /* Hack to make CHKCOP happy. */ + if (!memcmp(&ea, &ia, 8) && !memcmp(&eb, &ib, 8)) + return C3; + + if (!is386 && !(cpu_state.npxc & 0x1000) && + ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + eb = ea; - return result & (C0|C2|C3); - } - } - #ifndef _MSC_VER /* Memory barrier, to force GCC to write to the input parameters * before the compare rather than after */ @@ -330,14 +304,14 @@ static __inline uint16_t x87_compare(double a, double b) "fcompp\n" "fnstsw %0\n" : "=m" (result) - : "m" (a), "m" (b) + : "m" (ea), "m" (eb) ); #else _ReadWriteBarrier(); _asm { - fld b - fld a + fld eb + fld ea fclex fcompp fnstsw result @@ -348,44 +322,33 @@ static __inline uint16_t x87_compare(double a, double b) #else /* Generic C version is known to give incorrect results in some * situations, eg comparison of infinity (Unreal) */ - uint32_t out = 0; + uint32_t result = 0; + double ea = a, eb = b; - if (is386) - { - if (((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) - { - result |= C3; - return result; - } + if (!is386 && !(cpu_state.npxc & 0x1000) && + ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + eb = ea; - if (a == b) - result |= C3; - else if (a < b) - result |= C0; - } - else - { - if (a == b) - result |= C3; - else if (a < b) - result |= C0; - } + if (ea == eb) + result |= C3; + else if (ea < eb) + result |= C0; return result; #endif } -static __inline uint16_t x87_ucompare(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 +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 || defined __amd64__ uint32_t result; #ifndef _MSC_VER /* Memory barrier, to force GCC to write to the input parameters * before the compare rather than after */ - __asm volatile ("" : : : "memory"); + asm volatile ("" : : : "memory"); - __asm( + asm( "fldl %2\n" "fldl %1\n" "fclex\n" @@ -433,6 +396,11 @@ typedef union uint64_t i; } x87_td; +#ifdef FPU_8087 +#define FP_ENTER() { \ + fpucount++; \ + } +#else #define FP_ENTER() do \ { \ if (cr0 & 0xc) \ @@ -442,11 +410,13 @@ typedef union } \ fpucount++; \ } while (0) +#endif #include "x87_ops_arith.h" #include "x87_ops_misc.h" #include "x87_ops_loadstore.h" +#ifndef FPU_8087 static int op_nofpu_a16(uint32_t fetchdat) { if (cr0 & 0xc) @@ -473,7 +443,16 @@ static int op_nofpu_a32(uint32_t fetchdat) return 0; } } +#endif +#ifdef FPU_8087 +static int FPU_ILLEGAL_a16(uint32_t fetchdat) +{ + geteaw(); + wait(timing_rr, 0); + return 0; +} +#else static int FPU_ILLEGAL_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); @@ -489,8 +468,261 @@ static int FPU_ILLEGAL_a32(uint32_t fetchdat) PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); return 0; } +#endif #define ILLEGAL_a16 FPU_ILLEGAL_a16 + +#ifdef FPU_8087 +const OpFn OP_TABLE(fpu_8087_d8)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +const OpFn OP_TABLE(fpu_8087_d9)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, ILLEGAL_a16, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, ILLEGAL_a16, opFRNDINT, opFSCALE, ILLEGAL_a16, ILLEGAL_a16 +}; + +const OpFn OP_TABLE(fpu_8087_da)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_db)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFI, opFI, opFCLEX, opFINIT, ILLEGAL_a16, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_dc)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, ILLEGAL_a16, ILLEGAL_a16, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_8087_dd)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_de)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_8087_df)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +#else #define ILLEGAL_a32 FPU_ILLEGAL_a32 const OpFn OP_TABLE(fpu_d8_a16)[32] = @@ -818,6 +1050,7 @@ const OpFn OP_TABLE(fpu_da_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) const OpFn OP_TABLE(fpu_686_da_a16)[256] = { opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, @@ -894,6 +1127,7 @@ const OpFn OP_TABLE(fpu_686_da_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#endif const OpFn OP_TABLE(fpu_287_db_a16)[256] = { @@ -1049,6 +1283,7 @@ const OpFn OP_TABLE(fpu_db_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) const OpFn OP_TABLE(fpu_686_db_a16)[256] = { opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, @@ -1125,6 +1360,7 @@ const OpFn OP_TABLE(fpu_686_db_a32)[256] = opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#endif const OpFn OP_TABLE(fpu_287_dc_a16)[32] = { @@ -1620,6 +1856,7 @@ const OpFn OP_TABLE(fpu_df_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) const OpFn OP_TABLE(fpu_686_df_a16)[256] = { opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, @@ -1696,6 +1933,7 @@ const OpFn OP_TABLE(fpu_686_df_a32)[256] = opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#endif const OpFn OP_TABLE(nofpu_a16)[256] = { @@ -1773,3 +2011,6 @@ const OpFn OP_TABLE(nofpu_a32)[256] = op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, }; +#endif + +#undef ILLEGAL diff --git a/src/cpu/x87_ops_arith.h b/src/cpu/x87_ops_arith.h index f53ad9213..720a5c469 100644 --- a/src/cpu/x87_ops_arith.h +++ b/src/cpu/x87_ops_arith.h @@ -4,13 +4,14 @@ 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; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(8); \ return 0; \ } \ @@ -19,6 +20,7 @@ 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); \ @@ -30,6 +32,7 @@ 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); \ @@ -42,9 +45,10 @@ 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; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(73); \ return 0; \ } \ @@ -53,9 +57,10 @@ 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; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(73); \ return 0; \ } \ @@ -64,6 +69,7 @@ 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; \ @@ -75,9 +81,10 @@ 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; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(8); \ return 0; \ } \ @@ -86,23 +93,32 @@ 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; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(8); \ return 0; \ } opFPU(s, x87_ts, 16, t.i, geteal, t.s) +#ifndef FPU_8087 opFPU(s, x87_ts, 32, t.i, geteal, t.s) +#endif opFPU(d, x87_td, 16, t.i, geteaq, t.d) +#ifndef FPU_8087 opFPU(d, x87_td, 32, t.i, geteaq, t.d) +#endif opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t) +#ifndef FPU_8087 opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t) +#endif opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t) +#ifndef FPU_8087 opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t) +#endif @@ -111,7 +127,6 @@ static int opFADD(uint32_t fetchdat) { FP_ENTER(); 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); @@ -121,7 +136,6 @@ static int opFADDr(uint32_t fetchdat) { FP_ENTER(); 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); @@ -131,7 +145,6 @@ static int opFADDP(uint32_t fetchdat) { FP_ENTER(); 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; x87_pop(); @@ -143,7 +156,6 @@ static int opFCOM(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FCOM\n"); 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; @@ -155,7 +167,6 @@ static int opFCOMP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FCOMP\n"); cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_compare(ST(0), ST(fetchdat & 7)); x87_pop(); @@ -168,7 +179,6 @@ static int opFCOMPP(uint32_t fetchdat) uint64_t *p, *q; FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FCOMPP\n"); cpu_state.npxs &= ~(C0|C2|C3); p = (uint64_t *)&ST(0); q = (uint64_t *)&ST(1); @@ -182,11 +192,11 @@ static int opFCOMPP(uint32_t fetchdat) CLOCK_CYCLES(4); return 0; } +#ifndef FPU_8087 static int opFUCOMPP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FUCOMPP\n", easeg, cpu_state.eaaddr); cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(1)); x87_pop(); @@ -195,15 +205,15 @@ static int opFUCOMPP(uint32_t fetchdat) return 0; } +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) static int opFCOMI(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FICOM\n"); flags_rebuild(); - flags &= ~(Z_FLAG | P_FLAG | C_FLAG); - if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; - else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + 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(4); return 0; } @@ -211,21 +221,21 @@ static int opFCOMIP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FICOMP\n"); flags_rebuild(); - flags &= ~(Z_FLAG | P_FLAG | C_FLAG); - if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; - else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + 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); return 0; } +#endif +#endif static int opFDIV(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FDIV\n"); x87_div(ST(0), ST(0), ST(fetchdat & 7)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(73); @@ -235,7 +245,6 @@ static int opFDIVr(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FDIV\n"); x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; CLOCK_CYCLES(73); @@ -245,7 +254,6 @@ static int opFDIVP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FDIVP\n"); x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; x87_pop(); @@ -257,7 +265,6 @@ static int opFDIVR(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FDIVR\n"); x87_div(ST(0), ST(fetchdat&7), ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(73); @@ -267,7 +274,6 @@ static int opFDIVRr(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FDIVR\n"); x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; CLOCK_CYCLES(73); @@ -277,7 +283,6 @@ static int opFDIVRP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FDIVR\n"); x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; x87_pop(); @@ -289,7 +294,6 @@ static int opFMUL(uint32_t fetchdat) { FP_ENTER(); 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); @@ -299,7 +303,6 @@ static int opFMULr(uint32_t fetchdat) { FP_ENTER(); 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); @@ -309,7 +312,6 @@ static int opFMULP(uint32_t fetchdat) { FP_ENTER(); 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; x87_pop(); @@ -321,7 +323,6 @@ static int opFSUB(uint32_t fetchdat) { FP_ENTER(); 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); @@ -331,7 +332,6 @@ static int opFSUBr(uint32_t fetchdat) { FP_ENTER(); 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); @@ -341,7 +341,6 @@ static int opFSUBP(uint32_t fetchdat) { FP_ENTER(); 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; x87_pop(); @@ -353,7 +352,6 @@ static int opFSUBR(uint32_t fetchdat) { FP_ENTER(); 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); @@ -363,7 +361,6 @@ static int opFSUBRr(uint32_t fetchdat) { FP_ENTER(); 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); @@ -373,7 +370,6 @@ static int opFSUBRP(uint32_t fetchdat) { FP_ENTER(); 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; x87_pop(); @@ -381,11 +377,11 @@ static int opFSUBRP(uint32_t fetchdat) return 0; } +#ifndef FPU_8087 static int opFUCOM(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FUCOM\n"); cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); CLOCK_CYCLES(4); @@ -396,7 +392,6 @@ static int opFUCOMP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FUCOMP\n"); cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); x87_pop(); @@ -404,15 +399,15 @@ static int opFUCOMP(uint32_t fetchdat) return 0; } +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) static int opFUCOMI(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FUCOMI\n"); flags_rebuild(); - flags &= ~(Z_FLAG | P_FLAG | C_FLAG); - if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; - else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + 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(4); return 0; } @@ -420,12 +415,13 @@ static int opFUCOMIP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FUCOMIP\n"); flags_rebuild(); - flags &= ~(Z_FLAG | P_FLAG | C_FLAG); - if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; - else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + 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); return 0; } +#endif +#endif diff --git a/src/cpu/x87_ops_loadstore.h b/src/cpu/x87_ops_loadstore.h index 39a14c4fb..3001e8ca8 100644 --- a/src/cpu/x87_ops_loadstore.h +++ b/src/cpu/x87_ops_loadstore.h @@ -8,12 +8,12 @@ * * x87 FPU instructions core. * - * Version: @(#)x87_ops_loadstore.h 1.0.0 2017/05/30 + * Version: @(#)x87_ops_loadstore.h 1.0.2 2019/06/11 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016-2017 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ static int opFILDiw_a16(uint32_t fetchdat) @@ -21,90 +21,85 @@ static int opFILDiw_a16(uint32_t fetchdat) int16_t temp; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; - if (fplog) pclog(" %f\n", (double)temp); x87_push((double)temp); CLOCK_CYCLES(13); return 0; } +#ifndef FPU_8087 static int opFILDiw_a32(uint32_t fetchdat) { int16_t temp; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; - if (fplog) pclog(" %f\n", (double)temp); x87_push((double)temp); CLOCK_CYCLES(13); return 0; } +#endif static int opFISTiw_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); -/* if (temp64 > 32767 || temp64 < -32768) - fatal("FISTw overflow %i\n", temp64);*/ seteaw((int16_t)temp64); CLOCK_CYCLES(29); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFISTiw_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); -/* if (temp64 > 32767 || temp64 < -32768) - fatal("FISTw overflow %i\n", temp64);*/ seteaw((int16_t)temp64); CLOCK_CYCLES(29); return cpu_state.abrt; } +#endif static int opFISTPiw_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); 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); return 0; } +#ifndef FPU_8087 static int opFISTPiw_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); 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); return 0; } +#endif static int opFILDiq_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); 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; @@ -112,14 +107,14 @@ static int opFILDiq_a16(uint32_t fetchdat) CLOCK_CYCLES(10); return 0; } +#ifndef FPU_8087 static int opFILDiq_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); 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; @@ -127,6 +122,7 @@ static int opFILDiq_a32(uint32_t fetchdat) CLOCK_CYCLES(10); return 0; } +#endif static int FBSTP_a16(uint32_t fetchdat) { @@ -134,7 +130,7 @@ static int FBSTP_a16(uint32_t fetchdat) int c; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); tempd = ST(0); if (tempd < 0.0) tempd = -tempd; @@ -154,13 +150,14 @@ static int FBSTP_a16(uint32_t fetchdat) x87_pop(); return 0; } +#ifndef FPU_8087 static int FBSTP_a32(uint32_t fetchdat) { double tempd; int c; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); tempd = ST(0); if (tempd < 0.0) tempd = -tempd; @@ -180,13 +177,14 @@ static int FBSTP_a32(uint32_t fetchdat) x87_pop(); return 0; } +#endif static int FISTPiq_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64) temp64 = cpu_state.MM[cpu_state.TOP].q; else @@ -196,12 +194,13 @@ static int FISTPiq_a16(uint32_t fetchdat) CLOCK_CYCLES(29); return 0; } +#ifndef FPU_8087 static int FISTPiq_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64) temp64 = cpu_state.MM[cpu_state.TOP].q; else @@ -211,278 +210,283 @@ static int FISTPiq_a32(uint32_t fetchdat) CLOCK_CYCLES(29); return 0; } +#endif static int opFILDil_a16(uint32_t fetchdat) { int32_t templ; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); 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); return 0; } +#ifndef FPU_8087 static int opFILDil_a32(uint32_t fetchdat) { int32_t templ; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); 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); return 0; } +#endif static int opFISTil_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); -/* if (temp64 > 2147483647 || temp64 < -2147483647) - fatal("FISTl out of range! %i\n", temp64);*/ seteal((int32_t)temp64); CLOCK_CYCLES(28); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFISTil_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); -/* if (temp64 > 2147483647 || temp64 < -2147483647) - fatal("FISTl out of range! %i\n", temp64);*/ seteal((int32_t)temp64); CLOCK_CYCLES(28); return cpu_state.abrt; } +#endif static int opFISTPil_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); 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); return 0; } +#ifndef FPU_8087 static int opFISTPil_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); 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); return 0; } +#endif static int opFLDe_a16(uint32_t fetchdat) { double t; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); t=x87_ld80(); if (cpu_state.abrt) return 1; - if (fplog) pclog(" %f\n", t); x87_push(t); CLOCK_CYCLES(6); return 0; } +#ifndef FPU_8087 static int opFLDe_a32(uint32_t fetchdat) { double t; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); t=x87_ld80(); if (cpu_state.abrt) return 1; - if (fplog) pclog(" %f\n", t); x87_push(t); CLOCK_CYCLES(6); return 0; } +#endif static int opFSTPe_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); x87_st80(ST(0)); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(6); return 0; } +#ifndef FPU_8087 static int opFSTPe_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); x87_st80(ST(0)); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(6); return 0; } +#endif static int opFLDd_a16(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); t.i = geteaq(); if (cpu_state.abrt) return 1; - if (fplog) pclog(" %f\n", t.d); x87_push(t.d); CLOCK_CYCLES(3); return 0; } +#ifndef FPU_8087 static int opFLDd_a32(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); t.i = geteaq(); if (cpu_state.abrt) return 1; - if (fplog) pclog(" %f\n", t.d); x87_push(t.d); CLOCK_CYCLES(3); return 0; } +#endif static int opFSTd_a16(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); t.d = ST(0); seteaq(t.i); CLOCK_CYCLES(8); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTd_a32(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); t.d = ST(0); seteaq(t.i); CLOCK_CYCLES(8); return cpu_state.abrt; } +#endif static int opFSTPd_a16(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_16(fetchdat); - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); - if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); t.d = ST(0); seteaq(t.i); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(8); return 0; } +#ifndef FPU_8087 static int opFSTPd_a32(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_32(fetchdat); - CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); - if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); t.d = ST(0); seteaq(t.i); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(8); return 0; } +#endif static int opFLDs_a16(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); ts.i = geteal(); if (cpu_state.abrt) return 1; - if (fplog) pclog(" %f\n", ts.s); x87_push((double)ts.s); CLOCK_CYCLES(3); return 0; } +#ifndef FPU_8087 static int opFLDs_a32(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); ts.i = geteal(); if (cpu_state.abrt) return 1; - if (fplog) pclog(" %f\n", ts.s); x87_push((double)ts.s); CLOCK_CYCLES(3); return 0; } +#endif static int opFSTs_a16(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); CLOCK_CYCLES(7); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTs_a32(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); CLOCK_CYCLES(7); return cpu_state.abrt; } +#endif static int opFSTPs_a16(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(7); return 0; } +#ifndef FPU_8087 static int opFSTPs_a32(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(7); return 0; } +#endif diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index bf4eb3c7f..36dbd8a76 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -1,12 +1,24 @@ +#ifdef FPU_8087 +static int opFI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxc &= ~0x80; + if (rmdat == 0xe1) + cpu_state.npxc |= 0x80; + wait(3, 0); + return 0; +} +#else static int opFSTSW_AX(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FSTSW\n"); AX = cpu_state.npxs; CLOCK_CYCLES(3); return 0; } +#endif @@ -32,7 +44,11 @@ static int opFINIT(uint32_t fetchdat) uint64_t *p; FP_ENTER(); cpu_state.pc++; +#ifdef FPU_8087 + cpu_state.npxc = 0x3FF; +#else cpu_state.npxc = 0x37F; +#endif cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); cpu_state.npxs = 0; p = (uint64_t *)cpu_state.tag; @@ -40,6 +56,7 @@ static int opFINIT(uint32_t fetchdat) cpu_state.TOP = 0; cpu_state.ismmx = 0; CLOCK_CYCLES(17); + CPU_BLOCK_END(); return 0; } @@ -48,7 +65,6 @@ 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); return 0; @@ -58,7 +74,6 @@ static int opFFREEP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FFREE\n"); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(3); @@ -69,7 +84,6 @@ static int opFST(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - 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); @@ -80,7 +94,6 @@ static int opFSTP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FSTP\n"); ST(fetchdat & 7) = ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; x87_pop(); @@ -135,30 +148,32 @@ static int FSTOR() cpu_state.ismmx = 1; CLOCK_CYCLES((cr0 & 1) ? 34 : 44); - 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; } 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; } +#ifndef FPU_8087 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; } +#endif static int FSAVE() { uint64_t *p; 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); switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) @@ -305,35 +320,41 @@ 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; } +#ifndef FPU_8087 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; } +#endif static int opFSTSW_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11)); CLOCK_CYCLES(3); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTSW_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11)); CLOCK_CYCLES(3); return cpu_state.abrt; } +#endif static int opFLD(uint32_t fetchdat) @@ -343,7 +364,6 @@ static int opFLD(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FLD %f\n", ST(fetchdat & 7)); 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)); @@ -360,7 +380,6 @@ static int opFXCH(uint32_t fetchdat) uint64_t old_i64; FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FXCH\n"); td = ST(0); ST(0) = ST(fetchdat&7); ST(fetchdat&7) = td; @@ -379,7 +398,6 @@ static int opFCHS(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FCHS\n"); ST(0) = -ST(0); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(6); @@ -390,7 +408,6 @@ static int opFABS(uint32_t fetchdat) { FP_ENTER(); 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); @@ -401,7 +418,6 @@ static int opFTST(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FTST\n"); 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; @@ -413,9 +429,8 @@ static int opFXAM(uint32_t fetchdat) { FP_ENTER(); 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] == 3) 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; @@ -427,7 +442,6 @@ static int opFLD1(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FLD1\n"); x87_push(1.0); CLOCK_CYCLES(4); return 0; @@ -437,7 +451,6 @@ static int opFLDL2T(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FLDL2T\n"); x87_push(3.3219280948873623); CLOCK_CYCLES(8); return 0; @@ -447,7 +460,6 @@ static int opFLDL2E(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FLDL2E\n"); x87_push(1.4426950408889634); CLOCK_CYCLES(8); return 0; @@ -457,7 +469,6 @@ static int opFLDPI(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FLDPI\n"); x87_push(3.141592653589793); CLOCK_CYCLES(8); return 0; @@ -467,7 +478,6 @@ static int opFLDEG2(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FLDEG2\n"); x87_push(0.3010299956639812); CLOCK_CYCLES(8); return 0; @@ -477,7 +487,6 @@ static int opFLDLN2(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FLDLN2\n"); x87_push_u64(0x3fe62e42fefa39f0ull); CLOCK_CYCLES(8); return 0; @@ -487,7 +496,6 @@ static int opFLDZ(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FLDZ\n"); x87_push(0.0); cpu_state.tag[cpu_state.TOP&7] = 1; CLOCK_CYCLES(4); @@ -498,7 +506,6 @@ static int opF2XM1(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("F2XM1\n"); ST(0) = pow(2.0, ST(0)) - 1.0; cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(200); @@ -509,7 +516,6 @@ static int opFYL2X(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FYL2X\n"); ST(1) = ST(1) * (log(ST(0)) / log(2.0)); cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; x87_pop(); @@ -521,7 +527,6 @@ static int opFYL2XP1(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FYL2XP1\n"); ST(1) = ST(1) * (log1p(ST(0)) / log(2.0)); cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; x87_pop(); @@ -533,7 +538,6 @@ static int opFPTAN(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FPTAN\n"); ST(0) = tan(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; x87_push(1.0); @@ -546,7 +550,6 @@ static int opFPATAN(uint32_t fetchdat) { FP_ENTER(); 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; x87_pop(); @@ -558,7 +561,6 @@ 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); return 0; @@ -568,7 +570,6 @@ 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); return 0; @@ -579,11 +580,9 @@ static int opFPREM(uint32_t fetchdat) int64_t temp64; FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FPREM %f %f ", ST(0), ST(1)); temp64 = (int64_t)(ST(0) / ST(1)); ST(0) = ST(0) - (ST(1) * (double)temp64); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - 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; @@ -591,16 +590,15 @@ static int opFPREM(uint32_t fetchdat) CLOCK_CYCLES(100); return 0; } +#ifndef FPU_8087 static int opFPREM1(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FPREM1 %f %f ", ST(0), ST(1)); temp64 = (int64_t)(ST(0) / ST(1)); ST(0) = ST(0) - (ST(1) * (double)temp64); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - 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; @@ -608,24 +606,24 @@ static int opFPREM1(uint32_t fetchdat) CLOCK_CYCLES(100); return 0; } +#endif static int opFSQRT(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FSQRT\n"); ST(0) = sqrt(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(83); return 0; } +#ifndef FPU_8087 static int opFSINCOS(uint32_t fetchdat) { double td; FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FSINCOS\n"); td = ST(0); ST(0) = sin(td); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; @@ -634,15 +632,14 @@ static int opFSINCOS(uint32_t fetchdat) CLOCK_CYCLES(330); return 0; } +#endif static int opFRNDINT(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FRNDINT %g ", ST(0)); ST(0) = (double)x87_fround(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - if (fplog) pclog("%g\n", ST(0)); CLOCK_CYCLES(21); return 0; } @@ -652,7 +649,6 @@ static int opFSCALE(uint32_t fetchdat) int64_t temp64; FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FSCALE\n"); temp64 = (int64_t)ST(1); ST(0) = ST(0) * pow(2.0, (double)temp64); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; @@ -660,11 +656,11 @@ static int opFSCALE(uint32_t fetchdat) return 0; } +#ifndef FPU_8087 static int opFSIN(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FSIN\n"); ST(0) = sin(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; cpu_state.npxs &= ~C2; @@ -676,19 +672,18 @@ static int opFCOS(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - if (fplog) pclog("FCOS\n"); ST(0) = cos(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; cpu_state.npxs &= ~C2; CLOCK_CYCLES(300); return 0; } +#endif static int FLDENV() { FP_ENTER(); - if (fplog) pclog("FLDENV %08X:%08X\n", easeg, cpu_state.eaaddr); switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) { case 0x000: /*16-bit real mode*/ @@ -716,23 +711,27 @@ 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; } +#ifndef FPU_8087 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; } +#endif static int opFLDCW_a16(uint32_t fetchdat) { uint16_t tempw; FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; @@ -740,12 +739,13 @@ static int opFLDCW_a16(uint32_t fetchdat) CLOCK_CYCLES(4); return 0; } +#ifndef FPU_8087 static int opFLDCW_a32(uint32_t fetchdat) { uint16_t tempw; FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; @@ -753,11 +753,11 @@ static int opFLDCW_a32(uint32_t fetchdat) CLOCK_CYCLES(4); return 0; } +#endif static int FSTENV() { FP_ENTER(); - if (fplog) pclog("FSTENV %08X:%08X\n", easeg, cpu_state.eaaddr); switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) { case 0x000: /*16-bit real mode*/ @@ -802,42 +802,49 @@ 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; } +#ifndef FPU_8087 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; } +#endif static int opFSTCW_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); - if (fplog) pclog("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.npxc); CLOCK_CYCLES(3); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTCW_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); - if (fplog) pclog("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.npxc); CLOCK_CYCLES(3); return cpu_state.abrt; } +#endif +#ifndef FPU_8087 +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) #define opFCMOV(condition) \ static int opFCMOV ## condition(uint32_t fetchdat) \ { \ FP_ENTER(); \ cpu_state.pc++; \ - if (fplog) pclog("FCMOV %f\n", ST(fetchdat & 7)); \ if (cond_ ## condition) \ { \ cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; \ @@ -859,3 +866,5 @@ opFCMOV(NB) opFCMOV(NE) opFCMOV(NBE) opFCMOV(NU) +#endif +#endif diff --git a/src/cpu_new/386.c b/src/cpu_new/386.c new file mode 100644 index 000000000..2b2268920 --- /dev/null +++ b/src/cpu_new/386.c @@ -0,0 +1,303 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "../timer.h" +#include "x86.h" +#include "x87.h" +#include "../nmi.h" +#include "../mem.h" +#include "../pic.h" +#include "../pit.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "386_common.h" +#include "codegen.h" + + +#ifdef ENABLE_386_LOG +int x386_do_log = ENABLE_386_LOG; + + +void +x386_log(const char *fmt, ...) +{ + va_list ap; + + if (x386_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define x386_log(fmt, ...) +#endif + + +#undef CPU_BLOCK_END +#define CPU_BLOCK_END() + + +extern int codegen_flags_changed; + +int tempc, oldcpl, optype, inttype, oddeven = 0; +int timetolive; + +uint16_t oldcs; + +uint32_t oldds, oldss, olddslimit, oldsslimit, + olddslimitw, oldsslimitw; +uint32_t oxpc; +uint32_t rmdat32; +uint32_t backupregs[16]; + +x86seg _oldds; + + +static __inline void +fetch_ea_32_long(uint32_t rmdat) +{ + uint8_t sib; + uint32_t addr; + + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (cpu_rm == 4) { + sib = rmdat >> 8; + + switch (cpu_mod) { + case 0: + cpu_state.eaaddr = cpu_state.regs[sib & 7].l; + cpu_state.pc++; + break; + case 1: + cpu_state.pc++; + cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; + break; + case 2: + cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; + break; + } + /*SIB byte present*/ + if ((sib & 7) == 5 && !cpu_mod) + cpu_state.eaaddr = getlong(); + else if ((sib & 6) == 4 && !cpu_state.ssegs) { + easeg = 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); + } else { + cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; + if (cpu_mod) { + if (cpu_rm == 5 && !cpu_state.ssegs) { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + if (cpu_mod == 1) { + cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } else + cpu_state.eaaddr += getlong(); + } else if (cpu_rm == 5) + cpu_state.eaaddr = getlong(); + } + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { + addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + + +static __inline void +fetch_ea_16_long(uint32_t rmdat) +{ + uint32_t addr; + + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (!cpu_mod && cpu_rm == 6) + cpu_state.eaaddr = getword(); + else { + switch (cpu_mod) { + case 0: + cpu_state.eaaddr = 0; + break; + case 1: + cpu_state.eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; + break; + case 2: + cpu_state.eaaddr = getword(); + break; + } + cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + cpu_state.eaaddr &= 0xFFFF; + } + + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { + addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + + +#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 0; } +#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 0 + +#include "x86_flags.h" + +#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ +#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 + + +#define OP_TABLE(name) ops_ ## name + +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "x86_ops.h" + + +void +exec386(int cycs) +{ + uint8_t opcode; + int vector, tempi, cycdiff, oldcyc; + int cycle_period, ins_cycles; + uint32_t addr; + + cycles += cycs; + + while (cycles > 0) { + cycle_period = (timer_target - (uint32_t)tsc) + 1; + + x86_was_reset = 0; + cycdiff = 0; + oldcyc = cycles; + while (cycdiff < cycle_period) { + ins_cycles = cycles; + + 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) { + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; + + cpu_state.pc++; + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + if (x86_was_reset) + break; + } + + if (cpu_state.abrt) { + flags_rebuild(); + tempi = cpu_state.abrt; + cpu_state.abrt = 0; + x86_doabrt(tempi); + if (cpu_state.abrt) { + cpu_state.abrt = 0; + cpu_state.pc = cpu_state.oldpc; + x386_log("Double fault %i\n", ins); + pmodeint(8, 0); + if (cpu_state.abrt) { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); +#ifdef ENABLE_386_LOG + x386_log("Triple fault - reset\n"); +#endif + } + } + } + + ins_cycles -= cycles; + tsc += ins_cycles; + + cycdiff = oldcyc - cycles; + + if (trap) { + flags_rebuild(); + if (msw&1) + pmodeint(1,0); + 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; + addr = (1 << 2) + idt.base; + 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 && nmi_mask) { + cpu_state.oldpc = cpu_state.pc; + 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) { + vector = picinterrupt(); + if (vector != 0xFF) { + flags_rebuild(); + if (msw & 1) + pmodeint(vector, 0); + 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; + addr = (vector << 2) + idt.base; + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc = readmemw(0, addr); + loadcs(readmemw(0, addr + 2)); + } + } + } + + ins++; + + if (timetolive) { + timetolive--; + if (!timetolive) + fatal("Life expired\n"); + } + } + + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + timer_process(); + } +} diff --git a/src/cpu_new/386_common.c b/src/cpu_new/386_common.c new file mode 100644 index 000000000..32b65e0bf --- /dev/null +++ b/src/cpu_new/386_common.c @@ -0,0 +1,292 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "../timer.h" +#include "x86.h" +#include "x87.h" +#include "../nmi.h" +#include "../mem.h" +#include "../pic.h" +#include "../pit.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.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]; + +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; + + +#ifdef ENABLE_386_COMMON_LOG +int x386_common_do_log = ENABLE_386_COMMON_LOG; + + +void +x386_common_log(const char *fmt, ...) +{ + va_list ap; + + if (x386_common_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define x386_common_log(fmt, ...) +#endif + + +void x86_int(int num) +{ + uint32_t addr; + 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(); +#ifdef ENABLE_386_COMMON_LOG + x386_log("Triple fault in real mode - reset\n"); +#endif + } + 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; + 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) + return 1; + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + if (cpu_state.abrt) + 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() +{ + x86_int(6); +} + +int checkio(int port) +{ + uint16_t t; + uint8_t d; + cpl_override = 1; + t = readmemw(tr.base, 0x66); + cpl_override = 0; + if (cpu_state.abrt) return 0; + if ((t+(port>>3))>tr.limit) return 1; + cpl_override = 1; + d = readmembl(tr.base + t + (port >> 3)); + cpl_override = 0; + return d&(1<<(port&7)); +} + +#define divexcp() { \ + x386_common_log("Divide exception at %04X(%06X):%04X\n",CS,cs,cpu_state.pc); \ + x86_int(0); \ +} + +int divl(uint32_t val) +{ + uint64_t num, quo; + uint32_t rem, quo32; + + if (val==0) + { + divexcp(); + return 1; + } + + num=(((uint64_t)EDX)<<32)|EAX; + quo=num/val; + rem=num%val; + quo32=(uint32_t)(quo&0xFFFFFFFF); + + if (quo!=(uint64_t)quo32) + { + divexcp(); + return 1; + } + EDX=rem; + EAX=quo32; + return 0; +} +int idivl(int32_t val) +{ + int64_t num, quo; + int32_t rem, quo32; + + if (val==0) + { + divexcp(); + return 1; + } + + num=(((uint64_t)EDX)<<32)|EAX; + quo=num/val; + rem=num%val; + 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/cpu_new/386_common.h b/src/cpu_new/386_common.h new file mode 100644 index 000000000..3ac390f98 --- /dev/null +++ b/src/cpu_new/386_common.h @@ -0,0 +1,328 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Common 386 CPU code. + * + * Version: @(#)386_common.h 1.0.1 2019/02/19 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ + +#ifndef _386_COMMON_H_ +#define _386_COMMON_H_ + +#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 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 || (cpu_state.eflags&VM_FLAG)) \ + { \ + int tempi = checkio(port); \ + if (cpu_state.abrt) return 1; \ + if (tempi) \ + { \ + x86gpf(NULL,0); \ + return 1; \ + } \ + } + +#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(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \ + { \ + x86gpf("Limit check (READ)", 0); \ + return 1; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 0); \ + (void) mmutranslatereal((chseg)->base + high, 0); \ + if (cpu_state.abrt) \ + return 1; \ + } + +#define CHECK_READ_REP(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (READ)", 0); \ + break; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 0); \ + (void) mmutranslatereal((chseg)->base + high, 0); \ + if (cpu_state.abrt) \ + break; \ + } + +#define CHECK_WRITE_COMMON(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && ((chseg)->access & 8))) \ + { \ + x86gpf("Limit check (WRITE)", 0); \ + return 1; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write to seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } + +#define CHECK_WRITE(chseg, low, high) \ + CHECK_WRITE_COMMON(chseg, low, high) \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 1); \ + (void) mmutranslatereal((chseg)->base + high, 1); \ + if (cpu_state.abrt) \ + return 1; \ + } + +#define CHECK_WRITE_REP(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (WRITE REP)", 0); \ + break; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 1); \ + (void) mmutranslatereal((chseg)->base + high, 1); \ + if (cpu_state.abrt) \ + break; \ + } + + +#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\ + { \ + x86_int(6); \ + return 1; \ + } + + + + +static inline uint8_t fastreadb(uint32_t a) +{ + uint8_t *t; + + if ((a >> 12) == pccache) + return *((uint8_t *)&pccache2[a]); + t = getpccache(a); + if (cpu_state.abrt) + return 0; + pccache = a >> 12; + pccache2 = t; + return *((uint8_t *)&pccache2[a]); +} + +static inline uint16_t fastreadw(uint32_t a) +{ + uint8_t *t; + uint16_t val; + if ((a&0xFFF)>0xFFE) + { + val = fastreadb(a); + val |= (fastreadb(a + 1) << 8); + return val; + } + if ((a>>12)==pccache) return *((uint16_t *)&pccache2[a]); + t = getpccache(a); + if (cpu_state.abrt) + return 0; + + pccache = a >> 12; + pccache2 = t; + return *((uint16_t *)&pccache2[a]); +} + +static inline uint32_t fastreadl(uint32_t a) +{ + uint8_t *t; + uint32_t val; + if ((a&0xFFF)<0xFFD) + { + if ((a>>12)!=pccache) + { + t = getpccache(a); + if (cpu_state.abrt) + return 0; + pccache2 = t; + pccache=a>>12; + } + return *((uint32_t *)&pccache2[a]); + } + 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++; + return fastreadb(cs + (cpu_state.pc - 1)); +} + +static inline uint16_t getword() +{ + cpu_state.pc+=2; + return fastreadw(cs+(cpu_state.pc-2)); +} + +static inline uint32_t getlong() +{ + cpu_state.pc+=4; + return fastreadl(cs+(cpu_state.pc-4)); +} + +static inline uint64_t getquad() +{ + cpu_state.pc+=8; + return fastreadl(cs+(cpu_state.pc-8)) | ((uint64_t)fastreadl(cs+(cpu_state.pc-4)) << 32); +} + + + +static inline uint8_t geteab() +{ + if (cpu_mod == 3) + 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); +} + +static inline uint16_t geteaw() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + if (eal_r) + return *(uint16_t *)eal_r; + return readmemw(easeg,cpu_state.eaaddr); +} + +static inline uint32_t geteal() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].l; + if (eal_r) + return *eal_r; + return readmeml(easeg,cpu_state.eaaddr); +} + +static inline uint64_t geteaq() +{ + return readmemq(easeg,cpu_state.eaaddr); +} + +static inline uint8_t geteab_mem() +{ + if (eal_r) return *(uint8_t *)eal_r; + return readmemb(easeg,cpu_state.eaaddr); +} +static inline uint16_t geteaw_mem() +{ + if (eal_r) return *(uint16_t *)eal_r; + return readmemw(easeg,cpu_state.eaaddr); +} +static inline uint32_t geteal_mem() +{ + if (eal_r) return *eal_r; + return readmeml(easeg,cpu_state.eaaddr); +} + +static __inline int seteaq_cwc(void) +{ + CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + return 0; +} + +static __inline void seteaq(uint64_t v) +{ + if (seteaq_cwc()) + return; + writememql(easeg + cpu_state.eaaddr, v); +} + +#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); 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) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); 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) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 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 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 + +#endif diff --git a/src/cpu_new/386_dynarec.c b/src/cpu_new/386_dynarec.c new file mode 100644 index 000000000..0081aceb8 --- /dev/null +++ b/src/cpu_new/386_dynarec.c @@ -0,0 +1,884 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "../pic.h" +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#ifdef USE_DYNAREC +#include "codegen.h" +#include "codegen_backend.h" +#endif +#include "386_common.h" + + +#ifdef ENABLE_386_DYNAREC_LOG +int x386_dynarec_do_log = ENABLE_386_DYNAREC_LOG; + + +void +x386_dynarec_log(const char *fmt, ...) +{ + va_list ap; + + if (x386_dynarec_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define x386_dynarec_log(fmt, ...) +#endif + + +#define CPU_BLOCK_END() cpu_block_end = 1 + +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; + + +static __inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (cpu_rm == 4) + { + uint8_t sib = rmdat >> 8; + + switch (cpu_mod) + { + case 0: + cpu_state.eaaddr = cpu_state.regs[sib & 7].l; + cpu_state.pc++; + break; + case 1: + cpu_state.pc++; + cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; + break; + case 2: + cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; + break; + } + /*SIB byte present*/ + if ((sib & 7) == 5 && !cpu_mod) + cpu_state.eaaddr = getlong(); + else if ((sib & 6) == 4 && !cpu_state.ssegs) + { + easeg = 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); + } + else + { + cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; + if (cpu_mod) + { + if (cpu_rm == 5 && !cpu_state.ssegs) + { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + if (cpu_mod == 1) + { + cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } + else + { + cpu_state.eaaddr += getlong(); + } + } + else if (cpu_rm == 5) + { + cpu_state.eaaddr = getlong(); + } + } + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } + cpu_state.last_ea = cpu_state.eaaddr; +} + +static __inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (!cpu_mod && cpu_rm == 6) + { + cpu_state.eaaddr = getword(); + } + else + { + switch (cpu_mod) + { + case 0: + cpu_state.eaaddr = 0; + break; + case 1: + cpu_state.eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; + break; + case 2: + cpu_state.eaaddr = getword(); + break; + } + cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) + { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + cpu_state.eaaddr &= 0xFFFF; + } + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } + cpu_state.last_ea = cpu_state.eaaddr; +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 1; } +#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 1 + +#include "x86_flags.h" + + +/*Prefetch emulation is a fairly simplistic model: + - All instruction bytes must be fetched before it starts. + - Cycles used for non-instruction memory accesses are counted and subtracted + from the total cycles taken + - Any remaining cycles are used to refill the prefetch queue. + + Note that this is only used for 286 / 386 systems. It is disabled when the + internal cache on 486+ CPUs is enabled. +*/ +static int prefetch_bytes = 0; +static int prefetch_prefixes = 0; + +static void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int reads_l, int writes, int writes_l, int ea32) +{ + int mem_cycles = reads*cpu_cycles_read + reads_l*cpu_cycles_read_l + writes*cpu_cycles_write + writes_l*cpu_cycles_write_l; + + if (instr_cycles < mem_cycles) + instr_cycles = mem_cycles; + + prefetch_bytes -= prefetch_prefixes; + prefetch_bytes -= bytes; + if (modrm != -1) + { + if (ea32) + { + if ((modrm & 7) == 4) + { + if ((modrm & 0x700) == 0x500) + prefetch_bytes -= 5; + else if ((modrm & 0xc0) == 0x40) + prefetch_bytes -= 2; + else if ((modrm & 0xc0) == 0x80) + prefetch_bytes -= 5; + } + else + { + if ((modrm & 0xc7) == 0x05) + prefetch_bytes -= 4; + else if ((modrm & 0xc0) == 0x40) + prefetch_bytes--; + else if ((modrm & 0xc0) == 0x80) + prefetch_bytes -= 4; + } + } + else + { + if ((modrm & 0xc7) == 0x06) + prefetch_bytes -= 2; + else if ((modrm & 0xc0) != 0xc0) + prefetch_bytes -= ((modrm & 0xc0) >> 6); + } + } + + /* Fill up prefetch queue */ + while (prefetch_bytes < 0) + { + prefetch_bytes += cpu_prefetch_width; + cycles -= cpu_prefetch_cycles; + } + + /* Subtract cycles used for memory access by instruction */ + instr_cycles -= mem_cycles; + + while (instr_cycles >= cpu_prefetch_cycles) + { + prefetch_bytes += cpu_prefetch_width; + instr_cycles -= cpu_prefetch_cycles; + } + + prefetch_prefixes = 0; + if (prefetch_bytes > 16) + prefetch_bytes = 16; +} + +static void prefetch_flush() +{ + prefetch_bytes = 0; +} + +#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() do { if (cpu_prefetch_cycles) prefetch_prefixes++; } while (0) +#define PREFETCH_FLUSH() prefetch_flush() + + +void enter_smm() +{ + uint32_t smram_state = smbase + 0xfe00; + uint32_t old_cr0 = cr0; + uint32_t old_flags = cpu_state.flags | ((uint32_t)cpu_state.eflags << 16); + + cr0 &= ~0x8000000d; + cpu_state.flags = 2; + cpu_state.eflags = 0; + + in_smm = 1; + smi_latched = 1; + + mem_writel_phys(smram_state + 0xf8, smbase); + mem_writel_phys(smram_state + 0x128, cr4); + mem_writel_phys(smram_state + 0x130, cpu_state.seg_es.limit); + mem_writel_phys(smram_state + 0x134, cpu_state.seg_es.base); + mem_writel_phys(smram_state + 0x138, cpu_state.seg_es.access); + mem_writel_phys(smram_state + 0x13c, cpu_state.seg_cs.limit); + mem_writel_phys(smram_state + 0x140, cpu_state.seg_cs.base); + mem_writel_phys(smram_state + 0x144, cpu_state.seg_cs.access); + mem_writel_phys(smram_state + 0x148, cpu_state.seg_ss.limit); + mem_writel_phys(smram_state + 0x14c, cpu_state.seg_ss.base); + mem_writel_phys(smram_state + 0x150, cpu_state.seg_ss.access); + mem_writel_phys(smram_state + 0x154, cpu_state.seg_ds.limit); + mem_writel_phys(smram_state + 0x158, cpu_state.seg_ds.base); + mem_writel_phys(smram_state + 0x15c, cpu_state.seg_ds.access); + mem_writel_phys(smram_state + 0x160, cpu_state.seg_fs.limit); + mem_writel_phys(smram_state + 0x164, cpu_state.seg_fs.base); + mem_writel_phys(smram_state + 0x168, cpu_state.seg_fs.access); + mem_writel_phys(smram_state + 0x16c, cpu_state.seg_gs.limit); + mem_writel_phys(smram_state + 0x170, cpu_state.seg_gs.base); + mem_writel_phys(smram_state + 0x174, cpu_state.seg_gs.access); + mem_writel_phys(smram_state + 0x178, ldt.limit); + mem_writel_phys(smram_state + 0x17c, ldt.base); + mem_writel_phys(smram_state + 0x180, ldt.access); + mem_writel_phys(smram_state + 0x184, gdt.limit); + mem_writel_phys(smram_state + 0x188, gdt.base); + mem_writel_phys(smram_state + 0x18c, gdt.access); + mem_writel_phys(smram_state + 0x190, idt.limit); + mem_writel_phys(smram_state + 0x194, idt.base); + mem_writel_phys(smram_state + 0x198, idt.access); + mem_writel_phys(smram_state + 0x19c, tr.limit); + mem_writel_phys(smram_state + 0x1a0, tr.base); + mem_writel_phys(smram_state + 0x1a4, tr.access); + + mem_writel_phys(smram_state + 0x1a8, cpu_state.seg_es.seg); + mem_writel_phys(smram_state + 0x1ac, cpu_state.seg_cs.seg); + mem_writel_phys(smram_state + 0x1b0, cpu_state.seg_ss.seg); + mem_writel_phys(smram_state + 0x1b4, cpu_state.seg_ds.seg); + mem_writel_phys(smram_state + 0x1b8, cpu_state.seg_fs.seg); + mem_writel_phys(smram_state + 0x1bc, cpu_state.seg_gs.seg); + mem_writel_phys(smram_state + 0x1c0, ldt.seg); + mem_writel_phys(smram_state + 0x1c4, tr.seg); + + mem_writel_phys(smram_state + 0x1c8, dr[7]); + mem_writel_phys(smram_state + 0x1cc, dr[6]); + mem_writel_phys(smram_state + 0x1d0, EAX); + mem_writel_phys(smram_state + 0x1d4, ECX); + mem_writel_phys(smram_state + 0x1d8, EDX); + mem_writel_phys(smram_state + 0x1dc, EBX); + mem_writel_phys(smram_state + 0x1e0, ESP); + mem_writel_phys(smram_state + 0x1e4, EBP); + mem_writel_phys(smram_state + 0x1e8, ESI); + mem_writel_phys(smram_state + 0x1ec, EDI); + mem_writel_phys(smram_state + 0x1f0, cpu_state.pc); + mem_writel_phys(smram_state + 0x1d0, old_flags); + mem_writel_phys(smram_state + 0x1f8, cr3); + mem_writel_phys(smram_state + 0x1fc, old_cr0); + + ds = es = fs_seg = gs = ss = 0; + + DS = ES = FS = GS = SS = 0; + + cpu_state.seg_ds.limit = cpu_state.seg_es.limit = cpu_state.seg_fs.limit = cpu_state.seg_gs.limit + = cpu_state.seg_ss.limit = 0xffffffff; + + cpu_state.seg_ds.limit_high = cpu_state.seg_es.limit_high = cpu_state.seg_fs.limit_high + = cpu_state.seg_gs.limit_high = cpu_state.seg_ss.limit_high = 0xffffffff; + + cpu_state.seg_ds.limit_low = cpu_state.seg_es.limit_low = cpu_state.seg_fs.limit_low + = cpu_state.seg_gs.limit_low = cpu_state.seg_ss.limit_low = 0; + + cpu_state.seg_ds.access = cpu_state.seg_es.access = cpu_state.seg_fs.access + = cpu_state.seg_gs.access = cpu_state.seg_ss.access = 0x93; + + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked + = cpu_state.seg_gs.checked = cpu_state.seg_ss.checked = 1; + + CS = 0x3000; + cs = smbase; + cpu_state.seg_cs.limit = cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.access = 0x93; + cpu_state.seg_cs.checked = 1; + + cr4 = 0; + dr[7] = 0x400; + cpu_state.pc = 0x8000; + + nmi_mask = 0; +} + +void leave_smm() +{ + uint32_t smram_state = smbase + 0xfe00; + + smbase = mem_readl_phys(smram_state + 0xf8); + cr4 = mem_readl_phys(smram_state + 0x128); + + cpu_state.seg_es.limit = cpu_state.seg_es.limit_high = mem_readl_phys(smram_state + 0x130); + cpu_state.seg_es.base = mem_readl_phys(smram_state + 0x134); + cpu_state.seg_es.limit_low = cpu_state.seg_es.base; + cpu_state.seg_es.access = mem_readl_phys(smram_state + 0x138); + + cpu_state.seg_cs.limit = cpu_state.seg_cs.limit_high = mem_readl_phys(smram_state + 0x13c); + cpu_state.seg_cs.base = mem_readl_phys(smram_state + 0x140); + cpu_state.seg_cs.limit_low = cpu_state.seg_cs.base; + cpu_state.seg_cs.access = mem_readl_phys(smram_state + 0x144); + + cpu_state.seg_ss.limit = cpu_state.seg_ss.limit_high = mem_readl_phys(smram_state + 0x148); + cpu_state.seg_ss.base = mem_readl_phys(smram_state + 0x14c); + cpu_state.seg_ss.limit_low = cpu_state.seg_ss.base; + cpu_state.seg_ss.access = mem_readl_phys(smram_state + 0x150); + + cpu_state.seg_ds.limit = cpu_state.seg_ds.limit_high = mem_readl_phys(smram_state + 0x154); + cpu_state.seg_ds.base = mem_readl_phys(smram_state + 0x158); + cpu_state.seg_ds.limit_low = cpu_state.seg_ds.base; + cpu_state.seg_ds.access = mem_readl_phys(smram_state + 0x15c); + + cpu_state.seg_fs.limit = cpu_state.seg_fs.limit_high = mem_readl_phys(smram_state + 0x160); + cpu_state.seg_fs.base = mem_readl_phys(smram_state + 0x164); + cpu_state.seg_fs.limit_low = cpu_state.seg_fs.base; + cpu_state.seg_fs.access = mem_readl_phys(smram_state + 0x168); + + cpu_state.seg_gs.limit = cpu_state.seg_gs.limit_high = mem_readl_phys(smram_state + 0x16c); + cpu_state.seg_gs.base = mem_readl_phys(smram_state + 0x170); + cpu_state.seg_gs.limit_low = cpu_state.seg_gs.base; + cpu_state.seg_gs.access = mem_readl_phys(smram_state + 0x174); + + ldt.limit = ldt.limit_high = mem_readl_phys(smram_state + 0x178); + ldt.base = mem_readl_phys(smram_state + 0x17c); + ldt.limit_low = ldt.base; + ldt.access = mem_readl_phys(smram_state + 0x180); + + gdt.limit = gdt.limit_high = mem_readl_phys(smram_state + 0x184); + gdt.base = mem_readl_phys(smram_state + 0x188); + gdt.limit_low = gdt.base; + gdt.access = mem_readl_phys(smram_state + 0x18c); + + idt.limit = idt.limit_high = mem_readl_phys(smram_state + 0x190); + idt.base = mem_readl_phys(smram_state + 0x194); + idt.limit_low = idt.base; + idt.access = mem_readl_phys(smram_state + 0x198); + + tr.limit = tr.limit_high = mem_readl_phys(smram_state + 0x19c); + tr.base = mem_readl_phys(smram_state + 0x1a0); + tr.limit_low = tr.base; + tr.access = mem_readl_phys(smram_state + 0x1a4); + + ES = mem_readl_phys(smram_state + 0x1a8); + CS = mem_readl_phys(smram_state + 0x1ac); + SS = mem_readl_phys(smram_state + 0x1b0); + DS = mem_readl_phys(smram_state + 0x1b4); + FS = mem_readl_phys(smram_state + 0x1b8); + GS = mem_readl_phys(smram_state + 0x1bc); + ldt.seg = mem_readl_phys(smram_state + 0x1c0); + tr.seg = mem_readl_phys(smram_state + 0x1c4); + + dr[7] = mem_readl_phys(smram_state + 0x1c8); + dr[6] = mem_readl_phys(smram_state + 0x1cc); + EAX = mem_readl_phys(smram_state + 0x1d0); + ECX = mem_readl_phys(smram_state + 0x1d4); + EDX = mem_readl_phys(smram_state + 0x1d8); + EBX = mem_readl_phys(smram_state + 0x1dc); + ESP = mem_readl_phys(smram_state + 0x1e0); + EBP = mem_readl_phys(smram_state + 0x1e4); + ESI = mem_readl_phys(smram_state + 0x1e8); + EDI = mem_readl_phys(smram_state + 0x1ec); + + cpu_state.pc = mem_readl_phys(smram_state + 0x1f0); + uint32_t new_flags = mem_readl_phys(smram_state + 0x1f4); + cpu_state.flags = new_flags & 0xffff; + cpu_state.eflags = new_flags >> 16; + cr3 = mem_readl_phys(smram_state + 0x1f8); + cr0 = mem_readl_phys(smram_state + 0x1fc); + + cpu_state.seg_cs.access &= ~0x60; + cpu_state.seg_cs.access |= cpu_state.seg_ss.access & 0x60; //cpl is dpl of ss + + if((cr0 & 1) && !(cpu_state.eflags&VM_FLAG)) + { + cpu_state.seg_cs.checked = CS ? 1 : 0; + cpu_state.seg_ds.checked = DS ? 1 : 0; + cpu_state.seg_es.checked = ES ? 1 : 0; + cpu_state.seg_fs.checked = FS ? 1 : 0; + cpu_state.seg_gs.checked = GS ? 1 : 0; + cpu_state.seg_ss.checked = SS ? 1 : 0; + } + else + { + cpu_state.seg_cs.checked = cpu_state.seg_ds.checked = cpu_state.seg_es.checked + = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = cpu_state.seg_ss.checked = 1; + } + + in_smm = 0; + + nmi_mask = 1; +} + +#define OP_TABLE(name) ops_ ## name +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" + +#define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG)) + +#ifdef USE_DYNAREC +static int cycles_main = 0; + + +void exec386_dynarec(int cycs) +{ + int vector; + uint32_t addr; + int tempi; + int cycdiff; + int oldcyc; + int cyc_period = cycs / 2000; /*5us*/ + + cycles_main += cycs; + while (cycles_main > 0) + { + int cycles_start; + + cycles += cyc_period; + cycles_start = cycles; + + while (cycles>0) + { + oldcyc=cycles; + if (!CACHE_ON()) /*Interpret block*/ + { + cpu_block_end = 0; + x86_was_reset = 0; + 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; + + cpu_state.pc++; + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + } + + if (((cs + cpu_state.pc) >> 12) != pccache) + CPU_BLOCK_END(); + + if (in_smm && smi_line && is_pentium) + CPU_BLOCK_END(); + + if (cpu_state.abrt) + CPU_BLOCK_END(); + if (trap) + CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + ins++; + } + } + else + { + 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]; + + 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++; + + codegen_block_start_recompile(block); + codegen_in_recompile = 1; + + 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; + + 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 (in_smm && smi_line && is_pentium) + CPU_BLOCK_END(); + + if (trap) + CPU_BLOCK_END(); + + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + if (cpu_state.abrt) + { + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + } + + if (!cpu_state.abrt && !x86_was_reset) + codegen_block_end_recompile(block); + + if (x86_was_reset) + codegen_reset(); + + codegen_in_recompile = 0; + } + 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); + + 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; + + trap = cpu_state.flags & T_FLAG; + + 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 (in_smm && smi_line && is_pentium) + CPU_BLOCK_END(); + + if (trap) + CPU_BLOCK_END(); + + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + if (cpu_state.abrt) + { + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + } + + if (!cpu_state.abrt && !x86_was_reset) + codegen_block_end(); + + if (x86_was_reset) + codegen_reset(); + } + else + cpu_state.oldpc = cpu_state.pc; + + } + + cycdiff=oldcyc-cycles; + tsc += cycdiff; + + if (cpu_state.abrt) + { + flags_rebuild(); + tempi = cpu_state.abrt; + cpu_state.abrt = 0; + x86_doabrt(tempi); + if (cpu_state.abrt) + { + cpu_state.abrt = 0; + cpu_state.pc = cpu_state.oldpc; + x386_dynarec_log("Double fault %i\n", ins); + pmodeint(8, 0); + if (cpu_state.abrt) + { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); +#ifdef ENABLE_386_DYNAREC_LOG + x386_dynarec_log("Triple fault - reset\n"); +#endif + } + } + } + + if (in_smm && smi_line && is_pentium) + { + enter_smm(); + } + + else if (trap) + { + trap = 0; + flags_rebuild(); + if (msw&1) + { + pmodeint(1,0); + } + 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; + addr = (1 << 2) + idt.base; + 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 && nmi_mask) + { + cpu_state.oldpc = cpu_state.pc; + 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) + { + vector = picinterrupt(); + if (vector != -1) + { + CPU_BLOCK_END(); + flags_rebuild(); + if (msw&1) + { + pmodeint(vector,0); + } + 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; + addr=vector<<2; + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + } + } + + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); + cycles_main -= (cycles_start - cycles); + } +} +#endif diff --git a/src/cpu_new/386_dynarec_ops.c b/src/cpu_new/386_dynarec_ops.c new file mode 100644 index 000000000..343ab13c3 --- /dev/null +++ b/src/cpu_new/386_dynarec_ops.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "x86_flags.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "../pic.h" +#include "codegen.h" + +#define CPU_BLOCK_END() cpu_block_end = 1 + +#include "386_common.h" + + +static inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +static inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; if (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) +#define PREFETCH_PREFIX() +#define PREFETCH_FLUSH() + +#define OP_TABLE(name) dynarec_ops_ ## name +/*Temporary*/ +#define CLOCK_CYCLES(c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" diff --git a/src/cpu_new/386_ops.h b/src/cpu_new/386_ops.h new file mode 100644 index 000000000..b3d331423 --- /dev/null +++ b/src/cpu_new/386_ops.h @@ -0,0 +1,1822 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * 286/386+ instruction handlers list. + * + * Version: @(#)386_ops.h 1.0.5 2018/10/17 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include "x86_ops.h" + + +#define ILLEGAL_ON(cond) \ + do \ + { \ + if ((cond)) \ + { \ + cpu_state.pc = cpu_state.oldpc; \ + x86illegal(); \ + return 0; \ + } \ + } while (0) + +static __inline void PUSH_W(uint16_t val) +{ + if (stack32) + { + writememw(ss, ESP - 2, val); if (cpu_state.abrt) return; + ESP -= 2; + cpu_state.last_ea = ESP; + } + else + { + writememw(ss, (SP - 2) & 0xFFFF, val); if (cpu_state.abrt) return; + SP -= 2; + cpu_state.last_ea = SP; + } +} + +static __inline void PUSH_L(uint32_t val) +{ + if (stack32) + { + writememl(ss, ESP - 4, val); if (cpu_state.abrt) return; + ESP -= 4; + cpu_state.last_ea = ESP; + } + else + { + writememl(ss, (SP - 4) & 0xFFFF, val); if (cpu_state.abrt) return; + SP -= 4; + cpu_state.last_ea = SP; + } +} + +static __inline uint16_t POP_W() +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(ss, ESP); if (cpu_state.abrt) return 0; + ESP += 2; + cpu_state.last_ea = ESP; + } + else + { + ret = readmemw(ss, SP); if (cpu_state.abrt) return 0; + SP += 2; + cpu_state.last_ea = SP; + } + return ret; +} + +static __inline uint32_t POP_L() +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(ss, ESP); if (cpu_state.abrt) return 0; + ESP += 4; + cpu_state.last_ea = ESP; + } + else + { + ret = readmeml(ss, SP); if (cpu_state.abrt) return 0; + SP += 4; + cpu_state.last_ea = SP; + } + return ret; +} + +static __inline uint16_t POP_W_seg(uint32_t seg) +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(seg, ESP); if (cpu_state.abrt) return 0; + ESP += 2; + cpu_state.last_ea = ESP; + } + else + { + ret = readmemw(seg, SP); if (cpu_state.abrt) return 0; + SP += 2; + cpu_state.last_ea = SP; + } + return ret; +} + +static __inline uint32_t POP_L_seg(uint32_t seg) +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(seg, ESP); if (cpu_state.abrt) return 0; + ESP += 4; + cpu_state.last_ea = ESP; + } + else + { + ret = readmeml(seg, SP); if (cpu_state.abrt) return 0; + SP += 4; + cpu_state.last_ea = SP; + } + return ret; +} + +static int fopcode; + +static int ILLEGAL(uint32_t fetchdat) +{ + cpu_state.pc = cpu_state.oldpc; + + pclog("Illegal instruction %08X (%02X)\n", fetchdat, fopcode); + x86illegal(); + return 0; +} + +static int internal_illegal(char *s) +{ + cpu_state.pc = cpu_state.oldpc; + x86gpf(s, 0); + return cpu_state.abrt; +} + +#ifdef ENABLE_386_DYNAREC_LOG +extern void x386_dynarec_log(const char *fmt, ...); +#else +#ifndef x386_dynarec_log +#define x386_dynarec_log(fmt, ...) +#endif +#endif + +#include "x86seg.h" +# include "x86_ops_amd.h" +#include "x86_ops_arith.h" +#include "x86_ops_atomic.h" +#include "x86_ops_bcd.h" +#include "x86_ops_bit.h" +#include "x86_ops_bitscan.h" +#include "x86_ops_call.h" +#include "x86_ops_flag.h" +#include "x86_ops_fpu.h" +#include "x86_ops_inc_dec.h" +#include "x86_ops_int.h" +#include "x86_ops_io.h" +#include "x86_ops_jump.h" +#include "x86_ops_misc.h" +#include "x87_ops.h" +#if defined(DEV_BRANCH) && defined(USE_I686) +# include "x86_ops_i686.h" +#endif +#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" +#include "x86_ops_mmx_mov.h" +#include "x86_ops_mmx_pack.h" +#include "x86_ops_mmx_shift.h" +#include "x86_ops_mov.h" +#include "x86_ops_mov_ctrl.h" +#include "x86_ops_mov_seg.h" +#include "x86_ops_movx.h" +#include "x86_ops_msr.h" +#include "x86_ops_mul.h" +#include "x86_ops_pmode.h" +#include "x86_ops_prefix.h" +#include "x86_ops_rep.h" +#include "x86_ops_ret.h" +#include "x86_ops_set.h" +#include "x86_ops_shift.h" +#include "x86_ops_stack.h" +#include "x86_ops_string.h" +#include "x86_ops_xchg.h" + + +static int op0F_w_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode](fetchdat >> 8); +} +static int op0F_l_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); +} +static int op0F_w_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); +} +static int op0F_l_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); +} + + +const OpFn OP_TABLE(286_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(386_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(486_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(winchip_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, 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, +}; + +const 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,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, 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,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, 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,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, 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,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, 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, +}; + +const OpFn OP_TABLE(pentium_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, 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, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, 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, +}; + +const OpFn OP_TABLE(pentiummmx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, +}; + +const OpFn OP_TABLE(k6_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, +}; + +const OpFn OP_TABLE(k62_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, 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, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opSYSCALL, opCLTS, opSYSRET, 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, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, opSYSCALL, opCLTS, opSYSRET, 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, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opSYSCALL, opCLTS, opSYSRET, 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, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, +}; + +const OpFn OP_TABLE(c6x86mx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, +}; + +#ifdef DEV_BRANCH +#ifdef USE_I686 +const OpFn OP_TABLE(pentiumpro_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, +}; + +#if 0 +const OpFn OP_TABLE(pentium2_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, +}; +#endif + +const OpFn OP_TABLE(pentium2d_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,opFXSAVESTOR_a16,opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,opFXSAVESTOR_a16,opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,opFXSAVESTOR_a32,opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,opFXSAVESTOR_a32,opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; +#endif +#endif + +const OpFn OP_TABLE(286)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +}; + +const OpFn OP_TABLE(386)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, opFS_w_a16, opGS_w_a16, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_l_rmw_a16,opADD_b_rm_a16, opADD_l_rm_a16, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a16, opOR_l_rmw_a16, opOR_b_rm_a16, opOR_l_rm_a16, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a16, +/*10*/ opADC_b_rmw_a16,opADC_l_rmw_a16,opADC_b_rm_a16, opADC_l_rm_a16, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a16,opSBB_l_rmw_a16,opSBB_b_rm_a16, opSBB_l_rm_a16, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a16,opAND_l_rmw_a16,opAND_b_rm_a16, opAND_l_rm_a16, opAND_AL_imm, opAND_EAX_imm, opES_l_a16, opDAA, opSUB_b_rmw_a16,opSUB_l_rmw_a16,opSUB_b_rm_a16, opSUB_l_rm_a16, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_l_rmw_a16,opXOR_b_rm_a16, opXOR_l_rm_a16, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a16, opAAA, opCMP_b_rmw_a16,opCMP_l_rmw_a16,opCMP_b_rm_a16, opCMP_l_rm_a16, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a16, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a16, opARPL_a16, opFS_l_a16, opGS_l_a16, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a16,opPUSH_imm_bl, opIMUL_l_ib_a16,opINSB_a16, opINSL_a16, opOUTSB_a16, opOUTSL_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_l_a16, op80_a16, op83_l_a16, opTEST_b_a16, opTEST_l_a16, opXCHG_b_a16, opXCHG_l_a16, opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, opMOV_l_seg_a16,opLEA_l_a16, opMOV_seg_w_a16,opPOPL_a16, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_EAX_a16, opMOV_a16_AL, opMOV_a16_EAX, opMOVSB_a16, opMOVSL_a16, opCMPSB_a16, opCMPSL_a16, opTEST_AL, opTEST_EAX, opSTOSB_a16, opSTOSL_a16, opLODSB_a16, opLODSL_a16, opSCASB_a16, opSCASL_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a16, opC1_l_a16, opRET_l_imm, opRET_l, opLES_l_a16, opLDS_l_a16, opMOV_b_imm_a16,opMOV_l_imm_a16,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a16, opD1_l_a16, opD2_a16, opD3_l_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_l_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_l_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_w_rmw_a32,opADD_b_rm_a32, opADD_w_rm_a32, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a32, opOR_w_rmw_a32, opOR_b_rm_a32, opOR_w_rm_a32, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a32, +/*10*/ opADC_b_rmw_a32,opADC_w_rmw_a32,opADC_b_rm_a32, opADC_w_rm_a32, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a32,opSBB_w_rmw_a32,opSBB_b_rm_a32, opSBB_w_rm_a32, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a32,opAND_w_rmw_a32,opAND_b_rm_a32, opAND_w_rm_a32, opAND_AL_imm, opAND_AX_imm, opES_w_a32, opDAA, opSUB_b_rmw_a32,opSUB_w_rmw_a32,opSUB_b_rm_a32, opSUB_w_rm_a32, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_w_rmw_a32,opXOR_b_rm_a32, opXOR_w_rm_a32, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a32, opAAA, opCMP_b_rmw_a32,opCMP_w_rmw_a32,opCMP_b_rm_a32, opCMP_w_rm_a32, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a32, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a32, opARPL_a32, opFS_w_a32, opGS_w_a32, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a32,opPUSH_imm_bw, opIMUL_w_ib_a32,opINSB_a32, opINSW_a32, opOUTSB_a32, opOUTSW_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_w_a32, op80_a32, op83_w_a32, opTEST_b_a32, opTEST_w_a32, opXCHG_b_a32, opXCHG_w_a32, opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, opMOV_w_seg_a32,opLEA_w_a32, opMOV_seg_w_a32,opPOPW_a32, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_AX_a32, opMOV_a32_AL, opMOV_a32_AX, opMOVSB_a32, opMOVSW_a32, opCMPSB_a32, opCMPSW_a32, opTEST_AL, opTEST_AX, opSTOSB_a32, opSTOSW_a32, opLODSB_a32, opLODSW_a32, opSCASB_a32, opSCASW_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a32, opC1_w_a32, opRET_w_imm, opRET_w, opLES_w_a32, opLDS_w_a32, opMOV_b_imm_a32,opMOV_w_imm_a32,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a32, opD1_w_a32, opD2_a32, opD3_w_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_w_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_w_a32, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_l_rmw_a32,opADD_b_rm_a32, opADD_l_rm_a32, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a32, opOR_l_rmw_a32, opOR_b_rm_a32, opOR_l_rm_a32, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a32, +/*10*/ opADC_b_rmw_a32,opADC_l_rmw_a32,opADC_b_rm_a32, opADC_l_rm_a32, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a32,opSBB_l_rmw_a32,opSBB_b_rm_a32, opSBB_l_rm_a32, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a32,opAND_l_rmw_a32,opAND_b_rm_a32, opAND_l_rm_a32, opAND_AL_imm, opAND_EAX_imm, opES_l_a32, opDAA, opSUB_b_rmw_a32,opSUB_l_rmw_a32,opSUB_b_rm_a32, opSUB_l_rm_a32, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_l_rmw_a32,opXOR_b_rm_a32, opXOR_l_rm_a32, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a32, opAAA, opCMP_b_rmw_a32,opCMP_l_rmw_a32,opCMP_b_rm_a32, opCMP_l_rm_a32, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a32, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a32, opARPL_a32, opFS_l_a32, opGS_l_a32, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a32,opPUSH_imm_bl, opIMUL_l_ib_a32,opINSB_a32, opINSL_a32, opOUTSB_a32, opOUTSL_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_l_a32, op80_a32, op83_l_a32, opTEST_b_a32, opTEST_l_a32, opXCHG_b_a32, opXCHG_l_a32, opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, opMOV_l_seg_a32,opLEA_l_a32, opMOV_seg_w_a32,opPOPL_a32, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_EAX_a32, opMOV_a32_AL, opMOV_a32_EAX, opMOVSB_a32, opMOVSL_a32, opCMPSB_a32, opCMPSL_a32, opTEST_AL, opTEST_EAX, opSTOSB_a32, opSTOSL_a32, opLODSB_a32, opLODSL_a32, opSCASB_a32, opSCASL_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a32, opC1_l_a32, opRET_l_imm, opRET_l, opLES_l_a32, opLDS_l_a32, opMOV_b_imm_a32,opMOV_l_imm_a32,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a32, opD1_l_a32, opD2_a32, opD3_l_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, +}; + +const 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, +}; + +const 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, +}; diff --git a/src/cpu_new/808x.c b/src/cpu_new/808x.c new file mode 100644 index 000000000..266c48c63 --- /dev/null +++ b/src/cpu_new/808x.c @@ -0,0 +1,2886 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * 808x CPU emulation, mostly ported from reenigne's XTCE, which + * is cycle-accurate. + * + * Version: @(#)808x.c 1.0.9 2019/02/13 + * + * Authors: Andrew Jenner, + * Miran Grca, + * + * Copyright 2015-2019 Andrew Jenner. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../nmi.h" +#include "../pic.h" +#include "../timer.h" + +/* The opcode of the instruction currently being executed. */ +uint8_t opcode; + +/* The tables to speed up the setting of the Z, N, and P cpu_state.flags. */ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +/* A 16-bit zero, needed because some speed-up arrays contain pointers to it. */ +uint16_t zero = 0; + +/* MOD and R/M stuff. */ +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; +uint32_t rmdat; + +/* XT CPU multiplier. */ +uint64_t xt_cpu_multi; + +/* Is the CPU 8088 or 8086. */ +int is8086 = 0; + +/* Variables for handling the non-maskable interrupts. */ +int nmi = 0, nmi_auto_clear = 0; + +/* Was the CPU ever reset? */ +int x86_was_reset = 0; + +/* Amount of instructions executed - used to calculate the % shown in the title bar. */ +int ins = 0; + +/* Is the TRAP flag on? */ +int trap = 0; + +/* The current effective address's segment. */ +uint32_t easeg; + + +/* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */ +static uint8_t pfq[6]; + +/* Variables to aid with the prefetch queue operation. */ +static int biu_cycles = 0, pfq_pos = 0; + +/* The IP equivalent of the current prefetch queue position. */ +static uint16_t pfq_ip; + +/* Pointer tables needed for segment overrides. */ +static uint32_t *opseg[4]; +static x86seg *_opseg[4]; + +static int noint = 0; +static int in_lock = 0; +static int cpu_alu_op, pfq_size; + +static uint16_t cpu_src = 0, cpu_dest = 0; +static uint16_t cpu_data = 0, last_addr = 0x0000; + +static uint32_t *ovr_seg = NULL; +static int prefetching = 1, completed = 1; +static int in_rep = 0, repeating = 0; +static int oldc, clear_lock = 0; +static int refresh = 0, takeint = 0; +static int cycdiff; + + +/* Various things needed for 8087. */ +#define OP_TABLE(name) ops_ ## name + +#define CPU_BLOCK_END() +#define SEG_CHECK_READ(seg) +#define SEG_CHECK_WRITE(seg) +#define CHECK_READ(a, b, c) +#define CHECK_WRITE(a, b, c) +#define UN_USED(x) (void)(x) +#define fetch_ea_16(val) +#define fetch_ea_32(val) +#define PREFETCH_RUN(a, b, c, d, e, f, g, h) + +#define CYCLES(val) \ + { \ + wait(val, 0); \ + } + +#define CLOCK_CYCLES(val) \ + { \ + wait(val, 0); \ + } + +typedef int (*OpFn)(uint32_t fetchdat); + + +static int tempc_fpu = 0; + + +#ifdef ENABLE_808X_LOG +void dumpregs(int); + +int x808x_do_log = ENABLE_808X_LOG; +int indump = 0; + + +static void +x808x_log(const char *fmt, ...) +{ + va_list ap; + + if (x808x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} + + +void +dumpregs(int force) +{ + int c; + char *seg_names[4] = { "ES", "CS", "SS", "DS" }; + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) + return; + + x808x_log("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", + cpu_state.pc, CS, DS, ES, SS, cpu_state.flags); + x808x_log("Old CS:EIP: %04X:%08X; %i ins\n", oldcs, cpu_state.oldpc, ins); + for (c = 0; c < 4; c++) { + x808x_log("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_names[c], _opseg[c]->base, _opseg[c]->limit, + _opseg[c]->access, _opseg[c]->limit_low, _opseg[c]->limit_high); + } + if (is386) { + x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_fs, cpu_state.seg_fs.limit, cpu_state.seg_fs.access, cpu_state.seg_fs.limit_low, cpu_state.seg_fs.limit_high); + x808x_log("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); + x808x_log("GDT : base=%06X limit=%04X\n", gdt.base, gdt.limit); + x808x_log("LDT : base=%06X limit=%04X\n", ldt.base, ldt.limit); + x808x_log("IDT : base=%06X limit=%04X\n", idt.base, idt.limit); + x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + x808x_log("386 in %s mode: %i-bit data, %-i-bit stack\n", + (msw & 1) ? ((cpu_state.eflags & VM_FLAG) ? "V86" : "protected") : "real", + (use32) ? 32 : 16, (stack32) ? 32 : 16); + x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); + x808x_log("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 { + x808x_log("808x/286 in %s mode\n", (msw & 1) ? "protected" : "real"); + x808x_log("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); + } + x808x_log("Entries in readlookup : %i writelookup : %i\n", readlnum, writelnum); + x87_dumpregs(); + indump = 0; +} +#else +#define x808x_log(fmt, ...) +#endif + + +static void pfq_add(int c, int add); +static void set_pzs(int bits); + + +uint16_t +get_last_addr(void) +{ + return last_addr; +} + + +static int +irq_pending(void) +{ + uint8_t temp; + + if (takeint && !noint) + temp = 1; + else + temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint); + + takeint = (cpu_state.flags & I_FLAG) && (pic.pend &~ pic.mask); + + return temp; +} + + +static void +clock_start(void) +{ + cycdiff = cycles; +} + + +static void +clock_end(void) +{ + int diff = cycdiff - cycles; + + /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ + tsc += (uint64_t)diff * ((uint64_t)xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); +} + + +static void +fetch_and_bus(int c, int bus) +{ + if (refresh > 0) { + /* Finish the current fetch, if any. */ + cycles -= ((4 - (biu_cycles & 3)) & 3); + pfq_add((4 - (biu_cycles & 3)) & 3, 1); + /* Add 4 memory access cycles. */ + cycles -= 4; + pfq_add(4, 0); + + refresh--; + } + + pfq_add(c, !bus); + clock_end(); + clock_start(); +} + + +static void +wait(int c, int bus) +{ + cycles -= c; + + fetch_and_bus(c, bus); +} + + +/* This is for external subtraction of cycles. */ +void +sub_cycles(int c) +{ + cycles -= c; + + if (!is286) + fetch_and_bus(c, 1); +} + + +#undef readmemb +#undef readmemw +#undef readmeml +#undef readmemq + +/* Common read function. */ +static uint8_t +readmemb_common(uint32_t a) +{ + uint8_t ret; + + if (readlookup2 == NULL) + ret = readmembl(a); + else { + if (readlookup2[(a) >> 12] == ((uintptr_t) -1)) + ret = readmembl(a); + else + ret = *(uint8_t *)(readlookup2[(a) >> 12] + (a)); + } + + return ret; +} + +/* Reads a byte from the memory and advances the BIU. */ +static uint8_t +readmemb(uint32_t a) +{ + uint8_t ret; + + wait(4, 1); + ret = readmemb_common(a); + + return ret; +} + + +/* Reads a byte from the memory but does not advance the BIU. */ +static uint8_t +readmembf(uint32_t a) +{ + uint8_t ret; + + a = cs + (a & 0xffff); + ret = readmemb_common(a); + + return ret; +} + + +/* Reads a word from the memory and advances the BIU. */ +static uint16_t +readmemw_common(uint32_t s, uint16_t a) +{ + uint16_t ret; + + ret = readmemb_common(s + a); + ret |= readmemb_common(s + ((a + 1) & 0xffff)) << 8; + + return ret; +} + + +static uint16_t +readmemw(uint32_t s, uint16_t a) +{ + uint16_t ret; + + if (is8086 && !(a & 1)) + wait(4, 1); + else + wait(8, 1); + ret = readmemw_common(s, a); + + return ret; +} + + +static uint16_t +readmemwf(uint16_t a) +{ + uint16_t ret; + + ret = readmemw_common(cs, a & 0xffff); + + return ret; +} + + +static uint16_t +readmem(uint32_t s) +{ + if (opcode & 1) + return readmemw(s, cpu_state.eaaddr); + else + return (uint16_t) readmemb(s + cpu_state.eaaddr); +} + + +static uint32_t +readmeml(uint32_t s, uint16_t a) +{ + uint32_t temp; + + temp = (uint32_t) (readmemw(s, a + 2)) << 16; + temp |= readmemw(s, a); + + return temp; +} + + +static uint64_t +readmemq(uint32_t s, uint16_t a) +{ + uint64_t temp; + + temp = (uint64_t) (readmeml(s, a + 4)) << 32; + temp |= readmeml(s, a); + + return temp; +} + + +static void +writememb_common(uint32_t a, uint8_t v) +{ + if (writelookup2 == NULL) + writemembl(a, v); + else { + if (writelookup2[(a) >> 12] == ((uintptr_t) -1)) + writemembl(a, v); + else + *(uint8_t *)(writelookup2[a >> 12] + a) = v; + } + + if ((a >= 0xf0000) && (a <= 0xfffff)) + last_addr = a & 0xffff; +} + + +/* Writes a byte to the memory and advances the BIU. */ +static void +writememb(uint32_t s, uint32_t a, uint8_t v) +{ + wait(4, 1); + writememb_common(s + a, v); +} + + +/* Writes a word to the memory and advances the BIU. */ +static void +writememw(uint32_t s, uint32_t a, uint16_t v) +{ + if (is8086 && !(a & 1)) + wait(4, 1); + else + wait(8, 1); + writememb_common(s + a, v & 0xff); + writememb_common(s + ((a + 1) & 0xffff), v >> 8); +} + + +static void +writemem(uint32_t s, uint16_t v) +{ + if (opcode & 1) + return writememw(s, cpu_state.eaaddr, v); + else + return writememb(s, cpu_state.eaaddr, (uint8_t) (v & 0xff)); +} + + +static void +writememl(uint32_t s, uint32_t a, uint32_t v) +{ + writememw(s, a, v & 0xffff); + writememw(s, a + 2, v >> 16); +} + + +static void +writememq(uint32_t s, uint32_t a, uint64_t v) +{ + writememl(s, a, v & 0xffffffff); + writememl(s, a + 4, v >> 32); +} + + +static void +pfq_write(void) +{ + uint16_t tempw; + + if (is8086 && (pfq_pos < (pfq_size - 1))) { + /* The 8086 fetches 2 bytes at a time, and only if there's at least 2 bytes + free in the queue. */ + tempw = readmemwf(pfq_ip); + *(uint16_t *) &(pfq[pfq_pos]) = tempw; + pfq_ip += 2; + pfq_pos += 2; + } else if (!is8086 && (pfq_pos < pfq_size)) { + /* The 8088 fetches 1 byte at a time, and only if there's at least 1 byte + free in the queue. */ + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } +} + + +static uint8_t +pfq_read(void) +{ + uint8_t temp, i; + + temp = pfq[0]; + for (i = 0; i < (pfq_size - 1); i++) + pfq[i] = pfq[i + 1]; + pfq_pos--; + cpu_state.pc = (cpu_state.pc + 1) & 0xffff; + return temp; +} + + +/* Fetches a byte from the prefetch queue, or from memory if the queue has + been drained. */ +static uint8_t +pfq_fetchb_common(void) +{ + uint8_t temp; + + if (pfq_pos == 0) { + /* Reset prefetch queue internal position. */ + pfq_ip = cpu_state.pc; + /* Fill the queue. */ + wait(4 - (biu_cycles & 3), 0); + } + + /* Fetch. */ + temp = pfq_read(); + return temp; +} + + +static uint8_t +pfq_fetchb(void) +{ + uint8_t ret; + + ret = pfq_fetchb_common(); + wait(1, 0); + return ret; +} + + +/* Fetches a word from the prefetch queue, or from memory if the queue has + been drained. */ +static uint16_t +pfq_fetchw(void) +{ + uint16_t temp; + + temp = pfq_fetchb_common(); + wait(1, 0); + temp |= (pfq_fetchb_common() << 8); + + return temp; +} + + +static uint16_t +pfq_fetch() +{ + if (opcode & 1) + return pfq_fetchw(); + else + return (uint16_t) pfq_fetchb(); +} + + +/* Adds bytes to the prefetch queue based on the instruction's cycle count. */ +static void +pfq_add(int c, int add) +{ + int d; + + if ((c <= 0) || (pfq_pos >= pfq_size)) + return; + + for (d = 0; d < c; d++) { + biu_cycles = (biu_cycles + 1) & 0x03; + if (prefetching && add && (biu_cycles == 0x00)) + pfq_write(); + } +} + + +/* Clear the prefetch queue - called on reset and on anything that affects either CS or IP. */ +static void +pfq_clear() +{ + pfq_pos = 0; + prefetching = 0; +} + + +static void +set_ip(uint16_t new_ip) { + pfq_ip = cpu_state.pc = new_ip; + prefetching = 1; +} + + +/* Memory refresh read - called by reads and writes on DMA channel 0. */ +void +refreshread(void) { + refresh++; +} + + +/* Preparation of the various arrays needed to speed up the MOD and R/M work. */ +static void +makemod1table(void) +{ + mod1add[0][0] = &BX; + mod1add[0][1] = &BX; + mod1add[0][2] = &BP; + mod1add[0][3] = &BP; + mod1add[0][4] = &SI; + mod1add[0][5] = &DI; + mod1add[0][6] = &BP; + mod1add[0][7] = &BX; + mod1add[1][0] = &SI; + mod1add[1][1] = &DI; + mod1add[1][2] = &SI; + mod1add[1][3] = &DI; + mod1add[1][4] = &zero; + mod1add[1][5] = &zero; + mod1add[1][6] = &zero; + mod1add[1][7] = &zero; + mod1seg[0] = &ds; + mod1seg[1] = &ds; + mod1seg[2] = &ss; + mod1seg[3] = &ss; + mod1seg[4] = &ds; + mod1seg[5] = &ds; + mod1seg[6] = &ss; + mod1seg[7] = &ds; + opseg[0] = &es; + opseg[1] = &cs; + opseg[2] = &ss; + opseg[3] = &ds; + _opseg[0] = &cpu_state.seg_es; + _opseg[1] = &cpu_state.seg_cs; + _opseg[2] = &cpu_state.seg_ss; + _opseg[3] = &cpu_state.seg_ds; +} + + +static uint16_t +sign_extend(uint8_t data) +{ + return data + (data < 0x80 ? 0 : 0xff00); +} + + +/* Fetches the effective address from the prefetch queue according to MOD and R/M. */ +static void +do_mod_rm(void) +{ + rmdat = pfq_fetchb(); + cpu_reg = (rmdat >> 3) & 7; + cpu_mod = (rmdat >> 6) & 3; + cpu_rm = rmdat & 7; + + if (cpu_mod == 3) + return; + + wait(1, 0); + if ((rmdat & 0xc7) == 0x06) { + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + easeg = ovr_seg ? *ovr_seg : ds; + wait(1, 0); + return; + } else switch (cpu_rm) { + case 0: + case 3: + wait(2, 0); + break; + case 1: + case 2: + wait(3, 0); + break; + } + cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + easeg = ovr_seg ? *ovr_seg : *mod1seg[cpu_rm]; + switch (rmdat & 0xc0) { + case 0x40: + wait(3, 0); + cpu_state.eaaddr += sign_extend(pfq_fetchb()); + break; + case 0x80: + wait(3, 0); + cpu_state.eaaddr += pfq_fetchw(); + break; + } + cpu_state.eaaddr &= 0xffff; + wait(2, 0); +} + + +#undef getr8 +#define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) + +#undef setr8 +#define setr8(r,v) if (r & 4) cpu_state.regs[r & 3].b.h = v; \ + else cpu_state.regs[r & 3].b.l = v; + + +/* Reads a byte from the effective address. */ +static uint8_t +geteab(void) +{ + if (cpu_mod == 3) + return (getr8(cpu_rm)); + + return readmemb(easeg + cpu_state.eaaddr); +} + + +/* Reads a word from the effective address. */ +static uint16_t +geteaw(void) +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + + return readmemw(easeg, cpu_state.eaaddr); +} + + +/* Neede for 8087 - memory only. */ +static uint32_t +geteal(void) +{ + if (cpu_mod == 3) { + fatal("808x register geteal()\n"); + return 0xffffffff; + } + + return readmeml(easeg, cpu_state.eaaddr); +} + + +/* Neede for 8087 - memory only. */ +static uint64_t +geteaq(void) +{ + if (cpu_mod == 3) { + fatal("808x register geteaq()\n"); + return 0xffffffff; + } + + return readmemq(easeg, cpu_state.eaaddr); +} + + +static void +read_ea(int memory_only, int bits) +{ + if (cpu_mod != 3) { + if (bits == 16) + cpu_data = readmemw(easeg, cpu_state.eaaddr); + else + cpu_data = readmemb(easeg + cpu_state.eaaddr); + return; + } + if (!memory_only) { + if (bits == 8) { + cpu_data = getr8(cpu_rm); + } else + cpu_data = cpu_state.regs[cpu_rm].w; + } +} + + +static void +read_ea2(int bits) +{ + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + if (bits == 16) + cpu_data = readmemw(easeg, cpu_state.eaaddr); + else + cpu_data = readmemb(easeg + cpu_state.eaaddr); +} + + +/* Writes a byte to the effective address. */ +static void +seteab(uint8_t val) +{ + if (cpu_mod == 3) { + setr8(cpu_rm, val); + } else + writememb(easeg, cpu_state.eaaddr, val); +} + + +/* Writes a word to the effective address. */ +static void +seteaw(uint16_t val) +{ + if (cpu_mod == 3) + cpu_state.regs[cpu_rm].w = val; + else + writememw(easeg, cpu_state.eaaddr, val); +} + + +static void +seteal(uint32_t val) +{ + if (cpu_mod == 3) { + fatal("808x register seteal()\n"); + return; + } else + writememl(easeg, cpu_state.eaaddr, val); +} + + +static void +seteaq(uint64_t val) +{ + if (cpu_mod == 3) { + fatal("808x register seteaq()\n"); + return; + } else + writememq(easeg, cpu_state.eaaddr, val); +} + + +/* Leave out the 686 stuff as it's not needed and + complicates compiling. */ +#define FPU_8087 +#define tempc tempc_fpu +#include "x87.h" +#include "x87_ops.h" +#undef tempc +#undef FPU_8087 + + +/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P cpu_state.flags. */ +static void +makeznptable(void) +{ + int c, d, e; + for (c = 0; c < 256; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable8[c] = 0; + else + znptable8[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); +#endif + if (!c) + znptable8[c] |= Z_FLAG; + if (c & 0x80) + znptable8[c] |= N_FLAG; + } + + for (c = 0; c < 65536; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable16[c] = 0; + else + znptable16[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) + x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); +#endif + if (!c) + znptable16[c] |= Z_FLAG; + if (c & 0x8000) + znptable16[c] |= N_FLAG; + } +} + + +/* Common reset function. */ +static void +reset_common(int hard) +{ + biu_cycles = 0; + in_rep = 0; + in_lock = 0; + completed = 1; + repeating = 0; + clear_lock = 0; + refresh = 0; + + if (hard) { +#ifdef ENABLE_808X_LOG + x808x_log("x86 reset\n"); +#endif + ins = 0; + } + use32 = 0; + cpu_cur_status = 0; + stack32 = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw = 0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + if (isibmcpu) + cpu_cache_int_enabled = 1; + else + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + cpu_state.eflags = 0; + cgate32 = 0; + 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; + idt.limit = is386 ? 0x03FF : 0xFFFF; + cpu_state.flags = 2; + trap = 0; + ovr_seg = NULL; + in_lock = 0; + + EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; + + if (hard) { + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + pfq_clear(); + cpu_set_edx(); + mmu_perm = 4; + pfq_size = (is8086) ? 6 : 4; + } + x86seg_reset(); +#ifdef USE_DYNAREC + if (hard) + codegen_reset(); +#endif + if (!hard) + flushmmucache(); + x86_was_reset = 1; + cpu_alt_reset = 0; + + prefetching = 1; + takeint = 0; +} + + +/* Hard reset. */ +void +resetx86(void) +{ + reset_common(1); +} + + +/* Soft reset. */ +void +softresetx86(void) +{ + reset_common(0); +} + + +/* Pushes a word to the stack. */ +static void +push(uint16_t *val) +{ + SP -= 2; + cpu_state.eaaddr = (SP & 0xffff); + writememw(ss, cpu_state.eaaddr, *val); +} + + +/* Pops a word from the stack. */ +static uint16_t +pop(void) +{ + cpu_state.eaaddr = (SP & 0xffff); + SP += 2; + return readmemw(ss, cpu_state.eaaddr); +} + + +static void +access(int num, int bits) +{ + switch (num) { + case 0: case 61: case 63: case 64: + case 67: case 69: case 71: case 72: + default: + break; + case 1: case 6: case 7: case 8: + case 9: case 17: case 20: case 21: + case 24: case 28: case 47: case 48: + case 49: case 50: case 51: case 55: + case 56: case 62: case 66: case 68: + wait(1, 0); + break; + case 3: case 11: case 15: case 22: + case 23: case 25: case 26: case 35: + case 44: case 45: case 46: case 52: + case 53: case 54: + wait(2, 0); + break; + case 16: case 18: case 19: case 27: + case 32: case 37: case 42: + wait(3, 0); + break; + case 10: case 12: case 13: case 14: + case 29: case 30: case 33: case 34: + case 39: case 41: case 60: + wait(4, 0); + break; + case 4: case 70: + wait(5, 0); + break; + case 31: case 38: case 40: + wait(6, 0); + break; + case 5: + if (opcode == 0xcc) + wait(7, 0); + else + wait(4, 0); + break; + case 36: + wait(1, 0); + pfq_clear(); + wait (1, 0); + if (cpu_mod != 3) + wait(1, 0); + wait(3, 0); + break; + case 43: + wait(2, 0); + pfq_clear(); + wait(1, 0); + break; + case 57: + if (cpu_mod != 3) + wait(2, 0); + wait(4, 0); + break; + case 58: + if (cpu_mod != 3) + wait(1, 0); + wait(4, 0); + break; + case 59: + wait(2, 0); + pfq_clear(); + if (cpu_mod != 3) + wait(1, 0); + wait(3, 0); + break; + case 65: + wait(1, 0); + pfq_clear(); + wait(2, 0); + if (cpu_mod != 3) + wait(1, 0); + break; + } +} + + +/* Calls an interrupt. */ +static void +interrupt(uint16_t addr) +{ + uint16_t old_cs, old_ip; + uint16_t new_cs, new_ip; + uint16_t tempf; + + addr <<= 2; + cpu_state.eaaddr = addr; + old_cs = CS; + access(5, 16); + new_ip = readmemw(0, cpu_state.eaaddr); + wait(1, 0); + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + access(6, 16); + new_cs = readmemw(0, cpu_state.eaaddr); + pfq_clear(); + access(39, 16); + tempf = cpu_state.flags & 0x0fd7; + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); + access(40, 16); + push(&old_cs); + old_ip = cpu_state.pc; + loadcs(new_cs); + access(68, 16); + set_ip(new_ip); + access(41, 16); + push(&old_ip); +} + + +static void +check_interrupts(void) +{ + int temp; + + if (irq_pending()) { + if ((cpu_state.flags & T_FLAG) && !noint) { + interrupt(1); + return; + } + if (nmi && nmi_enable && nmi_mask) { + nmi_enable = 0; + interrupt(2); + return; + } + temp = picinterrupt(); + if (temp != -1) { + repeating = 0; + completed = 1; + ovr_seg = NULL; + in_lock = 0; + clear_lock = 0; + ovr_seg = NULL; + wait(9, 0); + interrupt((uint16_t) (temp & 0xffff)); + } + } +} + + +static int +rep_action(int bits) +{ + uint16_t t; + + if (in_rep == 0) + return 0; + wait(2, 0); + t = CX; + if (irq_pending() && (repeating != 0)) { + access(71, bits); + pfq_clear(); + set_ip(cpu_state.pc - 2); + t = 0; + } + if (t == 0) { + wait(1, 0); + completed = 1; + repeating = 0; + return 1; + } + --CX; + completed = 0; + wait(2, 0); + if (!repeating) + wait(2, 0); + return 0; +} + + +static uint16_t +jump(uint16_t delta) +{ + uint16_t old_ip; + access(67, 8); + pfq_clear(); + wait(5, 0); + old_ip = cpu_state.pc; + set_ip((cpu_state.pc + delta) & 0xffff); + return old_ip; +} + + +static void +jump_short(void) +{ + jump(sign_extend((uint8_t) cpu_data)); +} + + +static uint16_t +jump_near(void) +{ + return jump(pfq_fetchw()); +} + + +/* Performs a conditional jump. */ +static void +jcc(uint8_t opcode, int cond) +{ + /* int8_t offset; */ + + wait(1, 0); + cpu_data = pfq_fetchb(); + wait(1, 0); + if ((!cond) == (opcode & 0x01)) + jump_short(); +} + + +static void +set_cf(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~C_FLAG) | (cond ? C_FLAG : 0); +} + + +static void +set_if(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~I_FLAG) | (cond ? I_FLAG : 0); +} + + +static void +set_df(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~D_FLAG) | (cond ? D_FLAG : 0); +} + + +static void +bitwise(int bits, uint16_t data) +{ + cpu_data = data; + cpu_state.flags &= ~(C_FLAG | A_FLAG | V_FLAG); + set_pzs(bits); +} + + +static void +test(int bits, uint16_t dest, uint16_t src) +{ + cpu_dest = dest; + cpu_src = src; + bitwise(bits, (cpu_dest & cpu_src)); +} + + +static void +set_of(int of) +{ + cpu_state.flags = (cpu_state.flags & ~0x800) | (of ? 0x800 : 0); +} + + +static int +top_bit(uint16_t w, int bits) +{ + if (bits == 16) + return ((w & 0x8000) != 0); + else + return ((w & 0x80) != 0); +} + + +static void +set_of_add(int bits) +{ + set_of(top_bit((cpu_data ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_of_sub(int bits) +{ + set_of(top_bit((cpu_dest ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_af(int af) +{ + cpu_state.flags = (cpu_state.flags & ~0x10) | (af ? 0x10 : 0); +} + + +static void +do_af(void) +{ + set_af(((cpu_data ^ cpu_src ^ cpu_dest) & 0x10) != 0); +} + + +static void +set_apzs(int bits) +{ + set_pzs(bits); + do_af(); +} + + +static void +add(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest + cpu_src; + set_apzs(bits); + set_of_add(bits); + + /* Anything - FF with carry on is basically anything + 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 2) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) + cpu_state.flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_data & size_mask)); +} + + +static void +sub(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest - cpu_src; + set_apzs(bits); + set_of_sub(bits); + + /* Anything - FF with carry on is basically anything - 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 3) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) + cpu_state.flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_dest & size_mask)); +} + + +static void +alu_op(int bits) +{ + switch(cpu_alu_op) { + case 1: + bitwise(bits, (cpu_dest | cpu_src)); + break; + case 2: + if (cpu_state.flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 0: + add(bits); + break; + case 3: + if (cpu_state.flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 5: case 7: + sub(bits); + break; + case 4: + test(bits, cpu_dest, cpu_src); + break; + case 6: + bitwise(bits, (cpu_dest ^ cpu_src)); + break; + } +} + + +static void +set_sf(int bits) +{ + cpu_state.flags = (cpu_state.flags & ~0x80) | (top_bit(cpu_data, bits) ? 0x80 : 0); +} + + +static void +set_pf(void) +{ + static uint8_t table[0x100] = { + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4}; + + cpu_state.flags = (cpu_state.flags & ~4) | table[cpu_data & 0xff]; +} + + +static void +mul(uint16_t a, uint16_t b) +{ + int negate = 0; + int bit_count = 8; + int carry, i; + uint16_t high_bit = 0x80; + uint16_t size_mask; + uint16_t c, r; + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd5) { + if (opcode & 1) { + bit_count = 16; + high_bit = 0x8000; + } else + wait(8, 0); + + size_mask = (1 << bit_count) - 1; + + if ((rmdat & 0x38) == 0x28) { + if (!top_bit(a, bit_count)) { + if (top_bit(b, bit_count)) { + wait(1, 0); + if ((b & size_mask) != ((opcode & 1) ? 0x8000 : 0x80)) + wait(1, 0); + b = ~b + 1; + negate = 1; + } + } else { + wait(1, 0); + a = ~a + 1; + negate = 1; + if (top_bit(b, bit_count)) { + b = ~b + 1; + negate = 0; + } else + wait(4, 0); + } + wait(10, 0); + } + wait(3, 0); + } + + c = 0; + a &= size_mask; + carry = (a & 1) != 0; + a >>= 1; + for (i = 0; i < bit_count; ++i) { + wait(7, 0); + if (carry) { + cpu_src = c; + cpu_dest = b; + add(bit_count); + c = cpu_data & size_mask; + wait(1, 0); + carry = !!(cpu_state.flags & C_FLAG); + } + r = (c >> 1) + (carry ? high_bit : 0); + carry = (c & 1) != 0; + c = r; + r = (a >> 1) + (carry ? high_bit : 0); + carry = (a & 1) != 0; + a = r; + } + if (negate) { + c = ~c; + a = (~a + 1) & size_mask; + if (a == 0) + ++c; + wait(9, 0); + } + cpu_data = a; + cpu_dest = c; + + set_sf(bit_count); + set_pf(); +} + + +static void +set_of_rotate(int bits) +{ + set_of(top_bit(cpu_data ^ cpu_dest, bits)); +} + + +static void +set_zf(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_state.flags = (cpu_state.flags & ~0x40) | (((cpu_data & size_mask) == 0) ? 0x40 : 0); +} + + +static void +set_pzs(int bits) +{ + set_pf(); + set_zf(bits); + set_sf(bits); +} + + +static void +set_co_mul(int carry) +{ + set_cf(carry); + set_of(carry); + if (!carry) + wait(1, 0); +} + + +/* Was div(), renamed to avoid conflicts with stdlib div(). */ +static int +x86_div(uint16_t l, uint16_t h) +{ + int b, bit_count = 8; + int negative = 0; + int dividend_negative = 0; + int size_mask, carry; + uint16_t r; + + if (opcode & 1) { + l = AX; + h = DX; + bit_count = 16; + } + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd4) { + if ((rmdat & 0x38) == 0x38) { + if (top_bit(h, bit_count)) { + h = ~h; + l = (~l + 1) & size_mask; + if (l == 0) + ++h; + h &= size_mask; + negative = 1; + dividend_negative = 1; + wait(4, 0); + } + if (top_bit(cpu_src, bit_count)) { + cpu_src = ~cpu_src + 1; + negative = !negative; + } else + wait(1, 0); + wait(9, 0); + } + wait(3, 0); + } + wait(8, 0); + cpu_src &= size_mask; + if (h >= cpu_src) { + if (opcode != 0xd4) + wait(1, 0); + interrupt(0); + return 0; + } + if (opcode != 0xd4) + wait(1, 0); + wait(2, 0); + carry = 1; + for (b = 0; b < bit_count; ++b) { + r = (l << 1) + (carry ? 1 : 0); + carry = top_bit(l, bit_count); + l = r; + r = (h << 1) + (carry ? 1 : 0); + carry = top_bit(h, bit_count); + h = r; + wait(8, 0); + if (carry) { + carry = 0; + h -= cpu_src; + if (b == bit_count - 1) + wait(2, 0); + } else { + carry = cpu_src > h; + if (!carry) { + h -= cpu_src; + wait(1, 0); + if (b == bit_count - 1) + wait(2, 0); + } + } + } + l = ~((l << 1) + (carry ? 1 : 0)); + if (opcode != 0xd4 && (rmdat & 0x38) == 0x38) { + wait(4, 0); + if (top_bit(l, bit_count)) { + if (cpu_mod == 3) + wait(1, 0); + interrupt(0); + return 0; + } + wait(7, 0); + if (negative) + l = ~l + 1; + if (dividend_negative) + h = ~h + 1; + } + if (opcode == 0xd4) { + AL = h & 0xff; + AH = l & 0xff; + } else { + AH = h & 0xff; + AL = l & 0xff; + if (opcode & 1) { + DX = h; + AX = l; + } + } + return 1; +} + + +static uint16_t +string_increment(int bits) +{ + int d = bits >> 3; + if (cpu_state.flags & D_FLAG) + cpu_state.eaaddr -= d; + else + cpu_state.eaaddr += d; + cpu_state.eaaddr &= 0xffff; + return cpu_state.eaaddr; +} + + +static void +lods(int bits) +{ + cpu_state.eaaddr = SI; + if (bits == 16) + cpu_data = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); + else + cpu_data = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); + SI = string_increment(bits); +} + + +static void +stos(int bits) +{ + cpu_state.eaaddr = DI; + if (bits == 16) + writememw(es, cpu_state.eaaddr, cpu_data); + else + writememb(es, cpu_state.eaaddr, (uint8_t) (cpu_data & 0xff)); + DI = string_increment(bits); +} + + +static void +da(void) +{ + set_pzs(8); + wait(2, 0); +} + + +static void +aa(void) +{ + set_of(0); + AL &= 0x0f; + wait(6, 0); +} + + +static void +set_ca(void) +{ + set_cf(1); + set_af(1); +} + + +static void +clear_ca(void) +{ + set_cf(0); + set_af(0); +} + + +static uint16_t +get_ea(void) +{ + if (opcode & 1) + return geteaw(); + else + return (uint16_t) geteab(); +} + + +static uint16_t +get_reg(uint8_t reg) +{ + if (opcode & 1) + return cpu_state.regs[reg].w; + else + return (uint16_t) getr8(reg); +} + + +static void +set_ea(uint16_t val) +{ + if (opcode & 1) + seteaw(val); + else + seteab((uint8_t) (val & 0xff)); +} + + +static void +set_reg(uint8_t reg, uint16_t val) +{ + if (opcode & 1) + cpu_state.regs[reg].w = val; + else + setr8(reg, (uint8_t) (val & 0xff)); +} + + +static void +cpu_data_opff_rm(void) { + if (!(opcode & 1)) { + if (cpu_mod != 3) + cpu_data |= 0xff00; + else + cpu_data = cpu_state.regs[cpu_rm].w; + } +} + + +/* Executes instructions up to the specified number of cycles. */ +void +execx86(int cycs) +{ + uint8_t temp = 0, temp2; + uint16_t addr, tempw; + uint16_t new_cs, new_ip; + int bits; + + cycles += cycs; + + while (cycles > 0) { + clock_start(); + + if (!repeating) { + cpu_state.oldpc = cpu_state.pc; + opcode = pfq_fetchb(); + oldc = cpu_state.flags & C_FLAG; + if (clear_lock) { + in_lock = 0; + clear_lock = 0; + } + wait(1, 0); + } + + completed = 1; + switch (opcode) { + case 0x06: case 0x0E: case 0x16: case 0x1E: /* PUSH seg */ + access(29, 16); + push(&(_opseg[(opcode >> 3) & 0x03]->seg)); + break; + case 0x07: case 0x0F: case 0x17: case 0x1F: /* POP seg */ + access(22, 16); + if (opcode == 0x0F) { + loadcs(pop()); + pfq_pos = 0; + } else + loadseg(pop(), _opseg[(opcode >> 3) & 0x03]); + wait(1, 0); + /* All POP segment instructions suppress interrupts for one instruction. */ + noint = 1; + break; + + case 0x26: /*ES:*/ + case 0x2E: /*CS:*/ + case 0x36: /*SS:*/ + case 0x3E: /*DS:*/ + wait(1, 0); + ovr_seg = opseg[(opcode >> 3) & 0x03]; + completed = 0; + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x38: case 0x39: case 0x3a: case 0x3b: + /* alu rm, r / r, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(46, bits); + tempw = get_ea(); + cpu_alu_op = (opcode >> 3) & 7; + if ((opcode & 2) == 0) { + cpu_dest = tempw; + cpu_src = get_reg(cpu_reg); + } else { + cpu_dest = get_reg(cpu_reg); + cpu_src = tempw; + } + if (cpu_mod != 3) + wait(2, 0); + wait(1, 0); + alu_op(bits); + if (cpu_alu_op != 7) { + if ((opcode & 2) == 0) { + access(10, bits); + set_ea(cpu_data); + if (cpu_mod == 3) + wait(1, 0); + } else { + set_reg(cpu_reg, cpu_data); + wait(1, 0); + } + } else + wait(1, 0); + break; + + case 0x04: case 0x05: case 0x0c: case 0x0d: + case 0x14: case 0x15: case 0x1c: case 0x1d: + case 0x24: case 0x25: case 0x2c: case 0x2d: + case 0x34: case 0x35: case 0x3c: case 0x3d: + /* alu A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_data = pfq_fetch(); + cpu_dest = get_reg(0); /* AX/AL */ + cpu_src = cpu_data; + cpu_alu_op = (opcode >> 3) & 7; + alu_op(bits); + if (cpu_alu_op != 7) + set_reg(0, cpu_data); + wait(1, 0); + break; + + case 0x27: /*DAA*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || (AL & 0x0f) > 9) { + cpu_data = AL + 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((cpu_state.flags & C_FLAG) || AL > 0x9f) { + AL += 0x60; + set_cf(1); + } + da(); + break; + case 0x2F: /*DAS*/ + wait(1, 0); + temp = AL; + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_data = AL - 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((cpu_state.flags & C_FLAG) || temp > 0x9f) { + AL -= 0x60; + set_cf(1); + } + da(); + break; + case 0x37: /*AAA*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL += 6; + ++AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); + break; + case 0x3F: /*AAS*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL -= 6; + --AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4A: case 0x4B: + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + /* INCDEC rw */ + wait(1, 0); + cpu_dest = cpu_state.regs[opcode & 7].w; + cpu_src = 1; + bits = 16; + if ((opcode & 8) == 0) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(16); + cpu_state.regs[opcode & 7].w = cpu_data; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + access(30, 16); + push(&(cpu_state.regs[opcode & 0x07].w)); + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + access(23, 16); + cpu_state.regs[opcode & 0x07].w = pop(); + wait(1, 0); + break; + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + jcc(opcode, cpu_state.flags & V_FLAG); + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + jcc(opcode, cpu_state.flags & C_FLAG); + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + jcc(opcode, cpu_state.flags & Z_FLAG); + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + jcc(opcode, cpu_state.flags & (C_FLAG | Z_FLAG)); + break; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + jcc(opcode, cpu_state.flags & N_FLAG); + break; + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + jcc(opcode, cpu_state.flags & P_FLAG); + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, temp ^ temp2); + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, (cpu_state.flags & Z_FLAG) || (temp != temp2)); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + /* alu rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(47, bits); + cpu_data = get_ea(); + cpu_dest = cpu_data; + if (cpu_mod != 3) + wait(3, 0); + if (opcode == 0x81) { + if (cpu_mod == 3) + wait(1, 0); + cpu_src = pfq_fetchw(); + } else { + if (cpu_mod == 3) + wait(1, 0); + if (opcode == 0x83) + cpu_src = sign_extend(pfq_fetchb()); + else + cpu_src = pfq_fetchb() | 0xff00; + } + wait(1, 0); + cpu_alu_op = (rmdat & 0x38) >> 3; + alu_op(bits); + if (cpu_alu_op != 7) { + access(11, bits); + set_ea(cpu_data); + } else { + if (cpu_mod != 3) + wait(1, 0); + } + break; + + case 0x84: case 0x85: + /* TEST rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(48, bits); + cpu_data = get_ea(); + test(bits, cpu_data, get_reg(cpu_reg)); + if (cpu_mod == 3) + wait(2, 0); + wait(2, 0); + break; + case 0x86: case 0x87: + /* XCHG rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(49, bits); + cpu_data = get_ea(); + cpu_src = get_reg(cpu_reg); + set_reg(cpu_reg, cpu_data); + wait(3, 0); + access(12, bits); + set_ea(cpu_src); + break; + + case 0x88: case 0x89: + /* MOV rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + access(13, bits); + set_ea(get_reg(cpu_reg)); + break; + case 0x8A: case 0x8B: + /* MOV reg, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(50, bits); + set_reg(cpu_reg, get_ea()); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0x8C: /*MOV w,sreg*/ + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(14, 16); + seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); + break; + + case 0x8D: /*LEA*/ + do_mod_rm(); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0x8E: /*MOV sreg,w*/ + do_mod_rm(); + access(51, 16); + tempw = geteaw(); + if ((rmdat & 0x18) == 0x08) { + loadcs(tempw); + pfq_pos = 0; + } else + loadseg(tempw, _opseg[(rmdat & 0x18) >> 3]); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + if (((rmdat & 0x18) >> 3) == 2) + noint = 1; + break; + + case 0x8F: /*POPW*/ + do_mod_rm(); + wait(1, 0); + cpu_src = cpu_state.eaaddr; + access(24, 16); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pop(); + cpu_state.eaaddr = cpu_src; + wait(2, 0); + access(15, 16); + seteaw(cpu_data); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + /* XCHG AX, rw */ + wait(1, 0); + cpu_data = cpu_state.regs[opcode & 7].w; + cpu_state.regs[opcode & 7].w = AX; + AX = cpu_data; + wait(1, 0); + break; + + case 0x98: /*CBW*/ + wait(1, 0); + AX = sign_extend(AL); + break; + case 0x99: /*CWD*/ + wait(4, 0); + if (!top_bit(AX, 16)) + DX = 0; + else { + wait(1, 0); + DX = 0xffff; + } + break; + case 0x9A: /*CALL FAR*/ + wait(1, 0); + new_ip = pfq_fetchw(); + wait(1, 0); + new_cs = pfq_fetchw(); + pfq_clear(); + access(31, 16); + push(&(CS)); + access(60, 16); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + set_ip(new_ip); + access(32, 16); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x9B: /*WAIT*/ + if (!repeating) + wait(2, 0); + wait(5, 0); +#ifdef NO_HACK + if (irq_pending()) { + wait(7, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } +#else + wait(7, 0); + check_interrupts(); +#endif + break; + case 0x9C: /*PUSHF*/ + access(33, 16); + tempw = (cpu_state.flags & 0x0fd7) | 0xf000; + push(&tempw); + break; + case 0x9D: /*POPF*/ + access(25, 16); + cpu_state.flags = pop() | 2; + wait(1, 0); + break; + case 0x9E: /*SAHF*/ + wait(1, 0); + cpu_state.flags = (cpu_state.flags & 0xff02) | AH; + wait(2, 0); + break; + case 0x9F: /*LAHF*/ + wait(1, 0); + AH = cpu_state.flags & 0xd7; + break; + + case 0xA0: case 0xA1: + /* MOV A, [iw] */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(1, bits); + set_reg(0, readmem((ovr_seg ? *ovr_seg : ds))); + wait(1, 0); + break; + case 0xA2: case 0xA3: + /* MOV [iw], A */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(7, bits); + writemem((ovr_seg ? *ovr_seg : ds), get_reg(0)); + break; + + case 0xA4: case 0xA5: /* MOVS */ + case 0xAC: case 0xAD: /* LODS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1, 0); + if ((opcode & 8) == 0 && in_rep != 0) + wait(1, 0); + } + if (rep_action(bits)) { + wait(1, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + if (in_rep != 0 && (opcode & 8) != 0) + wait(1, 0); + access(20, bits); + lods(bits); + if ((opcode & 8) == 0) { + access(27, bits); + stos(bits); + } else { + set_reg(0, cpu_data); + if (in_rep != 0) + wait(2, 0); + } + if (in_rep == 0) { + wait(3, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xA6: case 0xA7: /* CMPS */ + case 0xAE: case 0xAF: /* SCAS */ + bits = 8 << (opcode & 1); + if (!repeating) + wait(1, 0); + if (rep_action(bits)) { + wait(2, 0); + break; + } + if (in_rep != 0) + wait(1, 0); + wait(1, 0); + cpu_dest = get_reg(0); + if ((opcode & 8) == 0) { + access(21, bits); + lods(bits); + wait(1, 0); + cpu_dest = cpu_data; + } + access(2, bits); + cpu_state.eaaddr = DI; + cpu_data = readmem(es); + DI = string_increment(bits); + cpu_src = cpu_data; + sub(bits); + wait(2, 0); + if (in_rep == 0) { + wait(3, 0); + break; + } + if ((!!(cpu_state.flags & Z_FLAG)) == (in_rep == 1)) { + completed = 1; + wait(4, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xA8: case 0xA9: + /* TEST A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_data = pfq_fetch(); + test(bits, get_reg(0), cpu_data); + wait(1, 0); + break; + + case 0xAA: case 0xAB: /* STOS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1, 0); + if (in_rep != 0) + wait(1, 0); + } + if (rep_action(bits)) { + wait(1, 0); + break; + } + cpu_data = AX; + access(28, bits); + stos(bits); + if (in_rep == 0) { + wait(3, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xB0: case 0xB1: case 0xB2: case 0xB3: /*MOV cpu_reg,#8*/ + case 0xB4: case 0xB5: case 0xB6: case 0xB7: + wait(1, 0); + if (opcode & 0x04) + cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); + else + cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); + wait(1, 0); + break; + + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + wait(1, 0); + cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); + wait(1, 0); + break; + + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + /* RET */ + bits = 8 + (opcode & 0x08); + if ((opcode & 9) != 1) + wait(1, 0); + if (!(opcode & 1)) { + cpu_src = pfq_fetchw(); + wait(1, 0); + } + if ((opcode & 9) == 9) + wait(1, 0); + pfq_clear(); + access(26, bits); + new_ip = pop(); + wait(2, 0); + if ((opcode & 8) == 0) + new_cs = CS; + else { + access(42, bits); + new_cs = pop(); + if (opcode & 1) + wait(1, 0); + } + if (!(opcode & 1)) { + SP += cpu_src; + wait(1, 0); + } + loadcs(new_cs); + access(72, bits); + set_ip(new_ip); + break; + + case 0xC4: case 0xC5: + /* LsS rw, rmd */ + do_mod_rm(); + bits = 16; + access(52, bits); + read_ea(1, bits); + cpu_state.regs[cpu_reg].w = cpu_data; + access(57, bits); + read_ea2(bits); + loadseg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); + wait(1, 0); + break; + + case 0xC6: case 0xC7: + /* MOV rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pfq_fetch(); + if (cpu_mod == 3) + wait(1, 0); + access(16, bits); + set_ea(cpu_data); + break; + + case 0xCC: /*INT 3*/ + interrupt(3); + break; + case 0xCD: /*INT*/ + wait(1, 0); + interrupt(pfq_fetchb()); + break; + case 0xCE: /*INTO*/ + wait(3, 0); + if (cpu_state.flags & V_FLAG) { + wait(2, 0); + interrupt(4); + } + break; + + case 0xCF: /*IRET*/ + access(43, 8); + new_ip = pop(); + wait(3, 0); + access(44, 8); + new_cs = pop(); + loadcs(new_cs); + access(62, 8); + set_ip(new_ip); + access(45, 8); + cpu_state.flags = pop() | 2; + wait(5, 0); + noint = 1; + nmi_enable = 1; + break; + + case 0xD0: case 0xD1: case 0xD2: case 0xD3: + /* rot rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(53, bits); + cpu_data = get_ea(); + if ((opcode & 2) == 0) { + cpu_src = 1; + wait((cpu_mod != 3) ? 4 : 0, 0); + } else { + cpu_src = CL; + wait((cpu_mod != 3) ? 9 : 6, 0); + } + while (cpu_src != 0) { + cpu_dest = cpu_data; + oldc = cpu_state.flags & C_FLAG; + switch (rmdat & 0x38) { + case 0x00: /* ROL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0); + set_of_rotate(bits); + break; + case 0x08: /* ROR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (cpu_state.flags & C_FLAG) + cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); + set_of_rotate(bits); + break; + case 0x10: /* RCL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); + set_of_rotate(bits); + break; + case 0x18: /* RCR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (oldc) + cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); + set_cf((cpu_dest & 1) != 0); + set_of_rotate(bits); + break; + case 0x20: /* SHL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + set_of_rotate(bits); + set_pzs(bits); + break; + case 0x28: /* SHR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + break; + case 0x30: /* SETMO - undocumented? */ + bitwise(bits, 0xffff); + set_cf(0); + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + case 0x38: /* SAR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (!(opcode & 1)) + cpu_data |= (cpu_dest & 0x80); + else + cpu_data |= (cpu_dest & 0x8000); + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + break; + } + if ((opcode & 2) != 0) + wait(4, 0); + --cpu_src; + } + access(17, bits); + set_ea(cpu_data); + break; + + case 0xD4: /*AAM*/ + wait(1, 0); + cpu_src = pfq_fetchb(); + if (x86_div(AL, 0)) + set_pzs(16); + break; + case 0xD5: /*AAD*/ + wait(1, 0); + mul(pfq_fetchb(), AH); + AL += cpu_data; + AH = 0x00; + set_pzs(16); + break; + case 0xD6: /*SALC*/ + wait(1, 0); + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; + wait(1, 0); + break; + case 0xD7: /*XLATB*/ + cpu_state.eaaddr = (BX + AL) & 0xffff; + access(4, 8); + AL = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); + wait(1, 0); + break; + + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDD: case 0xDC: case 0xDE: case 0xDF: + /* esc i, r, rm */ + do_mod_rm(); + access(54, 16); + tempw = cpu_state.pc; + if (!hasfpu) + geteaw(); + else switch(opcode) { + case 0xD8: + ops_fpu_8087_d8[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); + break; + case 0xD9: + ops_fpu_8087_d9[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDA: + ops_fpu_8087_da[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDB: + ops_fpu_8087_db[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDC: + ops_fpu_8087_dc[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); + break; + case 0xDD: + ops_fpu_8087_dd[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDE: + ops_fpu_8087_de[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDF: + ops_fpu_8087_df[rmdat & 0xff]((uint32_t) rmdat); + break; + } + cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on + the 286+ core, but not here. */ + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0xE0: case 0xE1: case 0xE2: case 0xE3: + /* LOOP */ + wait(3, 0); + cpu_data = pfq_fetchb(); + if (opcode != 0xe2) + wait(1, 0); + if (opcode != 0xe3) { + --CX; + oldc = (CX != 0); + switch (opcode) { + case 0xE0: + if (cpu_state.flags & Z_FLAG) + oldc = 0; + break; + case 0xE1: + if (!(cpu_state.flags & Z_FLAG)) + oldc = 0; + break; + } + } else + oldc = (CX == 0); + if (oldc) + jump_short(); + break; + + case 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xEC: case 0xED: case 0xEE: case 0xEF: + bits = 8 << (opcode & 1); + if ((opcode & 0x0e) != 0x0c) + wait(1, 0); + if ((opcode & 8) == 0) + cpu_data = pfq_fetchb(); + else + cpu_data = DX; + cpu_state.eaaddr = cpu_data; + if ((opcode & 2) == 0) { + access(3, bits); + if ((opcode & 1) && is8086 && !(cpu_data & 1)) { + AX = inw(cpu_data); + wait(4, 1); /* I/O access and wait state. */ + } else { + AL = inb(cpu_data); + if (opcode & 1) + AH = inb(cpu_data + 1); + wait(bits >> 1, 1); /* I/O access. */ + } + wait(1, 0); + } else { + if ((opcode & 8) == 0) + access(8, bits); + else + access(9, bits); + if ((opcode & 1) && is8086 && !(cpu_data & 1)) { + outw(cpu_data, AX); + wait(4, 1); + } else { + outb(cpu_data, AL); + if (opcode & 1) + outb(cpu_data + 1, AH); + wait(bits >> 1, 1); /* I/O access. */ + } + } + break; + + case 0xE8: /*CALL rel 16*/ + wait(1, 0); + cpu_state.oldpc = jump_near(); + access(34, 8); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0xE9: /*JMP rel 16*/ + wait(1, 0); + jump_near(); + break; + case 0xEA: /*JMP far*/ + wait(1, 0); + addr = pfq_fetchw(); + wait(1, 0); + tempw = pfq_fetchw(); + loadcs(tempw); + access(70, 8); + pfq_clear(); + set_ip(addr); + break; + case 0xEB: /*JMP rel*/ + wait(1, 0); + cpu_data = (int8_t) pfq_fetchb(); + jump_short(); + wait(1, 0); + break; + + case 0xF0: case 0xF1: /*LOCK - F1 is alias*/ + in_lock = 1; + wait(1, 0); + completed = 0; + break; + + case 0xF2: /*REPNE*/ + case 0xF3: /*REPE*/ + wait(1, 0); + in_rep = (opcode == 0xf2 ? 1 : 2); + completed = 0; + break; + + case 0xF4: /*HLT*/ + if (!repeating) { + wait(1, 0); + pfq_clear(); + } + wait(1, 0); + if (irq_pending()) { + wait(cycles & 1, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } + break; + case 0xF5: /*CMC*/ + wait(1, 0); + cpu_state.flags ^= C_FLAG; + break; + + case 0xF6: case 0xF7: + bits = 8 << (opcode & 1); + do_mod_rm(); + access(55, bits); + cpu_data = get_ea(); + switch (rmdat & 0x38) { + case 0x00: case 0x08: + /* TEST */ + wait(2, 0); + if (cpu_mod != 3) + wait(1, 0); + cpu_src = pfq_fetch(); + wait(1, 0); + test(bits, cpu_data, cpu_src); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x10: /* NOT */ + case 0x18: /* NEG */ + wait(2, 0); + if ((rmdat & 0x38) == 0x10) + cpu_data = ~cpu_data; + else { + cpu_src = cpu_data; + cpu_dest = 0; + sub(bits); + } + access(18, bits); + set_ea(cpu_data); + break; + case 0x20: /* MUL */ + case 0x28: /* IMUL */ + wait(1, 0); + if (opcode & 1) { + mul(AX, cpu_data); + AX = cpu_data; + DX = cpu_dest; + cpu_data |= DX; + set_co_mul(DX != ((AX & 0x8000) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); + } else { + mul(AL, cpu_data); + AL = (uint8_t) cpu_data; + AH = (uint8_t) cpu_dest; + cpu_data |= AH; + set_co_mul(AH != ((AL & 0x80) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xff)); + } + /* NOTE: When implementing the V20, care should be taken to not change + the zero flag. */ + set_zf(bits); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x30: /* DIV */ + case 0x38: /* IDIV */ + if (cpu_mod != 3) + wait(1, 0); + cpu_src = cpu_data; + if (x86_div(AL, AH)) + wait(1, 0); + break; + } + break; + + case 0xF8: case 0xF9: + /* CLCSTC */ + wait(1, 0); + set_cf(opcode & 1); + break; + case 0xFA: case 0xFB: + /* CLISTI */ + wait(1, 0); + set_if(opcode & 1); + break; + case 0xFC: case 0xFD: + /* CLDSTD */ + wait(1, 0); + set_df(opcode & 1); + break; + + case 0xFE: case 0xFF: + /* misc */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(56, bits); + read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); + switch (rmdat & 0x38) { + case 0x00: /* INC rm */ + case 0x08: /* DEC rm */ + cpu_dest = cpu_data; + cpu_src = 1; + if ((rmdat & 0x38) == 0x00) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(bits); + wait(2, 0); + access(19, bits); + set_ea(cpu_data); + break; + case 0x10: /* CALL rm */ + cpu_data_opff_rm(); + access(63, bits); + wait(1, 0); + pfq_clear(); + wait(4, 0); + if (cpu_mod != 3) + wait(1, 0); + wait(1, 0); /* Wait. */ + cpu_state.oldpc = cpu_state.pc; + set_ip(cpu_data); + wait(2, 0); + access(35, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x18: /* CALL rmd */ + new_ip = cpu_data; + access(58, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + access(36, bits); + push(&(CS)); + access(64, bits); + wait(4, 0); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + set_ip(new_ip); + access(37, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x20: /* JMP rm */ + cpu_data_opff_rm(); + access(65, bits); + set_ip(cpu_data); + break; + case 0x28: /* JMP rmd */ + new_ip = cpu_data; + access(59, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + loadcs(new_cs); + access(66, bits); + set_ip(new_ip); + break; + case 0x30: /* PUSH rm */ + case 0x38: + if (cpu_mod != 3) + wait(1, 0); + access(38, bits); + push(&(cpu_data)); + break; + } + break; + + default: + x808x_log("Illegal opcode: %02X\n", opcode); + pfq_fetchb(); + wait(8, 0); + break; + } + + if (completed) { + repeating = 0; + ovr_seg = NULL; + in_rep = 0; + if (in_lock) + clear_lock = 1; + clock_end(); + check_interrupts(); + + if (noint) + noint = 0; + } + + ins++; + } +} diff --git a/src/cpu_new/codegen.c b/src/cpu_new/codegen.c new file mode 100644 index 000000000..243f61791 --- /dev/null +++ b/src/cpu_new/codegen.c @@ -0,0 +1,772 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86_ops.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, 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) +{ + codegen_timing_start = timing->start; + codegen_timing_prefix = timing->prefix; + codegen_timing_opcode = timing->opcode; + codegen_timing_block_start = timing->block_start; + codegen_timing_block_end = timing->block_end; + 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; + 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, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /*a0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ + + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/ + 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ +}; + +void codegen_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 = (OpFn *) 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 = (OpFn *) 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) ? (OpFn *) x86_dynarec_opcodes_d8_a32 : (OpFn *) 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) ? (OpFn *) x86_dynarec_opcodes_d9_a32 : (OpFn *) 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) ? (OpFn *) x86_dynarec_opcodes_da_a32 : (OpFn *) 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) ? (OpFn *) x86_dynarec_opcodes_db_a32 : (OpFn *) 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) ? (OpFn *) x86_dynarec_opcodes_dc_a32 : (OpFn *) 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) ? (OpFn *) x86_dynarec_opcodes_dd_a32 : (OpFn *) 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) ? (OpFn *) x86_dynarec_opcodes_de_a32 : (OpFn *) 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) ? (OpFn *) x86_dynarec_opcodes_df_a32 : (OpFn *) 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 = (OpFn *) x86_dynarec_opcodes_REPNE; + recomp_op_table = NULL;//recomp_opcodes_REPNE; + break; + case 0xf3: /*REPE*/ +#ifdef DEBUG_EXTRA + last_prefix = 0xf3; +#endif + op_table = (OpFn *) 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); + if (recomp_opcodes_3DNOW[opcode_3dnow]) + { + next_pc = opcode_pc + 1; + + op_table = (OpFn *) 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); + /* It is apparently a prefixed instruction. */ + 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 = (OpFn *) 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); + } + 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); + } + 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/cpu_new/codegen.h b/src/cpu_new/codegen.h new file mode 100644 index 000000000..d4f2563f6 --- /dev/null +++ b/src/cpu_new/codegen.h @@ -0,0 +1,414 @@ +#ifndef _CODEGEN_H_ +#define _CODEGEN_H_ + +#include "mem.h" +#include "x86_ops.h" + +/*Handling self-modifying code (of which there is a lot on x86) : + + PCem tracks a 'dirty mask' for each physical page, in which each bit + represents 64 bytes. This is only tracked for pages that have code in - when a + page first has a codeblock generated, it is evicted from the writelookup and + added to the page_lookup for this purpose. When in the page_lookup, each write + will go through the mem_write_ram*_page() functions and set the dirty mask + appropriately. + + Each codeblock also contains a code mask (actually two masks, one for each + page the block is/may be in), again with each bit representing 64 bytes. + + Each page has a list of codeblocks present in it. As each codeblock can span + up to two pages, two lists are present. + + When a codeblock is about to be executed, the code masks are compared with the + dirty masks for the relevant pages. If either intersect, then + codegen_check_flush() is called on the affected page(s), and all affected + blocks are evicted. + + The 64 byte granularity appears to work reasonably well for most cases, + avoiding most unnecessary evictions (eg when code & data are stored in the + same page). +*/ + +typedef struct codeblock_t +{ + 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.*/ + 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; + uint64_t a = _cs | ((uint64_t)phys << 32); + + if (!pages[phys >> 12].head) + return NULL; + + block = &codeblock[pages[phys >> 12].head]; + while (block) + { + 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 ? &codeblock[block->right] : NULL; + } + + return block; +} + +static inline void codeblock_tree_add(codeblock_t *new_block) +{ + codeblock_t *block = &codeblock[pages[new_block->phys >> 12].head]; + uint64_t a = new_block->_cs | ((uint64_t)new_block->phys << 32); + + if (!pages[new_block->phys >> 12].head) + { + 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; + 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 ? &codeblock[block->right] : NULL; + } + + if (a < old_block_cmp) + old_block->left = get_block_nr(new_block); + else + old_block->right = get_block_nr(new_block); + + 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) +{ + 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 = BLOCK_INVALID; + else + { + 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_nr) + { + pages[block->phys >> 12].head = block->right; + codeblock[pages[block->phys >> 12].head].parent = BLOCK_INVALID; + } + else + { + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) + { + parent->left = block->right; + codeblock[parent->left].parent = parent_nr; + } + if (parent->right == block_nr) + { + parent->right = block->right; + codeblock[parent->right].parent = parent_nr; + } + } + return; + } + else if (!block->right) + { + /*Only left node*/ + if (!parent_nr) + { + pages[block->phys >> 12].head = block->left; + codeblock[pages[block->phys >> 12].head].parent = BLOCK_INVALID; + } + else + { + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) + { + parent->left = block->left; + codeblock[parent->left].parent = parent_nr; + } + if (parent->right == block_nr) + { + parent->right = block->left; + codeblock[parent->right].parent = parent_nr; + } + } + return; + } + else + { + /*Difficult case - node has two children. Walk right child to find lowest node*/ + codeblock_t *lowest = &codeblock[block->right], *highest; + codeblock_t *old_parent; + uint16_t lowest_nr; + + while (lowest->left) + lowest = &codeblock[lowest->left]; + lowest_nr = get_block_nr(lowest); + + old_parent = &codeblock[lowest->parent]; + + /*Replace deleted node with lowest node*/ + if (!parent_nr) + pages[block->phys >> 12].head = lowest_nr; + else + { + 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_nr; + lowest->left = block->left; + if (lowest->left) + codeblock[lowest->left].parent = lowest_nr; + + old_parent->left = BLOCK_INVALID; + + highest = &codeblock[lowest->right]; + if (!lowest->right) + { + if (lowest_nr != block->right) + { + lowest->right = block->right; + codeblock[block->right].parent = lowest_nr; + } + return; + } + + while (highest->right) + highest = &codeblock[highest->right]; + + if (block->right && block->right != lowest_nr) + { + highest->right = block->right; + codeblock[block->right].parent = get_block_nr(highest); + } + } +} + +#define PAGE_MASK_MASK 63 +#define PAGE_MASK_SHIFT 6 + +void codegen_mark_code_present_multibyte(codeblock_t *block, uint32_t start_pc, int len); + +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; + +extern int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks; +extern int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; +extern int cpu_recomp_flushes, cpu_recomp_flushes_latched; +extern int cpu_recomp_evicted, cpu_recomp_evicted_latched; +extern int cpu_recomp_reuse, cpu_recomp_reuse_latched; +extern int cpu_recomp_removed, cpu_recomp_removed_latched; + +extern int cpu_reps, cpu_reps_latched; +extern int cpu_notreps, cpu_notreps_latched; + +extern int codegen_block_cycles; + +extern void (*codegen_timing_start)(); +extern void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, 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, 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_k6; + +void codegen_timing_set(codegen_timing_t *timing); + +extern int block_current; +extern int block_pos; + +#define CPU_BLOCK_END() cpu_block_end = 1 + +/*Current physical page of block being recompiled. -1 if no recompilation taking place */ +extern uint32_t recomp_page; + +extern x86seg *op_ea_seg; +extern int op_ssegs; +extern uint32_t op_old_pc; + +/*Set to 1 if flags have been changed in the block being recompiled, and hence + flags_op is known and can be relied on */ +extern int codegen_flags_changed; + +extern int codegen_fpu_entered; +extern int codegen_mmx_entered; + +extern int codegen_fpu_loaded_iq[8]; +extern int codegen_reg_loaded[8]; + +extern int codegen_in_recompile; + +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/cpu_new/codegen_accumulate.c b/src/cpu_new/codegen_accumulate.c new file mode 100644 index 000000000..c9b85ba78 --- /dev/null +++ b/src/cpu_new/codegen_accumulate.c @@ -0,0 +1,46 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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) +{ + 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) + { + 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/cpu_new/codegen_accumulate.h b/src/cpu_new/codegen_accumulate.h new file mode 100644 index 000000000..55d7c8eba --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_allocator.c b/src/cpu_new/codegen_allocator.c new file mode 100644 index 000000000..b78c4df12 --- /dev/null +++ b/src/cpu_new/codegen_allocator.c @@ -0,0 +1,125 @@ +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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); +#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]); + } + + /*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++; + 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; + + while (1) + { + int next_block_nr = block->next; + 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/cpu_new/codegen_allocator.h b/src/cpu_new/codegen_allocator.h new file mode 100644 index 000000000..90fa1c0b6 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend.h b/src/cpu_new/codegen_backend.h new file mode 100644 index 000000000..89beeee1c --- /dev/null +++ b/src/cpu_new/codegen_backend.h @@ -0,0 +1,41 @@ +#ifndef _CODEGEN_BACKEND_H_ +#define _CODEGEN_BACKEND_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/cpu_new/codegen_backend_arm.c b/src/cpu_new/codegen_backend_arm.c new file mode 100644 index 000000000..ddabbb5c5 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm.c @@ -0,0 +1,370 @@ +#ifdef __ARM_EABI__ + +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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; + + 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/cpu_new/codegen_backend_arm.h b/src/cpu_new/codegen_backend_arm.h new file mode 100644 index 000000000..87dc2d8a0 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_arm64.c b/src/cpu_new/codegen_backend_arm64.c new file mode 100644 index 000000000..32489000f --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64.c @@ -0,0 +1,384 @@ +#ifdef __aarch64__ + +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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; + } + + 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/cpu_new/codegen_backend_arm64.h b/src/cpu_new/codegen_backend_arm64.h new file mode 100644 index 000000000..b4888d38e --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_arm64_defs.h b/src/cpu_new/codegen_backend_arm64_defs.h new file mode 100644 index 000000000..dabfe8ae8 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_arm64_imm.c b/src/cpu_new/codegen_backend_arm64_imm.c new file mode 100644 index 000000000..0362b71d6 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_arm64_ops.c b/src/cpu_new/codegen_backend_arm64_ops.c new file mode 100644 index 000000000..44cf87647 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64_ops.c @@ -0,0 +1,1386 @@ +#ifdef __aarch64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_backend_arm64_ops.h b/src/cpu_new/codegen_backend_arm64_ops.h new file mode 100644 index 000000000..2a514edbe --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_arm64_uops.c b/src/cpu_new/codegen_backend_arm64_uops.c new file mode 100644 index 000000000..e9cf28684 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64_uops.c @@ -0,0 +1,3372 @@ +#ifdef __aarch64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_backend_arm_defs.h b/src/cpu_new/codegen_backend_arm_defs.h new file mode 100644 index 000000000..74567998a --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_arm_ops.c b/src/cpu_new/codegen_backend_arm_ops.c new file mode 100644 index 000000000..1b2ef28f3 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm_ops.c @@ -0,0 +1,1274 @@ +#ifdef __ARM_EABI__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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; + 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; + *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/cpu_new/codegen_backend_arm_ops.h b/src/cpu_new/codegen_backend_arm_ops.h new file mode 100644 index 000000000..7627f51a7 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_arm_uops.c b/src/cpu_new/codegen_backend_arm_uops.c new file mode 100644 index 000000000..1dbaab407 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm_uops.c @@ -0,0 +1,3502 @@ +#ifdef __ARM_EABI__ + +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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; + 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; + *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/cpu_new/codegen_backend_x86-64.c b/src/cpu_new/codegen_backend_x86-64.c new file mode 100644 index 000000000..4615aa381 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64.c @@ -0,0 +1,391 @@ +#ifdef __amd64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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 +#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; +#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; + + 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, (uintptr_t)x86gpf); */ + 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/cpu_new/codegen_backend_x86-64.h b/src/cpu_new/codegen_backend_x86-64.h new file mode 100644 index 000000000..70e953a6b --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64.h @@ -0,0 +1,12 @@ +#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 diff --git a/src/cpu_new/codegen_backend_x86-64_defs.h b/src/cpu_new/codegen_backend_x86-64_defs.h new file mode 100644 index 000000000..a21f62902 --- /dev/null +++ b/src/cpu_new/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_XMM7 + +#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/cpu_new/codegen_backend_x86-64_ops.c b/src/cpu_new/codegen_backend_x86-64_ops.c new file mode 100644 index 000000000..74173e626 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_ops.c @@ -0,0 +1,1787 @@ +#ifdef __amd64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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_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_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 >= -80 || 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/cpu_new/codegen_backend_x86-64_ops.h b/src/cpu_new/codegen_backend_x86-64_ops.h new file mode 100644 index 000000000..62a9ba203 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_ops.h @@ -0,0 +1,193 @@ +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_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_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/cpu_new/codegen_backend_x86-64_ops_helpers.h b/src/cpu_new/codegen_backend_x86-64_ops_helpers.h new file mode 100644 index 000000000..a7755d1a8 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_x86-64_ops_sse.c b/src/cpu_new/codegen_backend_x86-64_ops_sse.c new file mode 100644 index 000000000..b8177648e --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_ops_sse.c @@ -0,0 +1,618 @@ +#ifdef __amd64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_backend_x86-64_ops_sse.h b/src/cpu_new/codegen_backend_x86-64_ops_sse.h new file mode 100644 index 000000000..76bb5ae7f --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_x86-64_uops.c b/src/cpu_new/codegen_backend_x86-64_uops.c new file mode 100644 index 000000000..bff4e3775 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_uops.c @@ -0,0 +1,3148 @@ +#ifdef __amd64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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); + /* int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); */ + +#ifdef RECOMPILER_DEBUG + 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); + /* int src_size = IREG_GET_SIZE(uop->src_reg_a_real); */ + +#ifdef RECOMPILER_DEBUG + 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); + /* int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); */ + +#ifdef RECOMPILER_DEBUG + 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); + /* int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); */ + +#ifdef RECOMPILER_DEBUG + 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); + /* int src_size = IREG_GET_SIZE(uop->src_reg_c_real); */ + +#ifdef RECOMPILER_DEBUG + 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); + /* int src_size = IREG_GET_SIZE(uop->src_reg_c_real); */ + +#ifdef RECOMPILER_DEBUG + 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)/*, 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_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_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_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)/*, 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_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); +} + +#endif diff --git a/src/cpu_new/codegen_backend_x86.c b/src/cpu_new/codegen_backend_x86.c new file mode 100644 index 000000000..d83d99af0 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86.c @@ -0,0 +1,351 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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 + 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; + + 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/cpu_new/codegen_backend_x86.h b/src/cpu_new/codegen_backend_x86.h new file mode 100644 index 000000000..a5aec727c --- /dev/null +++ b/src/cpu_new/codegen_backend_x86.h @@ -0,0 +1,12 @@ +#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 diff --git a/src/cpu_new/codegen_backend_x86_defs.h b/src/cpu_new/codegen_backend_x86_defs.h new file mode 100644 index 000000000..25964ba3c --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_x86_ops.c b/src/cpu_new/codegen_backend_x86_ops.c new file mode 100644 index 000000000..18f0171a5 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops.c @@ -0,0 +1,1295 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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_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_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 >= -80 || 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/cpu_new/codegen_backend_x86_ops.h b/src/cpu_new/codegen_backend_x86_ops.h new file mode 100644 index 000000000..294b42236 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops.h @@ -0,0 +1,192 @@ +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_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_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/cpu_new/codegen_backend_x86_ops_fpu.c b/src/cpu_new/codegen_backend_x86_ops_fpu.c new file mode 100644 index 000000000..dd1e658fb --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops_fpu.c @@ -0,0 +1,84 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_backend_x86_ops_fpu.h b/src/cpu_new/codegen_backend_x86_ops_fpu.h new file mode 100644 index 000000000..e4479ae72 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_x86_ops_helpers.h b/src/cpu_new/codegen_backend_x86_ops_helpers.h new file mode 100644 index 000000000..3fca4f4d2 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_x86_ops_sse.c b/src/cpu_new/codegen_backend_x86_ops_sse.c new file mode 100644 index 000000000..641d16532 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops_sse.c @@ -0,0 +1,578 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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 >= -80 || 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/cpu_new/codegen_backend_x86_ops_sse.h b/src/cpu_new/codegen_backend_x86_ops_sse.h new file mode 100644 index 000000000..0c895a605 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_backend_x86_uops.c b/src/cpu_new/codegen_backend_x86_uops.c new file mode 100644 index 000000000..679a7b77b --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_uops.c @@ -0,0 +1,3141 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_ops.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" + +#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_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_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); +} + +#endif diff --git a/src/cpu_new/codegen_block.c b/src/cpu_new/codegen_block.c new file mode 100644 index 000000000..acff96a92 --- /dev/null +++ b/src/cpu_new/codegen_block.c @@ -0,0 +1,862 @@ +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.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) +{ + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("block_free_list_add: block=%p in dirty list\n", block); + 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; +} + +static void block_dirty_list_add(codeblock_t *block) +{ + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("block_dirty_list_add: block=%p already in dirty list\n", block); + 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); + } + 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; + 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]; + + 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"); + + block_dirty_list_tail = evict_block->prev; + codeblock[evict_block->prev].next = BLOCK_INVALID; + + dirty_list_size--; + evict_block->flags &= ~CODEBLOCK_IN_DIRTY_LIST; + delete_dirty_block(evict_block); + } +} + +static void block_dirty_list_remove(codeblock_t *block) +{ + codeblock_t *prev_block = &codeblock[block->prev]; + codeblock_t *next_block = &codeblock[block->next]; + + if (!(block->flags & CODEBLOCK_IN_DIRTY_LIST)) + fatal("block_dirty_list_remove: block=%p not in dirty list\n", block); + + /*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--; + if (dirty_list_size < 0) + fatal("remove - dirty_list_size < 0!\n"); + block->flags &= ~CODEBLOCK_IN_DIRTY_LIST; +} + +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) + { + if (dirty_list_size <= 0) + fatal("get - dirty_list_size <= 0!\n"); + + /*Reuse oldest block*/ + block = &codeblock[block_dirty_list_tail]; + + 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; + block->next = 0; + 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); + + if (!block->page_mask) + fatal("add_to_block_list - mask = 0 %llx %llx\n", block->page_mask,block->page_mask2); + + 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) + { + 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); + } + + 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; + } + } +} + +static void remove_from_block_list(codeblock_t *block, uint32_t pc) +{ + if (!block->page_mask) + return; + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("remove_from_block_list: in dirty list\n"); + + 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)) + { + if (block->prev_2 || block->next_2) + fatal("Invalid block_2 %x %p %08x\n", block->flags, block, block->phys); + return; + } + block->flags &= ~CODEBLOCK_HAS_PAGE2; + + 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 + { + 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; + + 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"); + + 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; + + if (block->pc == BLOCK_PC_INVALID) + fatal("Deleting deleted block\n"); + 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; + + if (block->pc == BLOCK_PC_INVALID) + fatal("Deleting deleted block\n"); + 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) + { + invalidate_block(block); + cpu_recomp_evicted++; + } + if (block_nr == next_block) + fatal("Broken 1\n"); + 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) + { + invalidate_block(block); + cpu_recomp_evicted++; + } + if (block_nr == next_block) + fatal("Broken 2\n"); + 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(); + if (!block) + fatal("codegen_block_init: block_free_list_get() returned NULL\n"); + 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; + block->status = cpu_cur_status; + + recomp_page = block->phys & ~0xfff; + 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; + + if (block->pc != cs + cpu_state.pc || (block->flags & CODEBLOCK_WAS_RECOMPILED)) + fatal("Recompile to used block!\n"); + + 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; + + 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; + + 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); + + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { + if (codeblock[block->next_2].pc == BLOCK_PC_INVALID) + fatal("block->next_2->pc=BLOCK_PC_INVALID %p\n", (void *)&codeblock[block->next_2]); + } + } + 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; + } + } + + 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; + + if (block->flags & CODEBLOCK_BYTE_MASK) + fatal("codegen_block_generate_end_mask2() - BYTE_MASK\n"); + + 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; + + for (; start_pc <= end_pc; start_pc++) + { + block->page_mask |= ((uint64_t)1 << start_pc); + } + + 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); + + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { + if (codeblock[block->next_2].pc == BLOCK_PC_INVALID) + fatal("block->next_2->pc=BLOCK_PC_INVALID %p\n", (void *)&codeblock[block->next_2]); + } + + 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; + } + } + + 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); + + 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/cpu_new/codegen_ir.c b/src/cpu_new/codegen_ir.c new file mode 100644 index 000000000..7d305737b --- /dev/null +++ b/src/cpu_new/codegen_ir.c @@ -0,0 +1,188 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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; + + 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); + + 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; + for (c = codegen_unroll_start; c < unroll_end; 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]; + + 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; + + 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); + } + } + + if (!uop_handlers[uop->type & UOP_MASK]) + fatal("!uop_handlers[uop->type & UOP_MASK] %08x\n", uop->type); + 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/cpu_new/codegen_ir.h b/src/cpu_new/codegen_ir.h new file mode 100644 index 000000000..60e75cfc9 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ir_defs.h b/src/cpu_new/codegen_ir_defs.h new file mode 100644 index 000000000..9d6c0e69d --- /dev/null +++ b/src/cpu_new/codegen_ir_defs.h @@ -0,0 +1,810 @@ +#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) + +#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_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); + +#endif diff --git a/src/cpu_new/codegen_ops.c b/src/cpu_new/codegen_ops.c new file mode 100644 index 000000000..c1c6e54e7 --- /dev/null +++ b/src/cpu_new/codegen_ops.c @@ -0,0 +1,522 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_3dnow.h" +#include "codegen_ops_arith.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_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" + +RecompOpFn recomp_opcodes[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropADD_b_rmw, ropADD_w_rmw, ropADD_b_rm, ropADD_w_rm, ropADD_AL_imm, ropADD_AX_imm, ropPUSH_ES_16, 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*/ 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_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_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_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*/ 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*/ 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_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_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_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*/ 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, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 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, +}; + +RecompOpFn recomp_opcodes_d8[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, +}; + +RecompOpFn recomp_opcodes_d9[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 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, 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, 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, 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*/ 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, 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, 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, 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, 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*/ 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*/ 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*/ 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, 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*/ 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*/ 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*/ 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, 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, +}; + +RecompOpFn recomp_opcodes_db[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_dc[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, +}; + +RecompOpFn recomp_opcodes_dd[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 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, 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, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, + +/*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*/ 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*/ 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, 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, 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, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, + +/*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*/ 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*/ 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*/ 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*/ 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, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 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*/ 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*/ 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, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, +}; + +RecompOpFn recomp_opcodes_df[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; diff --git a/src/cpu_new/codegen_ops.h b/src/cpu_new/codegen_ops.h new file mode 100644 index 000000000..361479b6d --- /dev/null +++ b/src/cpu_new/codegen_ops.h @@ -0,0 +1,49 @@ +#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]; +extern RecompOpFn recomp_opcodes_db[512]; +extern RecompOpFn recomp_opcodes_dc[512]; +extern RecompOpFn recomp_opcodes_dd[512]; +extern RecompOpFn recomp_opcodes_de[512]; +extern RecompOpFn recomp_opcodes_df[512]; +/*extern RecompOpFn recomp_opcodes_REPE[512]; +extern RecompOpFn recomp_opcodes_REPNE[512];*/ + +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 +#define REG_AX 0 +#define REG_CX 1 +#define REG_DX 2 +#define REG_BX 3 +#define REG_SP 4 +#define REG_BP 5 +#define REG_SI 6 +#define REG_DI 7 +#define REG_AL 0 +#define REG_AH 4 +#define REG_CL 1 +#define REG_CH 5 +#define REG_DL 2 +#define REG_DH 6 +#define REG_BL 3 +#define REG_BH 7 + +#endif diff --git a/src/cpu_new/codegen_ops_3dnow.c b/src/cpu_new/codegen_ops_3dnow.c new file mode 100644 index 000000000..2406fe8e0 --- /dev/null +++ b/src/cpu_new/codegen_ops_3dnow.c @@ -0,0 +1,211 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_3dnow.h b/src/cpu_new/codegen_ops_3dnow.h new file mode 100644 index 000000000..0b44a0e18 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_arith.c b/src/cpu_new/codegen_ops_arith.c new file mode 100644 index 000000000..70eddd4a9 --- /dev/null +++ b/src/cpu_new/codegen_ops_arith.c @@ -0,0 +1,2520 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_arith.h b/src/cpu_new/codegen_ops_arith.h new file mode 100644 index 000000000..d1bbaa75d --- /dev/null +++ b/src/cpu_new/codegen_ops_arith.h @@ -0,0 +1,64 @@ +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); + +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); + +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); + +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); + +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); + +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); + + +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); + +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); + +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/cpu_new/codegen_ops_branch.c b/src/cpu_new/codegen_ops_branch.c new file mode 100644 index 000000000..5bea31781 --- /dev/null +++ b/src/cpu_new/codegen_ops_branch.c @@ -0,0 +1,1014 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_branch.h b/src/cpu_new/codegen_ops_branch.h new file mode 100644 index 000000000..3a5007125 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_fpu_arith.c b/src/cpu_new/codegen_ops_fpu_arith.c new file mode 100644 index 000000000..3f5621c3c --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_arith.c @@ -0,0 +1,575 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_fpu_arith.h b/src/cpu_new/codegen_ops_fpu_arith.h new file mode 100644 index 000000000..01c41ae32 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_fpu_constant.c b/src/cpu_new/codegen_ops_fpu_constant.c new file mode 100644 index 000000000..bca268ee3 --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_constant.c @@ -0,0 +1,36 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_fpu_constant.h b/src/cpu_new/codegen_ops_fpu_constant.h new file mode 100644 index 000000000..4be90f5fe --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_fpu_loadstore.c b/src/cpu_new/codegen_ops_fpu_loadstore.c new file mode 100644 index 000000000..599ab800e --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_loadstore.c @@ -0,0 +1,234 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_fpu_loadstore.h b/src/cpu_new/codegen_ops_fpu_loadstore.h new file mode 100644 index 000000000..a29124560 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_fpu_misc.c b/src/cpu_new/codegen_ops_fpu_misc.c new file mode 100644 index 000000000..7de92a39c --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_misc.c @@ -0,0 +1,114 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_fpu_misc.h b/src/cpu_new/codegen_ops_fpu_misc.h new file mode 100644 index 000000000..4aa49907f --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_helpers.c b/src/cpu_new/codegen_ops_helpers.c new file mode 100644 index 000000000..9fc754e6c --- /dev/null +++ b/src/cpu_new/codegen_ops_helpers.c @@ -0,0 +1,75 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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) + { + 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/cpu_new/codegen_ops_helpers.h b/src/cpu_new/codegen_ops_helpers.h new file mode 100644 index 000000000..41ffe297f --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_jump.c b/src/cpu_new/codegen_ops_jump.c new file mode 100644 index 000000000..4363c9040 --- /dev/null +++ b/src/cpu_new/codegen_ops_jump.c @@ -0,0 +1,292 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_jump.h b/src/cpu_new/codegen_ops_jump.h new file mode 100644 index 000000000..31a544721 --- /dev/null +++ b/src/cpu_new/codegen_ops_jump.h @@ -0,0 +1,21 @@ +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); + +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); + +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); + +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); + +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); + +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); + +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/cpu_new/codegen_ops_logic.c b/src/cpu_new/codegen_ops_logic.c new file mode 100644 index 000000000..87607ab2d --- /dev/null +++ b/src/cpu_new/codegen_ops_logic.c @@ -0,0 +1,807 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_logic.h b/src/cpu_new/codegen_ops_logic.h new file mode 100644 index 000000000..dd020676e --- /dev/null +++ b/src/cpu_new/codegen_ops_logic.h @@ -0,0 +1,36 @@ +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); + +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); + +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); + +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/cpu_new/codegen_ops_misc.c b/src/cpu_new/codegen_ops_misc.c new file mode 100644 index 000000000..3896e7ebc --- /dev/null +++ b/src/cpu_new/codegen_ops_misc.c @@ -0,0 +1,614 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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_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, cpu_state.oldpc); + uop_CALL_FUNC(ir, loadcsjmp); + uop_MOVZX(ir, IREG_pc, src_reg); + 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_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, cpu_state.oldpc); + uop_CALL_FUNC(ir, loadcsjmp); + uop_MOV(ir, IREG_pc, src_reg); + 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/cpu_new/codegen_ops_misc.h b/src/cpu_new/codegen_ops_misc.h new file mode 100644 index 000000000..d335e2a05 --- /dev/null +++ b/src/cpu_new/codegen_ops_misc.h @@ -0,0 +1,37 @@ +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); + +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); + +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); + +uint32_t ropNOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t 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); +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); + +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); + +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); + +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); + +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/cpu_new/codegen_ops_mmx_arith.c b/src/cpu_new/codegen_ops_mmx_arith.c new file mode 100644 index 000000000..6b42273fa --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_arith.c @@ -0,0 +1,60 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_mmx_arith.h b/src/cpu_new/codegen_ops_mmx_arith.h new file mode 100644 index 000000000..2ac0acd83 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_mmx_cmp.c b/src/cpu_new/codegen_ops_mmx_cmp.c new file mode 100644 index 000000000..649e8550f --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_cmp.c @@ -0,0 +1,47 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_mmx_cmp.h b/src/cpu_new/codegen_ops_mmx_cmp.h new file mode 100644 index 000000000..8f25cded4 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_mmx_loadstore.c b/src/cpu_new/codegen_ops_mmx_loadstore.c new file mode 100644 index 000000000..37ab3199a --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_loadstore.c @@ -0,0 +1,113 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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; + + 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/cpu_new/codegen_ops_mmx_loadstore.h b/src/cpu_new/codegen_ops_mmx_loadstore.h new file mode 100644 index 000000000..1a2d4b032 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_mmx_logic.c b/src/cpu_new/codegen_ops_mmx_logic.c new file mode 100644 index 000000000..4a554b238 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_logic.c @@ -0,0 +1,111 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_mmx_logic.h b/src/cpu_new/codegen_ops_mmx_logic.h new file mode 100644 index 000000000..4295c6c14 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_mmx_pack.c b/src/cpu_new/codegen_ops_mmx_pack.c new file mode 100644 index 000000000..6e9616271 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_pack.c @@ -0,0 +1,50 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_mmx_pack.h b/src/cpu_new/codegen_ops_mmx_pack.h new file mode 100644 index 000000000..351940d6b --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_mmx_shift.c b/src/cpu_new/codegen_ops_mmx_shift.c new file mode 100644 index 000000000..014001d53 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_shift.c @@ -0,0 +1,96 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_mmx_shift.h b/src/cpu_new/codegen_ops_mmx_shift.h new file mode 100644 index 000000000..31ef9be6d --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_ops_mov.c b/src/cpu_new/codegen_ops_mov.c new file mode 100644 index 000000000..87d7bc8bb --- /dev/null +++ b/src/cpu_new/codegen_ops_mov.c @@ -0,0 +1,773 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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; + + 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/cpu_new/codegen_ops_mov.h b/src/cpu_new/codegen_ops_mov.h new file mode 100644 index 000000000..c6bf57460 --- /dev/null +++ b/src/cpu_new/codegen_ops_mov.h @@ -0,0 +1,43 @@ +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); + +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); + +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); + +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); + +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); + +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); + +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); + +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); + +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); + +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/cpu_new/codegen_ops_shift.c b/src/cpu_new/codegen_ops_shift.c new file mode 100644 index 000000000..2d0b760d2 --- /dev/null +++ b/src/cpu_new/codegen_ops_shift.c @@ -0,0 +1,1138 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_shift.h b/src/cpu_new/codegen_ops_shift.h new file mode 100644 index 000000000..72166ad8f --- /dev/null +++ b/src/cpu_new/codegen_ops_shift.h @@ -0,0 +1,16 @@ +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); + +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); + +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); + +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/cpu_new/codegen_ops_stack.c b/src/cpu_new/codegen_ops_stack.c new file mode 100644 index 000000000..28b346446 --- /dev/null +++ b/src/cpu_new/codegen_ops_stack.c @@ -0,0 +1,412 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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/cpu_new/codegen_ops_stack.h b/src/cpu_new/codegen_ops_stack.h new file mode 100644 index 000000000..dbbbd372b --- /dev/null +++ b/src/cpu_new/codegen_ops_stack.h @@ -0,0 +1,49 @@ +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); + +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); + +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); + +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); + +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); + +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); + +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); + +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); + +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); + +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); + +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); + +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/cpu_new/codegen_reg.c b/src/cpu_new/codegen_reg.c new file mode 100644 index 000000000..70b654998 --- /dev/null +++ b/src/cpu_new/codegen_reg.c @@ -0,0 +1,767 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_WORD !REG_INTEGER\n"); + 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, (int)(uintptr_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: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_DWORD !REG_INTEGER\n"); + 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, (int)(uintptr_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: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_QWORD !REG_FP\n"); + 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, (int)(uintptr_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: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_POINTER !REG_INTEGER\n"); + 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, (int)(uintptr_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: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_DOUBLE !REG_FP\n"); + 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, (int)(uintptr_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: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_FPU_ST_BYTE !REG_INTEGER\n"); + 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: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_FPU_ST_QWORD !REG_FP\n"); + 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: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_FPU_ST_DOUBLE !REG_FP\n"); + 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; +} + +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: + 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); + codegen_direct_write_8(block, p, reg_set->reg_list[c].reg); + break; + + case REG_WORD: + 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); + codegen_direct_write_16(block, p, reg_set->reg_list[c].reg); + break; + + case REG_DWORD: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_DWORD !REG_INTEGER\n"); + if ((uintptr_t)p < 256) + codegen_direct_write_32_stack(block, (int)(uintptr_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: + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_QWORD !REG_FP\n"); + if ((uintptr_t)p < 256) + codegen_direct_write_64_stack(block, (int)(uintptr_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: + 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); + codegen_direct_write_ptr(block, p, reg_set->reg_list[c].reg); + break; + + case REG_DOUBLE: + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_DOUBLE !REG_FP\n"); + if ((uintptr_t)p < 256) + codegen_direct_write_double_stack(block, (int)(uintptr_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: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_FPU_ST_BYTE !REG_INTEGER\n"); + 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: + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_FPU_ST_QWORD !REG_FP\n"); + 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: + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_FPU_ST_DOUBLE !REG_FP\n"); + 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; +} + +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)) + { + 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); + 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; + 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; + + 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; + } + + 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"); + } + + 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; + } + if (c == reg_set->nr_regs) + fatal("codegen_reg_alloc_read_reg - out of registers\n"); + } + if (reg_set->dirty[c]) + codegen_reg_writeback(reg_set, block, c, 1); + codegen_reg_load(reg_set, block, c, ir_reg); + reg_set->locked |= (1 << c); + reg_set->dirty[c] = 0; + } + + reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount--; + 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"); + + if (host_reg_idx) + *host_reg_idx = 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); + + 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); + + reg_set->regs[c].reg = ir_reg.reg; + reg_set->regs[c].version = ir_reg.version; + reg_set->dirty[c] = 1; + 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) + { + 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"); + 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; + } + if (c == reg_set->nr_regs) + fatal("codegen_reg_alloc_write_reg - out of registers\n"); + 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; + return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg); +} + +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))) + { + 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/cpu_new/codegen_reg.h b/src/cpu_new/codegen_reg.h new file mode 100644 index 000000000..85bb9f142 --- /dev/null +++ b/src/cpu_new/codegen_reg.h @@ -0,0 +1,402 @@ +#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; + + if (IREG_GET_REG(reg) == IREG_INVALID) + fatal("codegen_reg_read - IREG_INVALID\n"); + + 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++; + if (!version->refcount) + fatal("codegen_reg_read - refcount overflow\n"); + else if (version->refcount > REG_REFCOUNT_MAX) + CPU_BLOCK_END(); + if (version->refcount > max_version_refcount) + max_version_refcount = version->refcount; + 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; + + if (IREG_GET_REG(reg) == IREG_INVALID) + fatal("codegen_reg_write - IREG_INVALID\n"); + + 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)]++; + if (!reg_last_version[IREG_GET_REG(reg)]) + fatal("codegen_reg_write - version overflow\n"); + else 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; + 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); + +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_mark_as_required(); +void codegen_reg_process_dead_list(struct ir_data_t *ir); +#endif diff --git a/src/cpu_new/codegen_timing_486.c b/src/cpu_new/codegen_timing_486.c new file mode 100644 index 000000000..6b744472b --- /dev/null +++ b/src/cpu_new/codegen_timing_486.c @@ -0,0 +1,424 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_ops.h" +#include "x87.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)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*e0*/ NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(3), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(6), CYCLES(3), NULL, NULL, CYCLES(4), CYCLES(8), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(4), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(140), CYCLES(196), CYCLES(200), CYCLES(218), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(83), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(257), CYCLES(257) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(9), NULL, CYCLES(28), CYCLES(28), NULL, CYCLES(5), NULL, CYCLES(6) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(3), CYCLES(7), CYCLES(17), CYCLES(3), CYCLES(3), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(8), CYCLES(16), NULL, NULL, CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(3), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(3) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), NULL, CYCLES(5), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(13), NULL, CYCLES(29), CYCLES(29), NULL, CYCLES(10), CYCLES(172), CYCLES(28) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *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) +{ + if ((uintptr_t)c <= 10000) + return (int)(uintptr_t)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_486_block_start() +{ + regmask_modified = 0; +} + +void codegen_timing_486_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_486_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + 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_jump_cycles +}; diff --git a/src/cpu_new/codegen_timing_686.c b/src/cpu_new/codegen_timing_686.c new file mode 100644 index 000000000..6bcb7c44d --- /dev/null +++ b/src/cpu_new/codegen_timing_686.c @@ -0,0 +1,1061 @@ +/*Elements taken into account : + - X/Y pairing + - FPU/FXCH pairing + - Prefix decode delay + - AGI stalls + Elements not taken into account : + - Branch prediction (beyond most simplistic approximation) + - FPU queue + - Out of order execution (beyond most simplistic approximation) +*/ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_ops.h" +#include "x87.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) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c) + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (1 << 0) +#define CYCLES_RM (1 << 0) +#define CYCLES_RMW (1 << 0) +#define CYCLES_BRANCH (1 << 0) + +#define CYCLES_MASK ((1 << 7) - 1) + +/*Instruction does not pair*/ +#define PAIR_NP (0 << 29) +/*Instruction pairs in X pipe only*/ +#define PAIR_X (1 << 29) +/*Instruction pairs in X pipe only, and can not pair with a following instruction*/ +#define PAIR_X_BRANCH (2 << 29) +/*Instruction pairs in both X and Y pipes*/ +#define PAIR_XY (3 << 29) + +#define PAIR_MASK (3 << 29) + +#define INVALID 0 + +static int prev_full; +static uint32_t prev_opcode; +static uint32_t *prev_timings; +static uint32_t prev_op_32; +static uint32_t prev_regmask; +static uint64_t *prev_deps; +static uint32_t prev_fetchdat; + +static uint32_t last_regmask_modified; +static uint32_t regmask_modified; + +static uint32_t opcode_timings[256] = +{ +/* 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, 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, 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, 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, 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, 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, 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, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_RM, 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), PAIR_XY | CYCLES(9), PAIR_XY | CYCLES(1), PAIR_XY | 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, 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), +/* LES LDS MOV MOV*/ + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(10), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH, 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*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_RMW, INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_REG, 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, 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, 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, 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, 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, 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, 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, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ PAIR_XY | CYCLES_REG, 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), +/* 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, 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, 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), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(13), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH, 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*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_REG, INVALID +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | 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 | 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, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, + +/*c0*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + +/*d0*/ INVALID, PAIR_X | 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 | 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 | 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] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | 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 | 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, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_X | 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 | 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 | 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] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + PAIR_XY | CYCLES_REG, 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] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_imm_mod3[8] = +{ + PAIR_XY | CYCLES_REG, 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), 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), 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] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(18) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG, 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, 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, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(19,27), PAIR_NP | CYCLES_MULTI(22,30) +}; +static uint32_t opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), +/* JMP JMP far PUSH*/ + PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(1), INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ +/* 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] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_X | CYCLES(30), PAIR_X | CYCLES(4), PAIR_X | CYCLES(24), PAIR_X | CYCLES(5) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + /*FXCH*/ + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + /*FNOP*/ + PAIR_X | CYCLES(2), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* opFCHS opFABS*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, +/* opFTST opFXAM (oddly low) */ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_X | CYCLES(92), PAIR_X | CYCLES(170), PAIR_X | CYCLES(129), PAIR_X | CYCLES(161), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_X | CYCLES(4), PAIR_X | CYCLES(2), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_X | CYCLES(91), INVALID, PAIR_X | CYCLES(60), PAIR_X | CYCLES(161), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_X | CYCLES(20), PAIR_X | CYCLES(14), PAIR_X | CYCLES(140), PAIR_X | CYCLES(141) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_X | CYCLES(29), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(48) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + INVALID, PAIR_X | CYCLES(5), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDe FSTPe*/ + INVALID, PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_db_mod3[64] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(5), PAIR_X | CYCLES(8), +/* opFNOP opFNOP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint32_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FRSTOR FSAVE FSTSW*/ + PAIR_X | CYCLES(72), INVALID, PAIR_X | CYCLES(67), PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + PAIR_X | CYCLES(3), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FUCOM FUCOMP*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_X | CYCLES(27), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(38) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, PAIR_X | CYCLES(7), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + PAIR_X | CYCLES(8), INVALID, PAIR_X | CYCLES(10), PAIR_X | CYCLES(13), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_X | CYCLES(8), PAIR_X | CYCLES(63), PAIR_X | CYCLES(13) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_X | CYCLES(6), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + PAIR_XY | CYCLES_RMW, 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; +static uint8_t last_prefix; + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + if (!(c & PAIR_MASK)) + return c & 0xffff; + + return c & CYCLES_MASK; +} + +void codegen_timing_686_block_start() +{ + prev_full = decode_delay = 0; + regmask_modified = last_regmask_modified = 0; +} + +void codegen_timing_686_start() +{ + decode_delay = 0; + last_prefix = 0; +} + +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*/ + decode_delay++; + last_prefix = prefix; +} + +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); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + /*One prefix per instruction is free*/ + decode_delay--; + if (decode_delay < 0) + decode_delay = 0; + + if (prev_full) + { + 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 + 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; + } + else if (((timings[opcode] & PAIR_MASK) == PAIR_X || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + && (prev_timings[opcode] & PAIR_MASK) == PAIR_X) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + 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; + } + 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 + 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; + } + else + { + int t1 = COUNT(prev_timings[prev_opcode], prev_op_32); + int t2 = COUNT(timings[opcode], op_32); + int t_pair = (t1 > t2) ? t1 : t2; + + if (!t_pair) + fatal("Pairable 0 cycles! %02x %02x\n", opcode, prev_opcode); + + 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; + return; + } + } + + if (!prev_full) + { + /*First instruction in the pair*/ + if ((timings[opcode] & PAIR_MASK) == PAIR_NP || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + { + /*Instruction not pairable*/ + 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); + } + else + { + /*Instruction might pair with next*/ + prev_full = 1; + prev_opcode = opcode; + prev_timings = timings; + prev_op_32 = op_32; + 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; + } + } +} + +void codegen_timing_686_block_end() +{ + if (prev_full) + { + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + prev_full = 0; + } +} + +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_jump_cycles +}; diff --git a/src/cpu_new/codegen_timing_common.c b/src/cpu_new/codegen_timing_common.c new file mode 100644 index 000000000..3b47a2734 --- /dev/null +++ b/src/cpu_new/codegen_timing_common.c @@ -0,0 +1,847 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.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, SRCDEP_EAX | DSTDEP_EAX, 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, SRCDEP_EAX | DSTDEP_EAX, 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, SRCDEP_EAX | DSTDEP_EAX, 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, SRCDEP_EAX | DSTDEP_EAX, 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, SRCDEP_EAX | DSTDEP_EAX | MODRM, 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, SRCDEP_EAX | DSTDEP_EAX | MODRM, 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, SRCDEP_EAX | DSTDEP_EAX | MODRM, 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, SRCDEP_EAX, 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, DSTDEP_REG | MODRM, IMPL_ESP, 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, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_ESP, DSTDEP_EBP, DSTDEP_ESI, DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, +/* LES LDS MOV MOV*/ + DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, MODRM, MODRM, +/* 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, SRCDEP_EAX | DSTDEP_EAX, 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, SRCDEP_EAX | DSTDEP_EAX, 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, SRCDEP_EAX | DSTDEP_EAX, 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, SRCDEP_EAX | DSTDEP_EAX, 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, SRCDEP_EAX | DSTDEP_EAX | MODRM, 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, SRCDEP_EAX | DSTDEP_EAX | MODRM, 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, SRCDEP_EAX | DSTDEP_EAX | MODRM, 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, SRCDEP_EAX, 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, DSTDEP_REG | SRCDEP_RM | MODRM, IMPL_ESP, 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, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_ESP, DSTDEP_EBP, DSTDEP_ESI, DSTDEP_EDI, + +/* 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, DSTDEP_RM | MODRM, +/* 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/cpu_new/codegen_timing_common.h b/src/cpu_new/codegen_timing_common.h new file mode 100644 index 000000000..19c28b998 --- /dev/null +++ b/src/cpu_new/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/cpu_new/codegen_timing_k6.c b/src/cpu_new/codegen_timing_k6.c new file mode 100644 index 000000000..9c216de9a --- /dev/null +++ b/src/cpu_new/codegen_timing_k6.c @@ -0,0 +1,2350 @@ +/*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 +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" +#include "../machine/machine.h" + +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "386_common.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 (machines[machine].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; + } + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + break; + + default: + ins_table = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + 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/cpu_new/codegen_timing_pentium.c b/src/cpu_new/codegen_timing_pentium.c new file mode 100644 index 000000000..ee893a361 --- /dev/null +++ b/src/cpu_new/codegen_timing_pentium.c @@ -0,0 +1,1327 @@ +/*Elements taken into account : + - 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 + - MMX latencies +*/ + +#include +#include "../86box.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 << 28) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c | PAIR_NP) + + +static int pair_timings[4][4] = +{ +/* Reg RM RMW Branch*/ +/*Reg*/ {1, 2, 3, 2}, +/*RM*/ {2, 2, 3, 3}, +/*RMW*/ {3, 4, 5, 4}, +/*Branch*/ {-1, -1, -1, -1} +}; + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (0ull << 0) +#define CYCLES_RM (1ull << 0) +#define CYCLES_RMW (2ull << 0) +#define CYCLES_BRANCH (3ull << 0) + +/*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 does not pair*/ +#define PAIR_NP (0ull << 29) +/*Instruction pairs in U pipe only*/ +#define PAIR_U (1ull << 29) +/*Instruction pairs in V pipe only*/ +#define PAIR_V (2ull << 29) +/*Instruction pairs in both U and V pipes*/ +#define PAIR_UV (3ull << 29) +/*Instruction pairs in U pipe only and only with FXCH*/ +#define PAIR_FX (5ull << 29) +/*Instruction is FXCH and only pairs in V pipe with FX pairable instruction*/ +#define PAIR_FXCH (6ull << 29) + +#define PAIR_FPU (4ull << 29) + +#define PAIR_MASK (7ull << 29) + + +/*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 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; + +static uint32_t regmask_modified; + +static uint32_t addr_regmask; + +static int fpu_latency; +static int fpu_st_latency[8]; + +static uint64_t opcode_timings[256] = +{ +/* 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, + +/* 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), + +/* 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, 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, 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, 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), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_RM, 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), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG, 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, 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, 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), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_RMW, INVALID +}; + +static uint64_t opcode_timings_mod3[256] = +{ +/* 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, 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, 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, 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, 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, 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), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ PAIR_UV | CYCLES_REG, 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), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG, 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, 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, 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), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_REG, INVALID +}; + +static 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, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_U | 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 | 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), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_U | 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 | 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 | 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 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, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_UV | 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 | 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), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_UV | 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 | 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 | 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 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 uint64_t opcode_timings_shift_mod3[8] = +{ + 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 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 uint64_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + 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 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) +}; +static uint64_t opcode_timings_f7_mod3[8] = +{ +/* 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 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_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 uint64_t opcode_timings_d8[8] = +{ +/* 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 uint64_t opcode_timings_d8_mod3[8] = +{ +/* 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 uint64_t opcode_timings_d9[8] = +{ +/* 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 uint64_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + 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_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 | FPU_CYCLES(3,0,0), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + 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 uint64_t opcode_timings_da[8] = +{ +/* 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 uint64_t opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID +}; + + +static uint64_t opcode_timings_db[8] = +{ +/* 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 uint64_t opcode_timings_db_mod3[64] = +{ + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_NP | 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, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint64_t opcode_timings_dc[8] = +{ +/* 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 uint64_t opcode_timings_dc_mod3[8] = +{ +/* 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 uint64_t opcode_timings_dd[8] = +{ +/* 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 uint64_t opcode_timings_dd_mod3[8] = +{ +/* 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 uint64_t opcode_timings_de[8] = +{ +/* 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 uint64_t opcode_timings_de_mod3[8] = +{ +/* 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 uint64_t opcode_timings_df[8] = +{ +/* 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 uint64_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_NP | FPU_CYCLES(6,0,0), INVALID, INVALID, INVALID +}; + +static uint64_t opcode_timings_81[8] = +{ + 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, decode_delay_offset; +static uint8_t last_prefix; +static int prefixes; + +static inline int COUNT(uint64_t timings, uint64_t deps, int op_32) +{ + if ((timings & PAIR_FPU) && !(deps & FPU_FXCH)) + return FPU_I_LATENCY(timings); + if (timings & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)timings >> 8) & 0xff; + return (uintptr_t)timings & 0xff; + } + 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; + case CYCLES_RM: + return 2; + case CYCLES_RMW: + return 3; + case CYCLES_BRANCH: + return cpu_has_feature(CPU_FEATURE_MMX) ? 1 : 2; + } + + fatal("Illegal COUNT %016llx\n", timings); + + 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 = 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) +{ + 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_has_feature(CPU_FEATURE_MMX) && (prefix == 0x66 || prefix == 0x67)) + { + /*On Pentium MMX 66h and 67h prefixes take 2 clocks*/ + decode_delay_offset += 2; + last_prefix = prefix; + return; + } + if (prefix == 0x0f && (fetchdat & 0xf0) == 0x80) + { + /*On Pentium 0fh prefix is 'free' when used on conditional jumps*/ + last_prefix = prefix; + return; + } + /*On Pentium all prefixes take 1 cycle to decode. Decode may be shadowed + by execution of previous instructions*/ + decode_delay_offset++; + last_prefix = prefix; +} + +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 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))) + { + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + break; + + 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; + 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; + 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; + 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; + 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; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + if (u_pipe_full) + { + 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; + + if ((timings[opcode] & PAIR_MASK) == PAIR_FXCH && + (u_pipe_timings[u_pipe_opcode] & PAIR_MASK) != PAIR_FX) + goto nopair; + + 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*/ + 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; + addr_regmask = 0; + } + + if ((timings[opcode] & PAIR_U) && (decode_delay + 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)) && (!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*/ + 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() +{ + if (u_pipe_full) + { + /*Run previous now*/ + 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_jump_cycles +}; diff --git a/src/cpu_new/codegen_timing_winchip.c b/src/cpu_new/codegen_timing_winchip.c new file mode 100644 index 000000000..90982349f --- /dev/null +++ b/src/cpu_new/codegen_timing_winchip.c @@ -0,0 +1,424 @@ +#include +#include "../86box.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" + +#define CYCLES(c) (int *)c +#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, 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, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, 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, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(2), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(7), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(2), CYCLES(2), NULL, NULL, CYCLES(5), CYCLES(7), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(5), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(5), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(300), CYCLES(58), CYCLES(676), CYCLES(355), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(72), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(474), CYCLES(474) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), NULL, CYCLES(8) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(7), CYCLES(18), CYCLES(27), CYCLES(7), CYCLES(7), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(6), CYCLES(8), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(74), CYCLES(74) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(4), CYCLES(6), NULL, NULL, CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(2), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(5) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), NULL, CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), CYCLES(172), CYCLES(8) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *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) +{ + if ((uintptr_t)c <= 10000) + return (int)(uintptr_t)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_winchip_block_start() +{ + regmask_modified = 0; +} + +void codegen_timing_winchip_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + 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_jump_cycles +}; diff --git a/src/cpu_new/codegen_timing_winchip2.c b/src/cpu_new/codegen_timing_winchip2.c new file mode 100644 index 000000000..9da156b82 --- /dev/null +++ b/src/cpu_new/codegen_timing_winchip2.c @@ -0,0 +1,745 @@ +/*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 +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_ops.h" +#include "x87.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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + 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/cpu_new/cpu.c b/src/cpu_new/cpu.c new file mode 100644 index 000000000..26b790dc4 --- /dev/null +++ b/src/cpu_new/cpu.c @@ -0,0 +1,2764 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * CPU type handler. + * + * Version: @(#)cpu.c 1.0.6 2018/05/05 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../device.h" +#include "../machine/machine.h" +#include "../io.h" +#include "x86_ops.h" +#include "../mem.h" +#include "../nmi.h" +#include "../pic.h" +#include "../pci.h" +#ifdef USE_DYNAREC +# include "codegen.h" +#endif + + +static void cpu_write(uint16_t addr, uint8_t val, void *priv); +static uint8_t cpu_read(uint16_t addr, void *priv); + + +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_AMDSEP = (1 << 10), + CPUID_SEP = (1 << 11), + CPUID_CMOV = (1 << 15), + CPUID_MMX = (1 << 23), + CPUID_FXSR = (1 << 24) +}; + +/*Addition flags returned by CPUID function 0x80000001*/ +enum +{ + CPUID_3DNOW = (1 << 31) +}; + + +#ifdef USE_DYNAREC +const OpFn *x86_dynarec_opcodes; +const OpFn *x86_dynarec_opcodes_0f; +const OpFn *x86_dynarec_opcodes_d8_a16; +const OpFn *x86_dynarec_opcodes_d8_a32; +const OpFn *x86_dynarec_opcodes_d9_a16; +const OpFn *x86_dynarec_opcodes_d9_a32; +const OpFn *x86_dynarec_opcodes_da_a16; +const OpFn *x86_dynarec_opcodes_da_a32; +const OpFn *x86_dynarec_opcodes_db_a16; +const OpFn *x86_dynarec_opcodes_db_a32; +const OpFn *x86_dynarec_opcodes_dc_a16; +const OpFn *x86_dynarec_opcodes_dc_a32; +const OpFn *x86_dynarec_opcodes_dd_a16; +const OpFn *x86_dynarec_opcodes_dd_a32; +const OpFn *x86_dynarec_opcodes_de_a16; +const OpFn *x86_dynarec_opcodes_de_a32; +const OpFn *x86_dynarec_opcodes_df_a16; +const OpFn *x86_dynarec_opcodes_df_a32; +const OpFn *x86_dynarec_opcodes_REPE; +const OpFn *x86_dynarec_opcodes_REPNE; +const OpFn *x86_dynarec_opcodes_3DNOW; +#endif + +const OpFn *x86_opcodes; +const OpFn *x86_opcodes_0f; +const OpFn *x86_opcodes_d8_a16; +const OpFn *x86_opcodes_d8_a32; +const OpFn *x86_opcodes_d9_a16; +const OpFn *x86_opcodes_d9_a32; +const OpFn *x86_opcodes_da_a16; +const OpFn *x86_opcodes_da_a32; +const OpFn *x86_opcodes_db_a16; +const OpFn *x86_opcodes_db_a32; +const OpFn *x86_opcodes_dc_a16; +const OpFn *x86_opcodes_dc_a32; +const OpFn *x86_opcodes_dd_a16; +const OpFn *x86_opcodes_dd_a32; +const OpFn *x86_opcodes_de_a16; +const OpFn *x86_opcodes_de_a32; +const OpFn *x86_opcodes_df_a16; +const OpFn *x86_opcodes_df_a32; +const OpFn *x86_opcodes_REPE; +const OpFn *x86_opcodes_REPNE; +const OpFn *x86_opcodes_3DNOW; + +int in_smm = 0, smi_line = 0, smi_latched = 0; +uint32_t smbase = 0x30000; + +CPU *cpu_s; +int cpu_effective; +int cpu_multi; +int cpu_16bitbus; +int cpu_busspeed; +int cpu_cyrix_alignment; +int CPUID; +uint64_t cpu_CR4_mask; +int isa_cycles; +int cpu_cycles_read, cpu_cycles_read_l, + cpu_cycles_write, cpu_cycles_write_l; +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 cpu_pci_speed, cpu_alt_reset; + +uint32_t cpu_features; + +int is286, + is386, + is486 = 1, + cpu_iscyrix, + isibmcpu, + israpidcad, + is_pentium; + +int hasfpu; + + +uint64_t tsc = 0; +msr_t msr; +cr0_t CR0; +uint64_t pmc[2] = {0, 0}; + +uint16_t temp_seg_data[4] = {0, 0, 0, 0}; + +#if defined(DEV_BRANCH) && defined(USE_I686) +uint16_t cs_msr = 0; +uint32_t esp_msr = 0; +uint32_t eip_msr = 0; +uint64_t apic_base_msr = 0; +uint64_t mtrr_cap_msr = 0; +uint64_t mtrr_physbase_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_physmask_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_fix64k_8000_msr = 0; +uint64_t mtrr_fix16k_8000_msr = 0; +uint64_t mtrr_fix16k_a000_msr = 0; +uint64_t mtrr_fix4k_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t pat_msr = 0; +uint64_t mtrr_deftype_msr = 0; +uint64_t msr_ia32_pmc[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t ecx17_msr = 0; +uint64_t ecx79_msr = 0; +uint64_t ecx8x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx116_msr = 0; +uint64_t ecx11x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx11e_msr = 0; +uint64_t ecx186_msr = 0; +uint64_t ecx187_msr = 0; +uint64_t ecx1e0_msr = 0; +uint64_t ecx570_msr = 0; +#endif + +uint64_t ecx83_msr = 0; /* AMD K5 and K6 MSR's. */ +uint64_t star = 0; /* These are K6-only. */ +uint64_t sfmask = 0; + +int timing_rr; +int timing_mr, timing_mrl; +int timing_rm, timing_rml; +int timing_mm, timing_mml; +int timing_bt, timing_bnt; +int timing_int, timing_int_rm, timing_int_v86, timing_int_pm, + timing_int_pm_outer; +int timing_iret_rm, timing_iret_v86, timing_iret_pm, + timing_iret_pm_outer; +int timing_call_rm, timing_call_pm, timing_call_pm_gate, + timing_call_pm_gate_inner; +int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; +int timing_misaligned; + + +static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; + +int cpu_has_feature(int feature) +{ + return cpu_features & feature; +} + + +void +cpu_dynamic_switch(int new_cpu) +{ + if (cpu_effective == new_cpu) + return; + + int c = cpu; + cpu = new_cpu; + cpu_set(); + pc_speed_changed(); + cpu = c; +} + + +void +cpu_set_edx(void) +{ + EDX = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].edx_reset; +} + + +void +cpu_set(void) +{ + if (!machines[machine].cpu[cpu_manufacturer].cpus) + { + /*CPU is invalid, set to default*/ + cpu_manufacturer = 0; + cpu = 0; + } + + cpu_effective = cpu; + cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + + cpu_alt_reset = 0; + + CPUID = cpu_s->cpuid_model; + is8086 = (cpu_s->cpu_type > CPU_8088); + is286 = (cpu_s->cpu_type >= CPU_286); + is386 = (cpu_s->cpu_type >= CPU_386SX); + isibmcpu = (cpu_s->cpu_type == CPU_IBM386SLC || cpu_s->cpu_type == CPU_IBM486SLC || cpu_s->cpu_type == CPU_IBM486BL); + israpidcad = (cpu_s->cpu_type == CPU_RAPIDCAD); + is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_RAPIDCAD || cpu_s->cpu_type == CPU_IBM486SLC || cpu_s->cpu_type == CPU_IBM486BL ); + is_pentium = (cpu_s->cpu_type >= CPU_WINCHIP); + hasfpu = (cpu_s->cpu_type >= CPU_i486DX) || (cpu_s->cpu_type == CPU_RAPIDCAD); + 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 || cpu_s->cpu_type == CPU_IBM386SLC || cpu_s->cpu_type == CPU_IBM486SLC ); + if (cpu_s->multi) { + cpu_busspeed = cpu_s->rspeed / cpu_s->multi; + } + cpu_multi = cpu_s->multi; + ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; + + if ((cpu_s->cpu_type == CPU_8088) || (cpu_s->cpu_type == CPU_8086) || + (cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || + (cpu_s->cpu_type == CPU_386DX) || (cpu_s->cpu_type == CPU_i486SX)) { + hasfpu = !!enable_external_fpu; + } + + cpu_update_waitstates(); + + isa_cycles = cpu_s->atclk_div; + + 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) + { + pci_nonburst_time = 4*cpu_s->rspeed / cpu_s->pci_speed; + pci_burst_time = cpu_s->rspeed / cpu_s->pci_speed; + } + else + { + pci_nonburst_time = 4; + pci_burst_time = 1; + } + + if (cpu_iscyrix) + io_sethandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + else + io_removehandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + + if (hasfpu) + io_sethandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + else + io_removehandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); +#else + x86_setopcodes(ops_386, ops_386_0f); +#endif + x86_opcodes_REPE = ops_REPE; + x86_opcodes_REPNE = ops_REPNE; + x86_opcodes_3DNOW = ops_3DNOW; +#ifdef USE_DYNAREC + x86_dynarec_opcodes_REPE = dynarec_ops_REPE; + x86_dynarec_opcodes_REPNE = dynarec_ops_REPNE; + x86_dynarec_opcodes_3DNOW = dynarec_ops_3DNOW; +#endif + +#ifdef USE_DYNAREC + if (hasfpu) + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_fpu_d8_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_fpu_d8_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_df_a32; + } + else + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_nofpu_a32; + } + codegen_timing_set(&codegen_timing_486); +#endif + + if (hasfpu) + { + x86_opcodes_d8_a16 = ops_fpu_d8_a16; + x86_opcodes_d8_a32 = ops_fpu_d8_a32; + x86_opcodes_d9_a16 = ops_fpu_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_d9_a32; + x86_opcodes_da_a16 = ops_fpu_da_a16; + x86_opcodes_da_a32 = ops_fpu_da_a32; + x86_opcodes_db_a16 = ops_fpu_db_a16; + x86_opcodes_db_a32 = ops_fpu_db_a32; + x86_opcodes_dc_a16 = ops_fpu_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_dd_a32; + x86_opcodes_de_a16 = ops_fpu_de_a16; + x86_opcodes_de_a32 = ops_fpu_de_a32; + x86_opcodes_df_a16 = ops_fpu_df_a16; + x86_opcodes_df_a32 = ops_fpu_df_a32; + } + else + { + x86_opcodes_d8_a16 = ops_nofpu_a16; + x86_opcodes_d8_a32 = ops_nofpu_a32; + x86_opcodes_d9_a16 = ops_nofpu_a16; + x86_opcodes_d9_a32 = ops_nofpu_a32; + x86_opcodes_da_a16 = ops_nofpu_a16; + x86_opcodes_da_a32 = ops_nofpu_a32; + x86_opcodes_db_a16 = ops_nofpu_a16; + x86_opcodes_db_a32 = ops_nofpu_a32; + x86_opcodes_dc_a16 = ops_nofpu_a16; + x86_opcodes_dc_a32 = ops_nofpu_a32; + x86_opcodes_dd_a16 = ops_nofpu_a16; + x86_opcodes_dd_a32 = ops_nofpu_a32; + x86_opcodes_de_a16 = ops_nofpu_a16; + x86_opcodes_de_a32 = ops_nofpu_a32; + x86_opcodes_df_a16 = ops_nofpu_a16; + x86_opcodes_df_a32 = ops_nofpu_a32; + } + + memset(&msr, 0, sizeof(msr)); + + timing_misaligned = 0; + cpu_cyrix_alignment = 0; + + switch (cpu_s->cpu_type) + { + case CPU_8088: + case CPU_8086: + break; + + case CPU_286: +#ifdef USE_DYNAREC + x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f); +#else + x86_setopcodes(ops_286, ops_286_0f); +#endif + if (enable_external_fpu) + { +#ifdef USE_DYNAREC + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32; +#endif + x86_opcodes_d9_a16 = ops_fpu_287_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_287_d9_a32; + x86_opcodes_da_a16 = ops_fpu_287_da_a16; + x86_opcodes_da_a32 = ops_fpu_287_da_a32; + x86_opcodes_db_a16 = ops_fpu_287_db_a16; + x86_opcodes_db_a32 = ops_fpu_287_db_a32; + x86_opcodes_dc_a16 = ops_fpu_287_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_287_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_287_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_287_dd_a32; + x86_opcodes_de_a16 = ops_fpu_287_de_a16; + x86_opcodes_de_a32 = ops_fpu_287_de_a32; + x86_opcodes_df_a16 = ops_fpu_287_df_a16; + x86_opcodes_df_a32 = ops_fpu_287_df_a32; + } + timing_rr = 2; /*register dest - register src*/ + timing_rm = 7; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 7; /*memory dest - memory src*/ + timing_rml = 9; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 11; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 23; + timing_int_v86 = 0; + timing_int_pm = 40; + timing_int_pm_outer = 78; + timing_iret_rm = 17; + timing_iret_v86 = 0; + timing_iret_pm = 31; + timing_iret_pm_outer = 55; + timing_call_rm = 13; + timing_call_pm = 26; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 82; + timing_retf_rm = 15; + timing_retf_pm = 25; + timing_retf_pm_outer = 55; + timing_jmp_rm = 11; + timing_jmp_pm = 23; + timing_jmp_pm_gate = 38; + break; + + case CPU_IBM386SLC: + case CPU_386SX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 8; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 10; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_386DX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 6; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 6; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_IBM486SLC: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 5; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 4; /*register dest - memory src long*/ + timing_mrl = 5; /*memory dest - register src long*/ + timing_mml = 5; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + case CPU_IBM486BL: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_RAPIDCAD: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_486SLC: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 5; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 5; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 7; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + timing_misaligned = 3; + break; + + case CPU_486DLC: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + 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: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_Am486SX: + case CPU_Am486DX: + /*AMD timing identical to Intel*/ +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_Cx486S: + case CPU_Cx486DX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 4-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; /*unknown*/ + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + timing_misaligned = 3; + break; + + case CPU_Cx5x86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 9; + timing_int_v86 = 82; /*unknown*/ + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + break; + + case CPU_WINCHIP: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_winchip_0f, dynarec_ops_386, dynarec_ops_winchip_0f); +#else + x86_setopcodes(ops_386, ops_winchip_0f); +#endif + 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; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (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; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_winchip); +#endif + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + break; + + case CPU_WINCHIP2: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f); +#else + x86_setopcodes(ops_386, ops_winchip2_0f); +#endif + 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: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + 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; + 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; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_pentium); +#endif + break; + + case CPU_PENTIUMMMX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); +#else + x86_setopcodes(ops_386, ops_pentiummmx_0f); +#endif + 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 | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_pentium); +#endif + break; + + case CPU_Cx6x86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + 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); +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + CPUID = 0; /*Disabled on powerup by default*/ + break; + + case CPU_Cx6x86L: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + 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); +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + ccr4 = 0x80; + break; + + + case CPU_CxGX1: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 2; + cpu_cyrix_alignment = 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_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; + + + case CPU_Cx6x86MX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_c6x86mx_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + 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_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + ccr4 = 0x80; + break; + + case CPU_K5: + case CPU_5K86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); +#else + x86_setopcodes(ops_386, ops_k6_0f); +#endif + 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_TSD | CR4_DE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_k6); +#endif + break; + + case CPU_K6: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); +#else + x86_setopcodes(ops_386, ops_k6_0f); +#endif + 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 | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_k6); +#endif + break; + + case CPU_K6_2: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_k62_0f, dynarec_ops_386, dynarec_ops_k62_0f); +#else + x86_setopcodes(ops_386, ops_k62_0f); +#endif + 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; + +#if defined(DEV_BRANCH) && defined(USE_I686) + case CPU_PENTIUMPRO: +#ifdef USE_DYNAREC + 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; +#else + x86_setopcodes(ops_386, ops_pentiumpro_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + 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_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; + +#if 0 + case CPU_PENTIUM2: +#ifdef USE_DYNAREC + 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; +#else + x86_setopcodes(ops_386, ops_pentium2_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + 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 | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; +#endif + + case CPU_PENTIUM2D: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium2d_0f, dynarec_ops_386, dynarec_ops_pentium2d_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_pentium2d_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + 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 | CR4_PCE | CR4_OSFXSR; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; +#endif + + default: + fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type); + } +} + + +char * +cpu_current_pc(char *bufp) +{ + static char buff[10]; + + if (bufp == NULL) + bufp = buff; + + sprintf(bufp, "%04X:%04X", CS, cpu_state.pc); + + return(bufp); +} + + +void +cpu_CPUID(void) +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_RAPIDCAD: + case CPU_i486DX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = 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: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = EDX = 0; /*No FPU*/ + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_Am486DX: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_WINCHIP: + if (!EAX) + { + EAX = 1; + if (msr.fcr2 & (1 << 14)) + { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } + else + { + EBX = 0x746e6543; /*CentaurHauls*/ + ECX = 0x736c7561; + EDX = 0x48727561; + } + } + else if (EAX == 1) + { + EAX = 0x540; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + } + else + 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: + if (!EAX) + { + EAX = 0x00000001; + 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; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_K5: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_5K86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x7428354B; + ECX = 0x5020296D; + EDX = 0x65636F72; + } + else if (EAX == 0x80000003) + { + EAX = 0x726F7373; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000004) + { + EAX = EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x04800000; + ECX = 0x08040120; + EDX = 0x10040120; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_K6: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID + 0x100; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x6D74364B; + ECX = 0x202F7720; + EDX = 0x746C756D; + } + else if (EAX == 0x80000003) + { + EAX = 0x64656D69; + EBX = 0x65206169; + ECX = 0x6E657478; + EDX = 0x6E6F6973; + } + else if (EAX == 0x80000004) + { + EAX = 0x73; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x02800140; + ECX = 0x20020220; + EDX = 0x20020220; + } + else if (EAX == 0x8FFFFFFF) + { + EAX = 0x4778654E; + EBX = 0x72656E65; + ECX = 0x6F697461; + EDX = 0x444D416E; + } + else + EAX = EBX = ECX = EDX = 0; + 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 (machines[machine].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_PENTIUMMMX: + if (!EAX) + { + EAX = 0x00000001; + 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_MMX; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + case CPU_Cx6x86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + case CPU_Cx6x86L: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + case CPU_CxGX1: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + + case CPU_Cx6x86MX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; + } + else + EAX = EBX = ECX = EDX = 0; + break; + +#ifdef DEV_BRANCH +#ifdef USE_I686 + 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_SEP | CPUID_CMOV; + } + else if (EAX == 2) + { + } + else + EAX = EBX = ECX = EDX = 0; + break; + + /* case CPU_PENTIUM2: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_CMOV; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040843; + } + else + EAX = EBX = ECX = EDX = 0; + break; */ + + case CPU_PENTIUM2D: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_FXSR | CPUID_CMOV; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040844; + } + else + EAX = EBX = ECX = EDX = 0; + break; +#endif +#endif + + } +} + +void cpu_RDMSR() +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_WINCHIP: + case CPU_WINCHIP2: + EAX = EDX = 0; + switch (ECX) + { + case 0x02: + EAX = msr.tr1; + break; + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x11: + EAX = msr.cesr; + break; + case 0x107: + EAX = msr.fcr; + break; + case 0x108: + EAX = msr.fcr2 & 0xffffffff; + EDX = msr.fcr2 >> 32; + break; + case 0x10a: + EAX = cpu_multi & 3; + break; + } + break; + + case CPU_K5: + case CPU_5K86: + case CPU_K6: + case CPU_K6_2: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: + EAX = EDX = 0; + switch (ECX) + { + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x83: + EAX = ecx83_msr & 0xffffffff; + EDX = ecx83_msr >> 32; + break; + case 0xC0000081: + EAX = star & 0xffffffff; + EDX = star >> 32; + break; + case 0xC0000084: + EAX = sfmask & 0xffffffff; + EDX = sfmask >> 32; + break; + default: + x86gpf(NULL, 0); + break; + } + break; + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + +#ifdef DEV_BRANCH +#ifdef USE_I686 + case CPU_PENTIUMPRO: + case CPU_PENTIUM2D: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x17: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type != CPU_PENTIUM2D) goto i686_invalid_rdmsr; + EAX = ecx17_msr & 0xffffffff; + EDX = ecx17_msr >> 32; + break; + case 0x1B: + EAX = apic_base_msr & 0xffffffff; + EDX = apic_base_msr >> 32; + break; + case 0x2A: + EAX = 0xC5800000; + EDX = 0; + break; + case 0x79: + EAX = ecx79_msr & 0xffffffff; + EDX = ecx79_msr >> 32; + break; + case 0x88: case 0x89: case 0x8A: case 0x8B: + EAX = ecx8x_msr[ECX - 0x88] & 0xffffffff; + EDX = ecx8x_msr[ECX - 0x88] >> 32; + break; + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: + EAX = msr_ia32_pmc[ECX - 0xC1] & 0xffffffff; + EDX = msr_ia32_pmc[ECX - 0xC1] >> 32; + break; + case 0xFE: + EAX = mtrr_cap_msr & 0xffffffff; + EDX = mtrr_cap_msr >> 32; + break; + case 0x116: + EAX = ecx116_msr & 0xffffffff; + EDX = ecx116_msr >> 32; + break; + case 0x118: case 0x119: case 0x11A: case 0x11B: + EAX = ecx11x_msr[ECX - 0x118] & 0xffffffff; + EDX = ecx11x_msr[ECX - 0x118] >> 32; + break; + case 0x11E: + EAX = ecx11e_msr & 0xffffffff; + EDX = ecx11e_msr >> 32; + break; + case 0x174: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX &= 0xFFFF0000; + EAX |= cs_msr; + break; + case 0x175: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = esp_msr; + break; + case 0x176: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = eip_msr; + break; + case 0x186: + EAX = ecx186_msr & 0xffffffff; + EDX = ecx186_msr >> 32; + break; + case 0x187: + EAX = ecx187_msr & 0xffffffff; + EDX = ecx187_msr >> 32; + break; + case 0x1E0: + EAX = ecx1e0_msr & 0xffffffff; + EDX = ecx1e0_msr >> 32; + break; + case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: + if (ECX & 1) + { + EAX = mtrr_physmask_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physmask_msr[(ECX - 0x200) >> 1] >> 32; + } + else + { + EAX = mtrr_physbase_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physbase_msr[(ECX - 0x200) >> 1] >> 32; + } + break; + case 0x250: + EAX = mtrr_fix64k_8000_msr & 0xffffffff; + EDX = mtrr_fix64k_8000_msr >> 32; + break; + case 0x258: + EAX = mtrr_fix16k_8000_msr & 0xffffffff; + EDX = mtrr_fix16k_8000_msr >> 32; + break; + case 0x259: + EAX = mtrr_fix16k_a000_msr & 0xffffffff; + EDX = mtrr_fix16k_a000_msr >> 32; + break; + case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: + EAX = mtrr_fix4k_msr[ECX - 0x268] & 0xffffffff; + EDX = mtrr_fix4k_msr[ECX - 0x268] >> 32; + break; + case 0x277: + EAX = pat_msr & 0xffffffff; + EDX = pat_msr >> 32; + break; + case 0x2FF: + EAX = mtrr_deftype_msr & 0xffffffff; + EDX = mtrr_deftype_msr >> 32; + break; + case 0x570: + EAX = ecx570_msr & 0xffffffff; + EDX = ecx570_msr >> 32; + break; + default: +i686_invalid_rdmsr: + x86gpf(NULL, 0); + break; + } + break; +#endif +#endif + } +} + +void cpu_WRMSR() +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_WINCHIP: + case CPU_WINCHIP2: + switch (ECX) + { + case 0x02: + msr.tr1 = EAX & 2; + break; + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x11: + msr.cesr = EAX & 0xff00ff; + break; + case 0x107: + msr.fcr = EAX; + 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)) && machines[machine].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 + CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; + break; + case 0x108: + msr.fcr2 = EAX | ((uint64_t)EDX << 32); + break; + case 0x109: + msr.fcr3 = EAX | ((uint64_t)EDX << 32); + break; + } + break; + + case CPU_K5: + case CPU_5K86: + case CPU_K6: + case CPU_K6_2: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: + switch (ECX) + { + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x83: + ecx83_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000081: + star = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000084: + sfmask = EAX | ((uint64_t)EDX << 32); + break; + } + break; + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + +#ifdef DEV_BRANCH +#ifdef USE_I686 + case CPU_PENTIUMPRO: + case CPU_PENTIUM2D: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x17: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type != CPU_PENTIUM2D) goto i686_invalid_wrmsr; + ecx17_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x1B: + apic_base_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x79: + ecx79_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x88: case 0x89: case 0x8A: case 0x8B: + ecx8x_msr[ECX - 0x88] = EAX | ((uint64_t)EDX << 32); + break; + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: + msr_ia32_pmc[ECX - 0xC1] = EAX | ((uint64_t)EDX << 32); + break; + case 0xFE: + mtrr_cap_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x116: + ecx116_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x118: case 0x119: case 0x11A: case 0x11B: + ecx11x_msr[ECX - 0x118] = EAX | ((uint64_t)EDX << 32); + break; + case 0x11E: + ecx11e_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x174: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + cs_msr = EAX & 0xFFFF; + break; + case 0x175: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + esp_msr = EAX; + break; + case 0x176: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + eip_msr = EAX; + break; + case 0x186: + ecx186_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x187: + ecx187_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x1E0: + ecx1e0_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: + if (ECX & 1) + mtrr_physmask_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + else + mtrr_physbase_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + break; + case 0x250: + mtrr_fix64k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x258: + mtrr_fix16k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x259: + mtrr_fix16k_a000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: + mtrr_fix4k_msr[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); + break; + case 0x277: + pat_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x2FF: + mtrr_deftype_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x570: + ecx570_msr = EAX | ((uint64_t)EDX << 32); + break; + default: +i686_invalid_wrmsr: + x86gpf(NULL, 0); + break; + } + break; +#endif +#endif + } +} + +static int cyrix_addr; + +static void cpu_write(uint16_t addr, uint8_t val, void *priv) +{ + if (addr == 0xf0) { + /* Writes to F0 clear FPU error and deassert the interrupt. */ + if (is286) + picintc(1 << 13); + else + nmi = 0; + return; + } else if (addr >= 0xf1) + return; /* FPU stuff */ + + if (!(addr & 1)) + cyrix_addr = val; + else switch (cyrix_addr) + { + case 0xc0: /*CCR0*/ + ccr0 = val; + break; + case 0xc1: /*CCR1*/ + ccr1 = val; + break; + case 0xc2: /*CCR2*/ + ccr2 = val; + break; + case 0xc3: /*CCR3*/ + ccr3 = val; + break; + case 0xe8: /*CCR4*/ + if ((ccr3 & 0xf0) == 0x10) + { + ccr4 = val; + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_Cx6x86) + { + if (val & 0x80) + CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpuid_model; + else + CPUID = 0; + } + } + break; + case 0xe9: /*CCR5*/ + if ((ccr3 & 0xf0) == 0x10) + ccr5 = val; + break; + case 0xea: /*CCR6*/ + if ((ccr3 & 0xf0) == 0x10) + ccr6 = val; + break; + } +} + +static uint8_t cpu_read(uint16_t addr, void *priv) +{ + if (addr >= 0xf0) + return 0xff; /* FPU stuff */ + + if (addr & 1) + { + switch (cyrix_addr) + { + case 0xc0: return ccr0; + case 0xc1: return ccr1; + case 0xc2: return ccr2; + case 0xc3: return ccr3; + case 0xe8: return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + case 0xe9: return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + case 0xea: return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + case 0xfe: return machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cyrix_id & 0xff; + case 0xff: return machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cyrix_id >> 8; + } + if ((cyrix_addr & 0xf0) == 0xc0) return 0xff; + if (cyrix_addr == 0x20 && machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_Cx5x86) return 0xff; + } + return 0xff; +} + + +void +#ifdef USE_DYNAREC +x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f, + const OpFn *dynarec_opcodes, const OpFn *dynarec_opcodes_0f) +{ + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; + x86_dynarec_opcodes = dynarec_opcodes; + x86_dynarec_opcodes_0f = dynarec_opcodes_0f; +} +#else +x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f) +{ + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; +} +#endif + + +void +cpu_update_waitstates(void) +{ + cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + + if (is486) + cpu_prefetch_width = 16; + else + cpu_prefetch_width = cpu_16bitbus ? 2 : 4; + + if (cpu_cache_int_enabled) + { + /* Disable prefetch emulation */ + cpu_prefetch_cycles = 0; + } + else if (cpu_waitstates && (cpu_s->cpu_type >= CPU_286 && cpu_s->cpu_type <= CPU_386DX)) + { + /* Waitstates override */ + cpu_prefetch_cycles = cpu_waitstates+1; + cpu_cycles_read = cpu_waitstates+1; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); + cpu_cycles_write = cpu_waitstates+1; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); + } + else if (cpu_cache_ext_enabled) + { + /* Use cache timings */ + cpu_prefetch_cycles = cpu_s->cache_read_cycles; + cpu_cycles_read = cpu_s->cache_read_cycles; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_read_cycles; + cpu_cycles_write = cpu_s->cache_write_cycles; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_write_cycles; + } + else + { + /* Use memory timings */ + cpu_prefetch_cycles = cpu_s->mem_read_cycles; + cpu_cycles_read = cpu_s->mem_read_cycles; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_read_cycles; + 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; +} diff --git a/src/cpu_new/cpu.h b/src/cpu_new/cpu.h new file mode 100644 index 000000000..6bf8c9a58 --- /dev/null +++ b/src/cpu_new/cpu.h @@ -0,0 +1,504 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CPU type handler. + * + * Version: @(#)cpu.h 1.0.13 2018/11/14 + * + * Authors: Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016,2018 Miran Grca. + */ +#ifndef EMU_CPU_H +# define EMU_CPU_H + + +#define CPU_8088 0 /* 808x class CPUs */ +#define CPU_8086 1 +#define CPU_286 2 /* 286 class CPUs */ +#define CPU_386SX 3 /* 386 class CPUs */ +#define CPU_386DX 4 +#define CPU_IBM386SLC 5 +#define CPU_IBM486SLC 6 +#define CPU_IBM486BL 7 +#define CPU_RAPIDCAD 8 +#define CPU_486SLC 9 +#define CPU_486DLC 10 +#define CPU_i486SX 11 /* 486 class CPUs */ +#define CPU_Am486SX 12 +#define CPU_Cx486S 13 +#define CPU_i486DX 14 +#define CPU_Am486DX 15 +#define CPU_Cx486DX 16 +#define CPU_iDX4 17 +#define CPU_Cx5x86 18 +#define CPU_WINCHIP 19 /* 586 class CPUs */ +#define CPU_WINCHIP2 20 +#define CPU_PENTIUM 21 +#define CPU_PENTIUMMMX 22 +#define CPU_Cx6x86 23 +#define CPU_Cx6x86MX 24 +#define CPU_Cx6x86L 25 +#define CPU_CxGX1 26 +#define CPU_K5 27 +#define CPU_5K86 28 +#define CPU_K6 29 +#define CPU_K6_2 30 +#define CPU_K6_3 31 +#define CPU_K6_2P 32 +#define CPU_K6_3P 33 +#define CPU_PENTIUMPRO 34 /* 686 class CPUs */ +#define CPU_PENTIUM2D 35 + +#define MANU_INTEL 0 +#define MANU_AMD 1 +#define MANU_CYRIX 2 +#define MANU_IDT 3 + +#define CPU_SUPPORTS_DYNAREC 1 +#define CPU_REQUIRES_DYNAREC 2 +#define CPU_ALTERNATE_XTAL 4 + + +typedef struct { + const char*name; + int cpu_type; + int rspeed; + double multi; + int pci_speed; + uint32_t edx_reset; + uint32_t cpuid_model; + uint16_t cyrix_id; + uint8_t cpu_flags; + int8_t mem_read_cycles, mem_write_cycles; + int8_t cache_read_cycles, cache_write_cycles; + int8_t atclk_div; +} CPU; + +extern CPU cpus_8088[]; +extern CPU cpus_8086[]; +extern CPU cpus_286[]; +extern CPU cpus_i386SX[]; +extern CPU cpus_i386DX[]; +extern CPU cpus_Am386SX[]; +extern CPU cpus_Am386DX[]; +extern CPU cpus_486SLC[]; +extern CPU cpus_486DLC[]; +extern CPU cpus_IBM386SLC[]; +extern CPU cpus_IBM486SLC[]; +extern CPU cpus_IBM486BL[]; +extern CPU cpus_i486S1[]; +extern CPU cpus_Am486S1[]; +extern CPU cpus_Cx486S1[]; +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_Pentium5V50[]; +extern CPU cpus_PentiumS5[]; +extern CPU cpus_Pentium3V[]; +extern CPU cpus_K5[]; +extern CPU cpus_K56[]; +extern CPU cpus_K56_SS7[]; +extern CPU cpus_Pentium[]; +extern CPU cpus_6x863V[]; +extern CPU cpus_6x86[]; +extern CPU cpus_6x86SS7[]; +#ifdef DEV_BRANCH +#ifdef USE_I686 +extern CPU cpus_PentiumPro[]; +extern CPU cpus_Pentium2[]; +extern CPU cpus_Pentium2D[]; +#endif +#endif + + +#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 CPL ((cpu_state.seg_cs.access>>5)&3) + +#define IOPL ((cpu_state.flags>>12)&3) + +#define IOPLp ((!(msw&1)) || (CPL<=IOPL)) + + +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 { + 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; + +typedef struct { + uint32_t tr1, tr12; + uint32_t cesr; + uint32_t fcr; + uint64_t fcr2, fcr3; +} msr_t; + +typedef union { + uint32_t l; + uint16_t w; +} cr0_t; + + +struct _cpustate_ { + 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; + int32_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; + uint32_t last_ea; + + 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; + + uint16_t flags, eflags; +} cpu_state; + +/*The cpu_state.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_FLAGS 0xffff + +/*If the cpu_state.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 + +#ifdef __MSC__ +# define COMPILE_TIME_ASSERT(expr) /*nada*/ +#else +# ifdef EXTREME_DEBUG +# define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; +# else +# define COMPILE_TIME_ASSERT(expr) /*nada*/ +# endif +#endif + +COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128) + +#define cpu_state_offset(MEMBER) ((uint8_t)((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128)) + +#define EAX cpu_state.regs[0].l +#define AX cpu_state.regs[0].w +#define AL cpu_state.regs[0].b.l +#define AH cpu_state.regs[0].b.h +#define ECX cpu_state.regs[1].l +#define CX cpu_state.regs[1].w +#define CL cpu_state.regs[1].b.l +#define CH cpu_state.regs[1].b.h +#define EDX cpu_state.regs[2].l +#define DX cpu_state.regs[2].w +#define DL cpu_state.regs[2].b.l +#define DH cpu_state.regs[2].b.h +#define EBX cpu_state.regs[3].l +#define BX cpu_state.regs[3].w +#define BL cpu_state.regs[3].b.l +#define BH cpu_state.regs[3].b.h +#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 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 cycles cpu_state._cycles + +#define cpu_rm cpu_state.rm_data.rm_mod_reg.rm +#define cpu_mod cpu_state.rm_data.rm_mod_reg.mod +#define cpu_reg cpu_state.rm_data.rm_mod_reg.reg + +#define CR4_TSD (1 << 2) +#define CR4_DE (1 << 3) +#define CR4_MCE (1 << 6) +#define CR4_PCE (1 << 8) +#define CR4_OSFXSR (1 << 9) + + +/* Global variables. */ +extern int cpu_iscyrix; +extern int cpu_16bitbus; +extern int cpu_busspeed; +extern int cpu_multi; +extern int cpu_cyrix_alignment; /*Cyrix 5x86/6x86 only has data misalignment + penalties when crossing 8-byte boundaries*/ + +extern int is8086, is286, is386, is486; +extern int isibmcpu; +extern int is_rapidcad; +extern int hasfpu; +#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) + +extern uint32_t cpu_features; + +extern int in_smm, smi_line, smi_latched; +extern uint32_t smbase; + +extern uint16_t cpu_cur_status; +extern uint64_t cpu_CR4_mask; +extern uint64_t tsc; +extern msr_t msr; +extern uint8_t opcode; +extern int insc; +extern int fpucount; +extern float mips,flops; +extern int clockrate; +extern int cgate16; +extern int cpl_override; +extern int CPUID; +extern uint64_t xt_cpu_multi; +extern int isa_cycles; +extern uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; +extern int ins,output; +extern uint32_t pccache; +extern uint8_t *pccache2; + +extern double bus_timing; +extern uint64_t pmc[2]; +extern uint16_t temp_seg_data[4]; +extern uint16_t cs_msr; +extern uint32_t esp_msr; +extern uint32_t eip_msr; + +/* For the AMD K6. */ +extern uint64_t star; + +#define FPU_CW_Reserved_Bits (0xe0c0) + +extern cr0_t CR0; +#define cr0 CR0.l +#define msw CR0.w +extern uint32_t cr2, cr3, cr4; +extern uint32_t dr[8]; + + +/*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*/ +extern x86seg gdt,ldt,idt,tr; +extern x86seg _oldds; +#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 fs_seg cpu_state.seg_fs.base +#define gs cpu_state.seg_gs.base + + +#define ISA_CYCLES(x) (x * isa_cycles) + +extern int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; +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; +extern int cpu_pci_speed; + +extern int timing_rr; +extern int timing_mr, timing_mrl; +extern int timing_rm, timing_rml; +extern int timing_mm, timing_mml; +extern int timing_bt, timing_bnt; +extern int timing_int, timing_int_rm, timing_int_v86, timing_int_pm; +extern int timing_int_pm_outer, timing_iret_rm, timing_iret_v86, timing_iret_pm; +extern int timing_iret_pm_outer, timing_call_rm, timing_call_pm; +extern int timing_call_pm_gate, timing_call_pm_gate_inner; +extern int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +extern int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; +extern int timing_misaligned; + + +extern CPU cpus_pcjr[]; // FIXME: should be in machine file! +extern CPU cpus_europc[]; // FIXME: should be in machine file! +extern CPU cpus_pc1512[]; // FIXME: should be in machine file! +extern CPU cpus_ibmat[]; // FIXME: should be in machine file! +extern CPU cpus_ibmxt286[]; // FIXME: should be in machine file! +extern CPU cpus_ps1_m2011[]; // FIXME: should be in machine file! +extern CPU cpus_ps2_m30_286[]; // FIXME: should be in machine file! +#if 0 +extern CPU cpus_acer[]; // FIXME: should be in machine file! +#endif + + +/* Functions. */ +extern int cpu_has_feature(int feature); + +int loadseg(uint16_t seg, x86seg *s); +void loadseg_dynarec(uint16_t seg, x86seg *s); +void loadcs(uint16_t seg); + +extern char *cpu_current_pc(char *bufp); + +extern void cpu_update_waitstates(void); +extern void cpu_set(void); + +extern void cpu_CPUID(void); +extern void cpu_RDMSR(void); +extern void cpu_WRMSR(void); + +extern int checkio(int port); +extern void codegen_block_end(void); +extern void codegen_reset(void); +extern void cpu_set_edx(void); +extern int divl(uint32_t val); +extern void execx86(int cycs); +extern void enter_smm(); +extern void leave_smm(); +extern void exec386(int cycs); +extern void exec386_dynarec(int cycs); +extern int idivl(int32_t val); +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); +extern void resetmcr(void); +extern void resetx86(void); +extern void refreshread(void); +extern void resetreadlookup(void); +extern void softresetx86(void); +extern void x86_int(int num); +extern void x86_int_sw(int num); +extern int x86_int_sw_rm(int num); +extern void x86gpf(char *s, uint16_t error); +extern void x86np(char *s, uint16_t error); +extern void x86ss(char *s, uint16_t error); +extern void x86ts(char *s, uint16_t error); + +#ifdef ENABLE_808X_LOG +extern void dumpregs(int __force); +extern void x87_dumpregs(void); +extern void x87_reset(void); +#endif + +extern int cpu_effective, cpu_alt_reset; +extern void cpu_dynamic_switch(int new_cpu); + + +#endif /*EMU_CPU_H*/ diff --git a/src/cpu_new/cpu_table.c b/src/cpu_new/cpu_table.c new file mode 100644 index 000000000..b6795074c --- /dev/null +++ b/src/cpu_new/cpu_table.c @@ -0,0 +1,678 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Define all known processor types. + * + * 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 + * + * Version: @(#)cpu_table.c 1.0.7 2019/10/21 + * + * Authors: Sarah Walker, + * leilei, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 leilei. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../machine/machine.h" + + +CPU cpus_8088[] = { + /*8088 standard*/ + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, 7159092, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/8", CPU_8088, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/10", CPU_8088, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/12", CPU_8088, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/16", CPU_8088, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_pcjr[] = { + /*8088 PCjr*/ + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_europc[] = { + /*8088 EuroPC*/ + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8088/9.54", CPU_8088, 9545456, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_8086[] = { + /*8086 standard*/ + {"8086/7.16", CPU_8086, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8086/8", CPU_8086, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/9.54", CPU_8086, 9545456, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8086/10", CPU_8086, 10000000, 2, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/12", CPU_8086, 12000000, 3, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/16", CPU_8086, 16000000, 4, 0, 0, 0, 0, 0, 0,0,0,0, 2}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_pc1512[] = { + /*8086 Amstrad*/ + {"8086/8", CPU_8086, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_286[] = { + /*286*/ + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/8", CPU_286, 8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 12500000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_ibmat[] = { + /*286*/ + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"286/8", CPU_286, 8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_ibmxt286[] = { + /*286*/ + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_ps1_m2011[] = { + /*286*/ + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 9} +}; + +CPU cpus_ps2_m30_286[] = { + /*286*/ + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 12500000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_i386SX[] = { + /*i386SX*/ + {"i386SX/16", CPU_386SX, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"i386SX/20", CPU_386SX, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/25", CPU_386SX, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/33", CPU_386SX, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"i386SX/40", CPU_386SX, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_i386DX[] = { + /*i386DX/RapidCAD*/ + {"i386DX/16", CPU_386DX, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2}, + {"i386DX/20", CPU_386DX, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/25", CPU_386DX, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/33", CPU_386DX, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"i386DX/40", CPU_386DX, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"RapidCAD/25", CPU_RAPIDCAD, 25000000, 1, 0, 0x0430, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"RapidCAD/33", CPU_RAPIDCAD, 33333333, 1, 0, 0x0430, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"RapidCAD/40", CPU_RAPIDCAD, 40000000, 1, 0, 0x0430, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"i486DX/33", CPU_i486DX, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_Am386SX[] = { + /*Am386SX*/ + {"Am386SX/16", CPU_386SX, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"Am386SX/20", CPU_386SX, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/25", CPU_386SX, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/33", CPU_386SX, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386SX/40", CPU_386SX, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_Am386DX[] = { + /*Am386DX*/ + {"Am386DX/25", CPU_386DX, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386DX/33", CPU_386DX, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386DX/40", CPU_386DX, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_486SLC[] = { + /*Cx486SLC*/ + {"Cx486SLC/20", CPU_486SLC, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/25", CPU_486SLC, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/33", CPU_486SLC, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, + {"Cx486SRx2/32", CPU_486SLC, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6, 4}, + {"Cx486SRx2/40", CPU_486SLC, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"Cx486SRx2/50", CPU_486SLC, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_IBM386SLC[] = { + /*IBM 386SLC*/ + {"386SLC/16", CPU_IBM386SLC, 16000000, 1, 0, 0x300, 0, 0, 0, 3,3,3,3, 2}, + {"386SLC/20", CPU_IBM386SLC, 20000000, 1, 0, 0x300, 0, 0, 0, 4,4,3,3, 3}, + {"386SLC/25", CPU_IBM386SLC, 25000000, 1, 0, 0x300, 0, 0, 0, 4,4,3,3, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_IBM486SLC[] = { + /*IBM 486SLC*/ + {"486SLC/33", CPU_IBM486SLC, 33333333, 1, 0, 0x400, 0, 0, 0, 6,6,3,3, 4}, + {"486SLC2/40", CPU_IBM486SLC, 40000000, 2, 0, 0x400, 0, 0, 0, 7,7,6,6, 5}, + {"486SLC2/50", CPU_IBM486SLC, 50000000, 2, 0, 0x400, 0, 0, 0, 8,8,6,6, 6}, + {"486SLC2/66", CPU_IBM486SLC, 66666666, 2, 0, 0x400, 0, 0, 0, 12,12,6,6, 8}, + {"486SLC3/60", CPU_IBM486SLC, 60000000, 3, 0, 0x400, 0, 0, 0, 12,12,9,9, 7}, + {"486SLC3/75", CPU_IBM486SLC, 75000000, 3, 0, 0x400, 0, 0, 0, 12,12,9,9, 9}, + {"486SLC3/100", CPU_IBM486SLC, 100000000, 3, 0, 0x400, 0, 0, 0, 18,18,9,9, 12}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_IBM486BL[] = { + /*IBM Blue Lightning*/ + {"486BL2/50", CPU_IBM486BL, 50000000, 2, 0, 0x400, 0, 0, 0, 8,8,6,6, 6}, + {"486BL2/66", CPU_IBM486BL, 66666666, 2, 0, 0x400, 0, 0, 0, 12,12,6,6, 8}, + {"486BL3/75", CPU_IBM486BL, 75000000, 3, 0, 0x400, 0, 0, 0, 12,12,9,9, 9}, + {"486BL3/100", CPU_IBM486BL, 100000000, 3, 0, 0x400, 0, 0, 0, 18,18,9,9, 12}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_486DLC[] = { + /*Cx486DLC*/ + {"Cx486DLC/25", CPU_486DLC, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4, 4,3,3, 3}, + {"Cx486DLC/33", CPU_486DLC, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6, 6,3,3, 4}, + {"Cx486DLC/40", CPU_486DLC, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7, 7,3,3, 5}, + {"Cx486DRx2/32", CPU_486DLC, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6, 6,6,6, 4}, + {"Cx486DRx2/40", CPU_486DLC, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"Cx486DRx2/50", CPU_486DLC, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"Cx486DRx2/66", CPU_486DLC, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6, 8}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; +CPU cpus_i486S1[] = { + /*i486*/ + {"i486SX/16", CPU_i486SX, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3, 3,3,3, 2}, + {"i486SX/20", CPU_i486SX, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486SX/25", CPU_i486SX, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486SX/33", CPU_i486SX, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"i486SX2/50", CPU_i486SX, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486SX2/66 (Q0569)", CPU_i486SX, 66666666, 2, 33333333, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 8}, + {"i486DX/25", CPU_i486DX, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486DX/33", CPU_i486DX, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"i486DX/50", CPU_i486DX, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,4,4, 6}, + {"i486DX2/40", CPU_i486DX, 40000000, 2, 20000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 7, 7,6,6, 5}, + {"i486DX2/50", CPU_i486DX, 50000000, 2, 25000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486DX2/66", CPU_i486DX, 66666666, 2, 33333333, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"iDX4 OverDrive 75", CPU_iDX4, 75000000, 3, 25000000, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, /*Only added the DX4 OverDrive as the others would be redundant*/ + {"iDX4 OverDrive 100", CPU_iDX4, 100000000, 3, 33333333, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; +CPU cpus_Am486S1[] = { + /*Am486*/ + {"Am486SX/33", CPU_Am486SX, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Am486SX/40", CPU_Am486SX, 40000000, 1, 40000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Am486SX2/50", CPU_Am486SX, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ + {"Am486SX2/66", CPU_Am486SX, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Am486DX/33", CPU_Am486DX, 33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Am486DX/40", CPU_Am486DX, 40000000, 1, 40000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Am486DX2/50", CPU_Am486DX, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"Am486DX2/66", CPU_Am486DX, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Am486DX2/80", CPU_Am486DX, 80000000, 2, 40000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; +CPU cpus_Cx486S1[] = { + /*Cyrix 486*/ + {"Cx486S/25", CPU_Cx486S, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, + {"Cx486S/33", CPU_Cx486S, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Cx486S/40", CPU_Cx486S, 40000000, 1, 40000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Cx486DX/33", CPU_Cx486DX, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Cx486DX/40", CPU_Cx486DX, 40000000, 1, 40000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Cx486DX2/50", CPU_Cx486DX, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"Cx486DX2/66", CPU_Cx486DX, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Cx486DX2/80", CPU_Cx486DX, 80000000, 2, 40000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +CPU cpus_i486[] = { + /*i486/P24T*/ + {"i486SX/16", CPU_i486SX, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3, 3,3,3, 2}, + {"i486SX/20", CPU_i486SX, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486SX/25", CPU_i486SX, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486SX/33", CPU_i486SX, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"i486SX2/50", CPU_i486SX, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486SX2/66 (Q0569)", CPU_i486SX, 66666666, 2, 33333333, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 8}, + {"i486DX/25", CPU_i486DX, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4, 4,3,3, 3}, + {"i486DX/33", CPU_i486DX, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"i486DX/50", CPU_i486DX, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8, 8,4,4, 6}, + {"i486DX2/40", CPU_i486DX, 40000000, 2, 20000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 7, 7,6,6, 5}, /*CPUID available on DX2, DX4, P24T, >= 40 MHz*/ + {"i486DX2/50", CPU_i486DX, 50000000, 2, 25000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486DX2/66", CPU_i486DX, 66666666, 2, 33333333, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"iDX4/75", CPU_iDX4, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, + {"iDX4/100", CPU_iDX4, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, + {"iDX4 OverDrive 75", CPU_iDX4, 75000000, 3, 25000000, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, + {"iDX4 OverDrive 100", CPU_iDX4, 100000000, 3, 33333333, 0x1480, 0x1480, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, + {"Pentium OverDrive 63", CPU_PENTIUM, 62500000, 5/2, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, 15/2}, + {"Pentium OverDrive 83", CPU_PENTIUM, 83333333, 5/2, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, 10}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_Am486[] = { + /*Am486/5x86*/ + {"Am486SX/33", CPU_Am486SX, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Am486SX/40", CPU_Am486SX, 40000000, 1, 40000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Am486SX2/50", CPU_Am486SX, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ + {"Am486SX2/66", CPU_Am486SX, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Am486DX/33", CPU_Am486DX, 33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Am486DX/40", CPU_Am486DX, 40000000, 1, 40000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Am486DX2/50", CPU_Am486DX, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"Am486DX2/66", CPU_Am486DX, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Am486DX2/80", CPU_Am486DX, 80000000, 2, 40000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"Am486DX4/75", CPU_Am486DX, 75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, + {"Am486DX4/90", CPU_Am486DX, 90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"Am486DX4/100", CPU_Am486DX, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"Am486DX4/120", CPU_Am486DX, 120000000, 3, 40000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"Am5x86/P75", CPU_Am486DX, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, + {"Am5x86/P75+", CPU_Am486DX, 150000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*The rare P75+ was indeed a triple-clocked 150 MHz according to research*/ + {"Am5x86/P90", CPU_Am486DX, 160000000, 4, 40000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20},/*160 MHz on a 40 MHz bus was a common overclock and "5x86/P90" was used by a number of BIOSes to refer to that configuration*/ + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +CPU cpus_Cx486[] = { + /*Cyrix 486*/ + {"Cx486S/25", CPU_Cx486S, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4, 4, 3, 3, 3}, + {"Cx486S/33", CPU_Cx486S, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Cx486S/40", CPU_Cx486S, 40000000, 1, 40000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Cx486DX/33", CPU_Cx486DX, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Cx486DX/40", CPU_Cx486DX, 40000000, 1, 40000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"Cx486DX2/50", CPU_Cx486DX, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8, 8, 6, 6, 6}, + {"Cx486DX2/66", CPU_Cx486DX, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12, 6, 6, 8}, + {"Cx486DX2/80", CPU_Cx486DX, 80000000, 2, 40000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"Cx486DX4/75", CPU_Cx486DX, 75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12, 9, 9, 9}, + {"Cx486DX4/100", CPU_Cx486DX, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + + /*Cyrix 5x86*/ + {"Cx5x86/80", CPU_Cx5x86, 80000000, 2, 40000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"Cx5x86/100", CPU_Cx5x86, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15, 9, 9, 12}, + {"Cx5x86/120", CPU_Cx5x86, 120000000, 3, 40000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"Cx5x86/133", CPU_Cx5x86, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +CPU cpus_6x863V[] = { + /*Cyrix 6x86*/ + {"Cx6x86/P90", CPU_Cx6x86, 80000000, 2, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, + {"Cx6x86/PR120+", CPU_Cx6x86, 100000000, 2, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"Cx6x86/PR133+", CPU_Cx6x86, 110000000, 2, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"Cx6x86/PR150+", CPU_Cx6x86, 120000000, 2, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Cx6x86/PR166+", CPU_Cx6x86, 133333333, 2, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86/PR200+", CPU_Cx6x86, 150000000, 2, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }; + +CPU cpus_6x86[] = { + /*Cyrix 6x86*/ + {"Cx6x86/P90", CPU_Cx6x86, 80000000, 2, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, + {"Cx6x86/PR120+", CPU_Cx6x86, 100000000, 2, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"Cx6x86/PR133+", CPU_Cx6x86, 110000000, 2, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"Cx6x86/PR150+", CPU_Cx6x86, 120000000, 2, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Cx6x86/PR166+", CPU_Cx6x86, 133333333, 2, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86/PR200+", CPU_Cx6x86, 150000000, 2, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, + + /*Cyrix 6x86L*/ + {"Cx6x86L/PR133+", CPU_Cx6x86L, 110000000, 2, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"Cx6x86L/PR150+", CPU_Cx6x86L, 120000000, 2, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Cx6x86L/PR166+", CPU_Cx6x86L, 133333333, 2, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86L/PR200+", CPU_Cx6x86L, 150000000, 2, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, + + /*Cyrix 6x86MX/MII*/ + {"Cx6x86MX/PR166", CPU_Cx6x86MX, 133333333, 2, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86MX/PR200", CPU_Cx6x86MX, 166666666, 5/2, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Cx6x86MX/PR233", CPU_Cx6x86MX, 187500000, 5/2, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2}, + {"Cx6x86MX/PR266", CPU_Cx6x86MX, 208333333, 5/2, 41666666, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, + {"MII/PR300", CPU_Cx6x86MX, 233333333, 7/2, 33333333, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,11,11, 28}, + {"MII/PR333", CPU_Cx6x86MX, 250000000, 3, 41666666, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 9, 9, 30}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }; + + CPU cpus_6x86SS7[] = { + /*Cyrix 6x86*/ + {"Cx6x86/P90", CPU_Cx6x86, 80000000, 2, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, + {"Cx6x86/PR120+", CPU_Cx6x86, 100000000, 2, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"Cx6x86/PR133+", CPU_Cx6x86, 110000000, 2, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"Cx6x86/PR150+", CPU_Cx6x86, 120000000, 2, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Cx6x86/PR166+", CPU_Cx6x86, 133333333, 2, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86/PR200+", CPU_Cx6x86, 150000000, 2, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, + + /*Cyrix 6x86L*/ + {"Cx6x86L/PR133+", CPU_Cx6x86L, 110000000, 2, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, + {"Cx6x86L/PR150+", CPU_Cx6x86L, 120000000, 2, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Cx6x86L/PR166+", CPU_Cx6x86L, 133333333, 2, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86L/PR200+", CPU_Cx6x86L, 150000000, 2, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 18}, + + /*Cyrix 6x86MX/MII*/ + {"Cx6x86MX/PR166", CPU_Cx6x86MX, 133333333, 2, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Cx6x86MX/PR200", CPU_Cx6x86MX, 166666666, 5/2, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Cx6x86MX/PR233", CPU_Cx6x86MX, 187500000, 5/2, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2}, + {"Cx6x86MX/PR266", CPU_Cx6x86MX, 208333333, 5/2, 41666666, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, + {"MII/PR300", CPU_Cx6x86MX, 233333333, 7/2, 33333333, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,11,11, 28}, + {"MII/PR333", CPU_Cx6x86MX, 250000000, 3, 41666666, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 9, 9, 30}, + {"MII/PR366", CPU_Cx6x86MX, 250000000, 5/2, 33333333, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 23,23, 7, 7, 30}, + {"MII/PR400", CPU_Cx6x86MX, 285000000, 3, 31666666, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 34}, + {"MII/PR433", CPU_Cx6x86MX, 300000000, 3, 33333333, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 9, 9, 36}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }; + +CPU cpus_WinChip[] = { + /*IDT WinChip*/ + {"WinChip 75", CPU_WINCHIP, 75000000, 3/2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 9}, + {"WinChip 90", CPU_WINCHIP, 90000000, 3/2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 21/2}, + {"WinChip 100", CPU_WINCHIP, 100000000, 3/2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 12}, + {"WinChip 120", CPU_WINCHIP, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 14}, + {"WinChip 133", CPU_WINCHIP, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 16}, + {"WinChip 150", CPU_WINCHIP, 150000000, 5/2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 35/2}, + {"WinChip 166", CPU_WINCHIP, 166666666, 5/2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 40}, + {"WinChip 180", CPU_WINCHIP, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 21}, + {"WinChip 200", CPU_WINCHIP, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, + {"WinChip 225", CPU_WINCHIP, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 27}, + {"WinChip 240", CPU_WINCHIP, 240000000, 4, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 28}, + {"WinChip 2/200", CPU_WINCHIP2, 200000000, 3, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, + {"WinChip 2/225", CPU_WINCHIP2, 225000000, 3, 37500000, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 27}, + {"WinChip 2/240", CPU_WINCHIP2, 240000000, 4, 30000000, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, + {"WinChip 2/250", CPU_WINCHIP2, 250000000, 3, 41666667, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, + {"WinChip 2A/200", CPU_WINCHIP2, 200000000, 3, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, + {"WinChip 2A/233", CPU_WINCHIP2, 233333333, 7/2, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, (7*8)/2}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +CPU cpus_WinChip_SS7[] = { + /*IDT WinChip*/ + {"WinChip 75", CPU_WINCHIP, 75000000, 3/2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 9}, + {"WinChip 90", CPU_WINCHIP, 90000000, 3/2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 21/2}, + {"WinChip 100", CPU_WINCHIP, 100000000, 3/2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 12}, + {"WinChip 120", CPU_WINCHIP, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 14}, + {"WinChip 133", CPU_WINCHIP, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12, 12, 6, 6, 16}, + {"WinChip 150", CPU_WINCHIP, 150000000, 5/2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 35/2}, + {"WinChip 166", CPU_WINCHIP, 166666666, 5/2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 40}, + {"WinChip 180", CPU_WINCHIP, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 21}, + {"WinChip 200", CPU_WINCHIP, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 24}, + {"WinChip 225", CPU_WINCHIP, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 27}, + {"WinChip 240", CPU_WINCHIP, 240000000, 4, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 28}, + {"WinChip 2/200", CPU_WINCHIP2, 200000000, 3, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 3*8}, + {"WinChip 2/225", CPU_WINCHIP2, 225000000, 3, 37500000, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 3*9}, + {"WinChip 2/240", CPU_WINCHIP2, 240000000, 4, 30000000, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, + {"WinChip 2/250", CPU_WINCHIP2, 250000000, 3, 41666667, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, + {"WinChip 2A/200", CPU_WINCHIP2, 200000000, 3, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, 3*8}, + {"WinChip 2A/233", CPU_WINCHIP2, 233333333, 7/2, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 21, 21, 9, 9, (7*8)/2}, + {"WinChip 2A/266", CPU_WINCHIP2, 233333333, 7/3, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 21, 21, 7, 7, 28}, + {"WinChip 2A/300", CPU_WINCHIP2, 250000000, 5/2, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 8, 8, 30}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +CPU cpus_Pentium5V[] = { + /*Intel Pentium (5V, socket 4)*/ + {"Pentium 60", CPU_PENTIUM, 60000000, 1, 30000000, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, + {"Pentium 66", CPU_PENTIUM, 66666666, 1, 33333333, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, + {"Pentium OverDrive 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_Pentium5V50[] = { + /*Intel Pentium (5V, socket 4, including 50 MHz FSB)*/ + {"Pentium 50 (Q0399)", CPU_PENTIUM, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4,3,3, 6}, + {"Pentium 60", CPU_PENTIUM, 60000000, 1, 30000000, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, + {"Pentium 66", CPU_PENTIUM, 66666666, 1, 33333333, 0x517, 0x517, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, + {"Pentium OverDrive 100", CPU_PENTIUM, 100000000, 2, 25000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8,6,6, 12}, + {"Pentium OverDrive 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_PentiumS5[] = { + /*Intel Pentium (Socket 5)*/ + {"Pentium 75", CPU_PENTIUM, 75000000, 3/2, 25000000, 0x522, 0x522, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 3/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"Pentium 90", CPU_PENTIUM, 90000000, 3/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, + {"Pentium 100/50", CPU_PENTIUM, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, + {"Pentium 100/66", CPU_PENTIUM, 100000000, 3/2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, + {"Pentium 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + + /*Intel Pentium OverDrive*/ + {"Pentium OverDrive 125", CPU_PENTIUM, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 16}, + {"Pentium OverDrive 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 40}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 5/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 5/2, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 5/2, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, 180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_Pentium3V[] = { + /*Intel Pentium*/ + {"Pentium 75", CPU_PENTIUM, 75000000, 3/2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 3/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium 90", CPU_PENTIUM, 90000000, 3/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"Pentium 100/50", CPU_PENTIUM, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"Pentium 100/66", CPU_PENTIUM, 100000000, 3/2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"Pentium 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Pentium 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Pentium 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium 200", CPU_PENTIUM, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + + /*Intel Pentium OverDrive*/ + {"Pentium OverDrive 125", CPU_PENTIUM, 125000000, 5/2, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, + {"Pentium OverDrive 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 5/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 5/2, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 5/2, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, 180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +CPU cpus_Pentium[] = { + /*Intel Pentium*/ + {"Pentium 75", CPU_PENTIUM, 75000000, 3/2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 3/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium 90", CPU_PENTIUM, 90000000, 3/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"Pentium 100/50", CPU_PENTIUM, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, + {"Pentium 100/66", CPU_PENTIUM, 100000000, 3/2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"Pentium 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Pentium 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Pentium 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium 200", CPU_PENTIUM, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + + /*Intel Pentium MMX*/ + {"Pentium MMX 166", CPU_PENTIUMMMX, 166666666, 5/2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"Pentium MMX 233", CPU_PENTIUMMMX, 233333333, 7/2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, 150000000, 5/2, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 166666666, 5/2, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, 233333333, 7/2, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, 300000000, 9/2, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + + /*Intel Pentium OverDrive*/ + {"Pentium OverDrive 125", CPU_PENTIUM, 125000000, 5/2, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, + {"Pentium OverDrive 150", CPU_PENTIUM, 150000000, 5/2, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 5/2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 5/2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 5/2, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 5/2, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, 180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, 200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; +CPU cpus_K5[] = { + /*AMD K5 (Socket 5)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 75000000, 3/2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 3/2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, + {"K5 (5k86) 90 (P90)", CPU_K5, 90000000, 3/2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 90000000, 3/2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, + {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 3/2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, + {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 3/2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 150000000, 5/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 5/2, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_K56[] = { + /*AMD K5 (Socket 7)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 75000000, 3/2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 3/2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"K5 (5k86) 90 (P90)", CPU_K5, 90000000, 3/2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 90000000, 3/2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 3/2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 3/2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 150000000, 5/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 5/2, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + + /*AMD K6 (Socket 7*/ + {"K6 (Model 6) 166", CPU_K6, 166666666, 5/2, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"K6 (Model 6) 200", CPU_K6, 200000000, 3, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"K6 (Model 6) 233", CPU_K6, 233333333, 7/2, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 10, 10, 28}, + {"K6 (Model 7) 200", CPU_K6, 200000000, 3, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"K6 (Model 7) 233", CPU_K6, 233333333, 7/2, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 10, 10, 28}, + {"K6 (Model 7) 266", CPU_K6, 266666666, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24, 12, 12, 32}, + {"K6 (Model 7) 300", CPU_K6, 300000000, 9/2, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 13, 13, 36}, + {"K6-2/233", CPU_K6_2, 233333333, 7/2, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 10, 10, 28}, + {"K6-2/266", CPU_K6_2, 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, 300000000, 9/2, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27, 13, 13, 36}, + {"K6-2/366", CPU_K6_2, 366666666, 11/2, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33,33, 17, 17, 44}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +CPU cpus_K56_SS7[] = { + /*AMD K5 (Socket 7)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 75000000, 3/2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 3/2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"K5 (5k86) 90 (P90)", CPU_K5, 90000000, 3/2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 90000000, 3/2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, + {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 3/2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 3/2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 150000000, 5/2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 5/2, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + + /*AMD K6 (Socket 7)*/ + {"K6 (Model 6) 166", CPU_K6, 166666666, 5/2, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"K6 (Model 6) 200", CPU_K6, 200000000, 3, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"K6 (Model 6) 233", CPU_K6, 233333333, 7/2, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"K6 (Model 7) 200", CPU_K6, 200000000, 3, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + {"K6 (Model 7) 233", CPU_K6, 233333333, 7/2, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"K6 (Model 7) 266", CPU_K6, 266666666, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"K6 (Model 7) 300", CPU_K6, 300000000, 9/2, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + + /*AMD K6-2 (Socket 7/Super Socket 7)*/ + {"K6-2/233", CPU_K6_2, 233333333, 7/2, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21, 21, 10, 10, 28}, + {"K6-2/266", CPU_K6_2, 266666666, 4, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24, 24, 12, 12, 32}, + {"K6-2/300", CPU_K6_2, 300000000, 3, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27, 27, 9, 9, 36}, + {"K6-2/333", CPU_K6_2, 332500000, 7/2, 31666667, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 30, 30, 11, 11, 40}, + {"K6-2/350", CPU_K6_2, 350000000, 7/2, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32, 32, 11, 11, 42}, + {"K6-2/366", CPU_K6_2, 366666666, 11/2, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33, 33, 17, 17, 44}, + {"K6-2/380", CPU_K6_2, 380000000, 4, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 34, 34, 12, 12, 46}, + {"K6-2/400", CPU_K6_2, 400000000, 4, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, + {"K6-2/450", CPU_K6_2, 450000000, 9/2, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, + {"K6-2/475", CPU_K6_2, 475000000, 5, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, + {"K6-2/500", CPU_K6_2, 500000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, + {"K6-2/533", CPU_K6_2, 533333333, 11/2, 32323232, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 48, 48, 17, 17, 64}, + {"K6-2/550", CPU_K6_2, 550000000, 11/2, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 50, 50, 17, 17, 66}, + + /*AMD K6-2+/K6-3/K6-3+ (Super Socket 7)*/ + {"K6-2+/450", CPU_K6_2P, 450000000, 9/2, 33333333, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, + {"K6-2+/475", CPU_K6_2P, 475000000, 5, 31666667, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, + {"K6-2+/500", CPU_K6_2P, 500000000, 5, 33333333, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, + {"K6-2+/533", CPU_K6_2P, 533333333, 11/2, 32323232, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 48, 48, 17, 17, 64}, + {"K6-2+/550", CPU_K6_2P, 550000000, 11/2, 32333333, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 50, 50, 17, 17, 66}, + {"K6-III/400", CPU_K6_3, 400000000, 4, 33333333, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, + {"K6-III/450", CPU_K6_3, 450000000, 9/2, 33333333, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, + {"K6-III+/400", CPU_K6_3P, 400000000, 4, 33333333, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, + {"K6-III+/450", CPU_K6_3P, 450000000, 9/2, 33333333, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, + {"K6-III+/475", CPU_K6_3P, 475000000, 5, 31666667, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, + {"K6-III+/500", CPU_K6_3P, 500000000, 5, 33333333, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +#ifdef DEV_BRANCH +#ifdef USE_I686 +CPU cpus_PentiumPro[] = { + /*Intel Pentium Pro*/ + {"Pentium Pro 50", CPU_PENTIUMPRO, 50000000, 1, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, + {"Pentium Pro 60" , CPU_PENTIUMPRO, 60000000, 1, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, + {"Pentium Pro 66" , CPU_PENTIUMPRO, 66666666, 1, 33333333, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, + {"Pentium Pro 75", CPU_PENTIUMPRO, 75000000, 3/2, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium Pro 150", CPU_PENTIUMPRO, 150000000, 5/2, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, + {"Pentium Pro 166", CPU_PENTIUMPRO, 166666666, 5/2, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, + {"Pentium Pro 180", CPU_PENTIUMPRO, 180000000, 3, 30000000, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 21}, + {"Pentium Pro 200", CPU_PENTIUMPRO, 200000000, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, + + /*Intel Pentium II OverDrive*/ + {"Pentium II Overdrive 50", CPU_PENTIUM2D, 50000000, 1, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4, 3, 3, 6}, + {"Pentium II Overdrive 60", CPU_PENTIUM2D, 60000000, 1, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 7}, + {"Pentium II Overdrive 66", CPU_PENTIUM2D, 66666666, 1, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6, 3, 3, 8}, + {"Pentium II Overdrive 75", CPU_PENTIUM2D, 75000000, 3/2, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"Pentium II Overdrive 210", CPU_PENTIUM2D, 210000000, 7/2, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, + {"Pentium II Overdrive 233", CPU_PENTIUM2D, 233333333, 7/2, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"Pentium II Overdrive 240", CPU_PENTIUM2D, 240000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 29}, + {"Pentium II Overdrive 266", CPU_PENTIUM2D, 266666666, 4, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"Pentium II Overdrive 270", CPU_PENTIUM2D, 270000000, 9/2, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 33}, + {"Pentium II Overdrive 300/66", CPU_PENTIUM2D, 300000000, 9/2, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, + {"Pentium II Overdrive 300/60", CPU_PENTIUM2D, 300000000, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"Pentium II Overdrive 333", CPU_PENTIUM2D, 333333333, 5, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; +#endif +#endif diff --git a/src/cpu_new/x86.h b/src/cpu_new/x86.h new file mode 100644 index 000000000..e3505a2e2 --- /dev/null +++ b/src/cpu_new/x86.h @@ -0,0 +1,70 @@ +extern uint8_t opcode, opcode2; +extern uint8_t flags_p; +extern uint8_t znptable8[256]; + +extern uint16_t zero, oldcs; +extern uint16_t lastcs, lastpc; +extern uint16_t *mod1add[2][8]; +extern uint16_t znptable16[65536]; + +extern int x86_was_reset, trap; +extern int codegen_flat_ss, codegen_flat_ds; +extern int timetolive, keyboardtimer, trap; +extern int optype, stack32; +extern int oldcpl, cgate32, cpl_override, fpucount; +extern int nmi_enable; +extern int oddeven, inttype; + +extern uint32_t use32; +extern uint32_t rmdat, easeg; +extern uint32_t oxpc, flags_zn; +extern uint32_t abrt_error; +extern uint32_t backupregs[16]; +extern uint32_t *mod1seg[8]; +extern uint32_t *eal_r, *eal_w; + +#define fetchdat rmdat + +#define setznp168 setznp16 + +#define getr8(r) ((r&4)?cpu_state.regs[r&3].b.h:cpu_state.regs[r&3].b.l) +#define getr16(r) cpu_state.regs[r].w +#define getr32(r) cpu_state.regs[r].l + +#define setr8(r,v) if (r&4) cpu_state.regs[r&3].b.h=v; \ + else cpu_state.regs[r&3].b.l=v; +#define setr16(r,v) cpu_state.regs[r].w=v +#define setr32(r,v) cpu_state.regs[r].l=v + +#define fetchea() { \ + rmdat = readmemb(cs + pc); \ + pc++; \ + reg = (rmdat >> 3) & 7; \ + mod = (rmdat >> 6) & 3; \ + rm = rmdat & 7; \ + if (mod!=3) \ + fetcheal(); \ + } + +#define JMP 1 +#define CALL 2 +#define IRET 3 +#define OPTYPE_INT 4 + + +enum +{ + ABRT_NONE = 0, + ABRT_GEN, + ABRT_TS = 0xA, + ABRT_NP = 0xB, + ABRT_SS = 0xC, + ABRT_GPF = 0xD, + ABRT_PF = 0xE +}; + + +extern void x86_doabrt(int x86_abrt); +extern void x86illegal(); +extern void x86seg_reset(); +extern void x86gpf(char *s, uint16_t error); diff --git a/src/cpu_new/x86_flags.h b/src/cpu_new/x86_flags.h new file mode 100644 index 000000000..9a9983926 --- /dev/null +++ b/src/cpu_new/x86_flags.h @@ -0,0 +1,630 @@ +extern int tempc; + +enum +{ + FLAGS_UNKNOWN, + + FLAGS_ZN8, + FLAGS_ZN16, + FLAGS_ZN32, + + FLAGS_ADD8, + FLAGS_ADD16, + FLAGS_ADD32, + + FLAGS_SUB8, + FLAGS_SUB16, + FLAGS_SUB32, + + FLAGS_SHL8, + FLAGS_SHL16, + FLAGS_SHL32, + + FLAGS_SHR8, + FLAGS_SHR16, + FLAGS_SHR32, + + FLAGS_SAR8, + FLAGS_SAR16, + FLAGS_SAR32, + + FLAGS_ROL8, + FLAGS_ROL16, + FLAGS_ROL32, + + FLAGS_ROR8, + FLAGS_ROR16, + FLAGS_ROR32, + + FLAGS_INC8, + FLAGS_INC16, + FLAGS_INC32, + + FLAGS_DEC8, + FLAGS_DEC16, + FLAGS_DEC32, + + FLAGS_ADC8, + FLAGS_ADC16, + FLAGS_ADC32, + + FLAGS_SBC8, + FLAGS_SBC16, + FLAGS_SBC32 +}; + +static inline int ZF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + 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 cpu_state.flags & Z_FLAG; + } + return 0; +} + +static inline int NF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + case FLAGS_ADC8: + case FLAGS_SBC8: + return cpu_state.flags_res & 0x80; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + case FLAGS_ADC16: + case FLAGS_SBC16: + return cpu_state.flags_res & 0x8000; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + 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 cpu_state.flags & N_FLAG; + } + return 0; +} + +static inline int PF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + 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 cpu_state.flags & P_FLAG; + } + return 0; +} + +static inline int VF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_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); + + case FLAGS_SHL8: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80); + case FLAGS_SHL16: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x8000); + case FLAGS_SHL32: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80000000); + + case FLAGS_SHR8: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80)); + case FLAGS_SHR16: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x8000)); + case FLAGS_SHR32: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); + + case FLAGS_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 cpu_state.flags & V_FLAG; + } + return 0; +} + +static inline int AF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_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: + case FLAGS_DEC8: + 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 cpu_state.flags & A_FLAG; + } + return 0; +} + +static inline int CF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ADD8: + 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) ? 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) ? 1 : 0; + case FLAGS_SHL16: + 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) ? 1 : 0; + + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + return (cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_SAR8: + return ((int8_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR16: + return ((int16_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR32: + return ((int32_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + return 0; + + case FLAGS_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: + case FLAGS_DEC32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_UNKNOWN: + return cpu_state.flags & C_FLAG; + } + return 0; +} + +//#define ZF_SET() (flags & Z_FLAG) +//#define NF_SET() (flags & N_FLAG) +//#define PF_SET() (flags & P_FLAG) +//#define VF_SET() (flags & V_FLAG) +//#define CF_SET() (flags & C_FLAG) +//#define AF_SET() (flags & A_FLAG) + +static inline void flags_rebuild() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + uint16_t tempf = 0; + if (CF_SET()) tempf |= C_FLAG; + if (PF_SET()) tempf |= P_FLAG; + if (AF_SET()) tempf |= A_FLAG; + if (ZF_SET()) tempf |= Z_FLAG; + if (NF_SET()) tempf |= N_FLAG; + if (VF_SET()) tempf |= V_FLAG; + cpu_state.flags = (cpu_state.flags & ~0x8d5) | tempf; + cpu_state.flags_op = FLAGS_UNKNOWN; + } +} + +static inline void flags_extract() +{ + cpu_state.flags_op = FLAGS_UNKNOWN; +} + +static inline void flags_rebuild_c() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + if (CF_SET()) + cpu_state.flags |= C_FLAG; + else + 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; + cpu_state.flags_res = val; +} +static inline void setznp16(uint16_t val) +{ + cpu_state.flags_op = FLAGS_ZN16; + cpu_state.flags_res = val; +} +static inline void setznp32(uint32_t val) +{ + cpu_state.flags_op = FLAGS_ZN32; + cpu_state.flags_res = val; +} + +#define set_flags_shift(op, orig, shift, res) \ + cpu_state.flags_op = op; \ + cpu_state.flags_res = res; \ + cpu_state.flags_op1 = orig; \ + cpu_state.flags_op2 = shift; + +#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; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_ADD8; +} +static inline void setadd16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_ADD16; +} +static inline void setadd32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_ADD32; +} +static inline void setadd8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_INC8; +} +static inline void setadd16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_INC16; +} +static inline void setadd32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_INC32; +} + +static inline void setsub8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_SUB8; +} +static inline void setsub16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_SUB16; +} +static inline void setsub32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_SUB32; +} + +static inline void setsub8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_DEC8; +} +static inline void setsub16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_DEC16; +} +static inline void setsub32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_DEC32; +} + +static inline void setadc8(uint8_t a, uint8_t b) +{ + 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) +{ + 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) +{ + 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) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - (b + tempc)) & 0xffff; + cpu_state.flags_op = FLAGS_SBC16; +} +static inline void setsbc32(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_SBC32; +} + +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); diff --git a/src/cpu_new/x86_flags_dynarec.h b/src/cpu_new/x86_flags_dynarec.h new file mode 100644 index 000000000..2a5212afa --- /dev/null +++ b/src/cpu_new/x86_flags_dynarec.h @@ -0,0 +1,528 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +/* This file is needed so that the dynarec can use the old flags + functions, while the interpreter can use the new ones. */ +extern int tempc; + +enum +{ + FLAGS_UNKNOWN, + + FLAGS_ZN8, + FLAGS_ZN16, + FLAGS_ZN32, + + FLAGS_ADD8, + FLAGS_ADD16, + FLAGS_ADD32, + + FLAGS_SUB8, + FLAGS_SUB16, + FLAGS_SUB32, + + FLAGS_SHL8, + FLAGS_SHL16, + FLAGS_SHL32, + + FLAGS_SHR8, + FLAGS_SHR16, + FLAGS_SHR32, + + FLAGS_SAR8, + FLAGS_SAR16, + FLAGS_SAR32, + + FLAGS_INC8, + FLAGS_INC16, + FLAGS_INC32, + + FLAGS_DEC8, + FLAGS_DEC16, + FLAGS_DEC32 +}; + +static __inline int ZF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return !cpu_state.flags_res; + + case FLAGS_UNKNOWN: + return cpu_state.flags & Z_FLAG; + + default: + return 0; + } +} + +static __inline int NF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + return cpu_state.flags_res & 0x80; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + return cpu_state.flags_res & 0x8000; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + return cpu_state.flags_res & 0x80000000; + + case FLAGS_UNKNOWN: + return cpu_state.flags & N_FLAG; + + default: + return 0; + } +} + +static __inline int PF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; + + case FLAGS_UNKNOWN: + return cpu_state.flags & P_FLAG; + + default: + return 0; + } +} + +static __inline int VF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_INC8: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_ADD16: + case FLAGS_INC16: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_ADD32: + case FLAGS_INC32: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SUB8: + case FLAGS_DEC8: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_SUB16: + case FLAGS_DEC16: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_SUB32: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SHL8: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80); + case FLAGS_SHL16: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x8000); + case FLAGS_SHL32: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80000000); + + case FLAGS_SHR8: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80)); + case FLAGS_SHR16: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x8000)); + case FLAGS_SHR32: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); + + case FLAGS_UNKNOWN: + return cpu_state.flags & V_FLAG; + + default: + return 0; + } +} + +static __inline int AF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_UNKNOWN: + return cpu_state.flags & A_FLAG; + + default: + return 0; + } +} + +static __inline int CF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ADD8: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100; + case FLAGS_ADD16: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000; + case FLAGS_ADD32: + return (cpu_state.flags_res < cpu_state.flags_op1); + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + return (cpu_state.flags_op1 < cpu_state.flags_op2); + + case FLAGS_SHL8: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80; + case FLAGS_SHL16: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000; + case FLAGS_SHL32: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000; + + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + return (cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_SAR8: + return ((int8_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR16: + return ((int16_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR32: + return ((int32_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + return 0; + + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_UNKNOWN: + return cpu_state.flags & C_FLAG; + + default: + return 0; + } +} + +static __inline void flags_rebuild_dynarec() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + uint16_t tempf = 0; + if (CF_SET_dynarec()) tempf |= C_FLAG; + if (PF_SET_dynarec()) tempf |= P_FLAG; + if (AF_SET_dynarec()) tempf |= A_FLAG; + if (ZF_SET_dynarec()) tempf |= Z_FLAG; + if (NF_SET_dynarec()) tempf |= N_FLAG; + if (VF_SET_dynarec()) tempf |= V_FLAG; + cpu_state.flags = (cpu_state.flags & ~0x8d5) | tempf; + cpu_state.flags_op = FLAGS_UNKNOWN; + } +} + +static __inline void flags_extract_dynarec() +{ + cpu_state.flags_op = FLAGS_UNKNOWN; +} + +static __inline void flags_rebuild_c_dynarec() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + if (CF_SET_dynarec()) + cpu_state.flags |= C_FLAG; + else + cpu_state.flags &= ~C_FLAG; + } +} + +static __inline void setznp8_dynarec(uint8_t val) +{ + cpu_state.flags_op = FLAGS_ZN8; + cpu_state.flags_res = val; +} +static __inline void setznp16_dynarec(uint16_t val) +{ + cpu_state.flags_op = FLAGS_ZN16; + cpu_state.flags_res = val; +} +static __inline void setznp32_dynarec(uint32_t val) +{ + cpu_state.flags_op = FLAGS_ZN32; + cpu_state.flags_res = val; +} + +#define set_flags_shift_dynarec(op, orig, shift, res) \ + cpu_state.flags_op = op; \ + cpu_state.flags_res = res; \ + cpu_state.flags_op1 = orig; \ + cpu_state.flags_op2 = shift; + +static __inline void setadd8_dynarec(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_ADD8; +} +static __inline void setadd16_dynarec(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_ADD16; +} +static __inline void setadd32_dynarec(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_ADD32; +} +static __inline void setadd8nc_dynarec(uint8_t a, uint8_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_INC8; +} +static __inline void setadd16nc_dynarec(uint16_t a, uint16_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_INC16; +} +static __inline void setadd32nc_dynarec(uint32_t a, uint32_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_INC32; +} + +static __inline void setsub8_dynarec(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_SUB8; +} +static __inline void setsub16_dynarec(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_SUB16; +} +static __inline void setsub32_dynarec(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_SUB32; +} + +static __inline void setsub8nc_dynarec(uint8_t a, uint8_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_DEC8; +} +static __inline void setsub16nc_dynarec(uint16_t a, uint16_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_DEC16; +} +static __inline void setsub32nc_dynarec(uint32_t a, uint32_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_DEC32; +} + +static __inline void setadc8_dynarec(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + 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 __inline void setadc16_dynarec(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + 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 __inline void setadc32_dynarec(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + cpu_state.flags|=(znptable8[c&0xFF]&P_FLAG); + if ((ca) || (c==a && tempc)) cpu_state.flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) cpu_state.flags|=V_FLAG; + if (((a&0xF)-((b&0xF)+tempc))&0x10) cpu_state.flags|=A_FLAG; +} + +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); \ No newline at end of file diff --git a/src/cpu_new/x86_ops.h b/src/cpu_new/x86_ops.h new file mode 100644 index 000000000..0de3b3252 --- /dev/null +++ b/src/cpu_new/x86_ops.h @@ -0,0 +1,242 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Miscellaneous x86 CPU Instructions. + * + * Version: @(#)x86_ops.h 1.0.2 2018/05/05 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef _X86_OPS_H +#define _X86_OPS_H + + +#define UN_USED(x) (void)(x) + + +typedef int (*OpFn)(uint32_t fetchdat); + +#ifdef USE_DYNAREC +void x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f, + const OpFn *dynarec_opcodes, + const OpFn *dynarec_opcodes_0f); + +extern const OpFn *x86_dynarec_opcodes; +extern const OpFn *x86_dynarec_opcodes_0f; +extern const OpFn *x86_dynarec_opcodes_d8_a16; +extern const OpFn *x86_dynarec_opcodes_d8_a32; +extern const OpFn *x86_dynarec_opcodes_d9_a16; +extern const OpFn *x86_dynarec_opcodes_d9_a32; +extern const OpFn *x86_dynarec_opcodes_da_a16; +extern const OpFn *x86_dynarec_opcodes_da_a32; +extern const OpFn *x86_dynarec_opcodes_db_a16; +extern const OpFn *x86_dynarec_opcodes_db_a32; +extern const OpFn *x86_dynarec_opcodes_dc_a16; +extern const OpFn *x86_dynarec_opcodes_dc_a32; +extern const OpFn *x86_dynarec_opcodes_dd_a16; +extern const OpFn *x86_dynarec_opcodes_dd_a32; +extern const OpFn *x86_dynarec_opcodes_de_a16; +extern const OpFn *x86_dynarec_opcodes_de_a32; +extern const OpFn *x86_dynarec_opcodes_df_a16; +extern const OpFn *x86_dynarec_opcodes_df_a32; +extern const OpFn *x86_dynarec_opcodes_REPE; +extern const OpFn *x86_dynarec_opcodes_REPNE; +extern const OpFn *x86_dynarec_opcodes_3DNOW; + +extern const OpFn dynarec_ops_286[1024]; +extern const OpFn dynarec_ops_286_0f[1024]; + +extern const OpFn dynarec_ops_386[1024]; +extern const OpFn dynarec_ops_386_0f[1024]; + +extern const OpFn dynarec_ops_486_0f[1024]; + +extern const OpFn dynarec_ops_winchip_0f[1024]; +extern const OpFn dynarec_ops_winchip2_0f[1024]; + +extern const OpFn dynarec_ops_pentium_0f[1024]; +extern const OpFn dynarec_ops_pentiummmx_0f[1024]; +extern const OpFn dynarec_ops_c6x86mx_0f[1024]; + +extern const OpFn dynarec_ops_k6_0f[1024]; +extern const OpFn dynarec_ops_k62_0f[1024]; + +#if defined(DEV_BRANCH) && defined(USE_I686) +extern const OpFn dynarec_ops_pentiumpro_0f[1024]; +extern const OpFn dynarec_ops_pentium2d_0f[1024]; +#endif + +extern const OpFn dynarec_ops_fpu_287_d9_a16[256]; +extern const OpFn dynarec_ops_fpu_287_d9_a32[256]; +extern const OpFn dynarec_ops_fpu_287_da_a16[256]; +extern const OpFn dynarec_ops_fpu_287_da_a32[256]; +extern const OpFn dynarec_ops_fpu_287_db_a16[256]; +extern const OpFn dynarec_ops_fpu_287_db_a32[256]; +extern const OpFn dynarec_ops_fpu_287_dc_a16[32]; +extern const OpFn dynarec_ops_fpu_287_dc_a32[32]; +extern const OpFn dynarec_ops_fpu_287_dd_a16[256]; +extern const OpFn dynarec_ops_fpu_287_dd_a32[256]; +extern const OpFn dynarec_ops_fpu_287_de_a16[256]; +extern const OpFn dynarec_ops_fpu_287_de_a32[256]; +extern const OpFn dynarec_ops_fpu_287_df_a16[256]; +extern const OpFn dynarec_ops_fpu_287_df_a32[256]; + +extern const OpFn dynarec_ops_fpu_d8_a16[32]; +extern const OpFn dynarec_ops_fpu_d8_a32[32]; +extern const OpFn dynarec_ops_fpu_d9_a16[256]; +extern const OpFn dynarec_ops_fpu_d9_a32[256]; +extern const OpFn dynarec_ops_fpu_da_a16[256]; +extern const OpFn dynarec_ops_fpu_da_a32[256]; +extern const OpFn dynarec_ops_fpu_db_a16[256]; +extern const OpFn dynarec_ops_fpu_db_a32[256]; +extern const OpFn dynarec_ops_fpu_dc_a16[32]; +extern const OpFn dynarec_ops_fpu_dc_a32[32]; +extern const OpFn dynarec_ops_fpu_dd_a16[256]; +extern const OpFn dynarec_ops_fpu_dd_a32[256]; +extern const OpFn dynarec_ops_fpu_de_a16[256]; +extern const OpFn dynarec_ops_fpu_de_a32[256]; +extern const OpFn dynarec_ops_fpu_df_a16[256]; +extern const OpFn dynarec_ops_fpu_df_a32[256]; +extern const OpFn dynarec_ops_nofpu_a16[256]; +extern const OpFn dynarec_ops_nofpu_a32[256]; + +extern const OpFn dynarec_ops_fpu_686_da_a16[256]; +extern const OpFn dynarec_ops_fpu_686_da_a32[256]; +extern const OpFn dynarec_ops_fpu_686_db_a16[256]; +extern const OpFn dynarec_ops_fpu_686_db_a32[256]; +extern const OpFn dynarec_ops_fpu_686_df_a16[256]; +extern const OpFn dynarec_ops_fpu_686_df_a32[256]; + +extern const OpFn dynarec_ops_REPE[1024]; +extern const OpFn dynarec_ops_REPNE[1024]; +extern const OpFn dynarec_ops_3DNOW[256]; +#else +void x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f); +#endif + +extern const OpFn *x86_opcodes; +extern const OpFn *x86_opcodes_0f; +extern const OpFn *x86_opcodes_d8_a16; +extern const OpFn *x86_opcodes_d8_a32; +extern const OpFn *x86_opcodes_d9_a16; +extern const OpFn *x86_opcodes_d9_a32; +extern const OpFn *x86_opcodes_da_a16; +extern const OpFn *x86_opcodes_da_a32; +extern const OpFn *x86_opcodes_db_a16; +extern const OpFn *x86_opcodes_db_a32; +extern const OpFn *x86_opcodes_dc_a16; +extern const OpFn *x86_opcodes_dc_a32; +extern const OpFn *x86_opcodes_dd_a16; +extern const OpFn *x86_opcodes_dd_a32; +extern const OpFn *x86_opcodes_de_a16; +extern const OpFn *x86_opcodes_de_a32; +extern const OpFn *x86_opcodes_df_a16; +extern const OpFn *x86_opcodes_df_a32; +extern const OpFn *x86_opcodes_REPE; +extern const OpFn *x86_opcodes_REPNE; +extern const OpFn *x86_opcodes_3DNOW; + +extern const OpFn ops_286[1024]; +extern const OpFn ops_286_0f[1024]; + +extern const OpFn ops_386[1024]; +extern const OpFn ops_386_0f[1024]; + +extern const OpFn ops_486_0f[1024]; + +extern const OpFn ops_winchip_0f[1024]; +extern const OpFn ops_winchip2_0f[1024]; + +extern const OpFn ops_pentium_0f[1024]; +extern const OpFn ops_pentiummmx_0f[1024]; + +extern const OpFn ops_c6x86mx_0f[1024]; + +extern const OpFn ops_k6_0f[1024]; +extern const OpFn ops_k62_0f[1024]; + +#if defined(DEV_BRANCH) && defined(USE_I686) +extern const OpFn ops_pentiumpro_0f[1024]; +extern const OpFn ops_pentium2d_0f[1024]; +#endif + +extern const OpFn ops_fpu_287_d9_a16[256]; +extern const OpFn ops_fpu_287_d9_a32[256]; +extern const OpFn ops_fpu_287_da_a16[256]; +extern const OpFn ops_fpu_287_da_a32[256]; +extern const OpFn ops_fpu_287_db_a16[256]; +extern const OpFn ops_fpu_287_db_a32[256]; +extern const OpFn ops_fpu_287_dc_a16[32]; +extern const OpFn ops_fpu_287_dc_a32[32]; +extern const OpFn ops_fpu_287_dd_a16[256]; +extern const OpFn ops_fpu_287_dd_a32[256]; +extern const OpFn ops_fpu_287_de_a16[256]; +extern const OpFn ops_fpu_287_de_a32[256]; +extern const OpFn ops_fpu_287_df_a16[256]; +extern const OpFn ops_fpu_287_df_a32[256]; + +extern const OpFn ops_fpu_d8_a16[32]; +extern const OpFn ops_fpu_d8_a32[32]; +extern const OpFn ops_fpu_d9_a16[256]; +extern const OpFn ops_fpu_d9_a32[256]; +extern const OpFn ops_fpu_da_a16[256]; +extern const OpFn ops_fpu_da_a32[256]; +extern const OpFn ops_fpu_db_a16[256]; +extern const OpFn ops_fpu_db_a32[256]; +extern const OpFn ops_fpu_dc_a16[32]; +extern const OpFn ops_fpu_dc_a32[32]; +extern const OpFn ops_fpu_dd_a16[256]; +extern const OpFn ops_fpu_dd_a32[256]; +extern const OpFn ops_fpu_de_a16[256]; +extern const OpFn ops_fpu_de_a32[256]; +extern const OpFn ops_fpu_df_a16[256]; +extern const OpFn ops_fpu_df_a32[256]; +extern const OpFn ops_nofpu_a16[256]; +extern const OpFn ops_nofpu_a32[256]; + +extern const OpFn ops_fpu_686_da_a16[256]; +extern const OpFn ops_fpu_686_da_a32[256]; +extern const OpFn ops_fpu_686_db_a16[256]; +extern const OpFn ops_fpu_686_db_a32[256]; +extern const OpFn ops_fpu_686_df_a16[256]; +extern const OpFn ops_fpu_686_df_a32[256]; + +extern const OpFn ops_REPE[1024]; +extern const OpFn ops_REPNE[1024]; +extern const OpFn ops_3DNOW[256]; + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +#endif /*_X86_OPS_H*/ diff --git a/src/cpu_new/x86_ops_3dnow.h b/src/cpu_new/x86_ops_3dnow.h new file mode 100644 index 000000000..c578c400a --- /dev/null +++ b/src/cpu_new/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(); + UN_USED(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; +} + +const 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/cpu_new/x86_ops_amd.h b/src/cpu_new/x86_ops_amd.h new file mode 100644 index 000000000..8f003e1fb --- /dev/null +++ b/src/cpu_new/x86_ops_amd.h @@ -0,0 +1,192 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * AMD SYSCALL and SYSRET CPU Instructions. + * + * Version: @(#)x86_ops_amd.h 1.0.4 2018/10/17 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ + +/* 0 = Limit 0-15 + 1 = Base 0-15 + 2 = Base 16-23 (bits 0-7), Access rights + 8-11 Type + 12 S + 13, 14 DPL + 15 P + 3 = Limit 16-19 (bits 0-3), Base 24-31 (bits 8-15), granularity, etc. + 4 A + 6 DB + 7 G */ + +#define AMD_SYSCALL_EIP (star & 0xFFFFFFFF) +#define AMD_SYSCALL_SB ((star >> 32) & 0xFFFF) +#define AMD_SYSRET_SB ((star >> 48) & 0xFFFF) + +/* 0F 05 */ +static int opSYSCALL(uint32_t fetchdat) +{ + uint16_t syscall_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t syscall_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!(cr0 & 1)) return internal_illegal("SYSCALL: CPU not in protected mode"); + if (!AMD_SYSCALL_SB) return internal_illegal("SYSCALL: AMD SYSCALL SB MSR is zero"); + + /* Set VM, IF, RF to 0. */ + /* cpu_state.eflags &= ~0x00030200; + cpu_state.flags &= ~0x0200; */ + + /* Let's do this by the AMD spec. */ + ECX = cpu_state.pc; + + cpu_state.eflags &= ~0x0002; + cpu_state.flags &= ~0x0200; + + /* CS */ + cpu_state.seg_cs.seg = AMD_SYSCALL_SB & ~7; + if (AMD_SYSCALL_SB & 4) + { + if (cpu_state.seg_cs.seg >= ldt.limit) + { + x386_dynarec_log("Bigger than LDT limit %04X %04X CS\n",AMD_SYSCALL_SB,ldt.limit); + x86gpf(NULL, AMD_SYSCALL_SB & ~3); + return 1; + } + cpu_state.seg_cs.seg +=ldt.base; + } + else + { + if (cpu_state.seg_cs.seg >= gdt.limit) + { + x386_dynarec_log("Bigger than GDT limit %04X %04X CS\n",AMD_SYSCALL_SB,gdt.limit); + x86gpf(NULL, AMD_SYSCALL_SB & ~3); + return 1; + } + cpu_state.seg_cs.seg += gdt.base; + } + cpl_override = 1; + + syscall_cs_seg_data[0] = 0xFFFF; + syscall_cs_seg_data[1] = 0; + syscall_cs_seg_data[2] = 0x9B00; + syscall_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSCALL_SB & ~3) | 0; + + do_seg_load(&cpu_state.seg_cs, syscall_cs_seg_data); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 0; + + cpu_state.seg_cs.limit = 0xFFFFFFFF; + cpu_state.seg_cs.limit_high = 0xFFFFFFFF; + + /* SS */ + syscall_ss_seg_data[0] = 0xFFFF; + syscall_ss_seg_data[1] = 0; + syscall_ss_seg_data[2] = 0x9300; + syscall_ss_seg_data[3] = 0xC0; + do_seg_load(&cpu_state.seg_ss, syscall_ss_seg_data); + cpu_state.seg_ss.seg = (AMD_SYSCALL_SB + 8) & 0xFFFC; + stack32 = 1; + + cpu_state.seg_ss.limit = 0xFFFFFFFF; + cpu_state.seg_ss.limit_high = 0xFFFFFFFF; + + cpu_state.seg_ss.checked = 0; + + cpu_state.pc = AMD_SYSCALL_EIP; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + return 0; +} + +/* 0F 07 */ +static int opSYSRET(uint32_t fetchdat) +{ + uint16_t sysret_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t sysret_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!AMD_SYSRET_SB) return internal_illegal("SYSRET: CS MSR is zero"); + if (!(cr0 & 1)) return internal_illegal("SYSRET: CPU not in protected mode"); + + cpu_state.pc = ECX; + + cpu_state.eflags |= (1 << 1); + + /* CS */ + cpu_state.seg_cs.seg = AMD_SYSRET_SB & ~7; + if (AMD_SYSRET_SB & 4) + { + if (cpu_state.seg_cs.seg >= ldt.limit) + { + x386_dynarec_log("Bigger than LDT limit %04X %04X CS\n",AMD_SYSRET_SB,ldt.limit); + x86gpf(NULL, AMD_SYSRET_SB & ~3); + return 1; + } + cpu_state.seg_cs.seg +=ldt.base; + } + else + { + if (cpu_state.seg_cs.seg >= gdt.limit) + { + x386_dynarec_log("Bigger than GDT limit %04X %04X CS\n",AMD_SYSRET_SB,gdt.limit); + x86gpf(NULL, AMD_SYSRET_SB & ~3); + return 1; + } + cpu_state.seg_cs.seg += gdt.base; + } + cpl_override = 1; + + sysret_cs_seg_data[0] = 0xFFFF; + sysret_cs_seg_data[1] = 0; + sysret_cs_seg_data[2] = 0xFB00; + sysret_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSRET_SB & ~3) | 3; + + do_seg_load(&cpu_state.seg_cs, sysret_cs_seg_data); + flushmmucache_cr3(); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 3; + + cpu_state.seg_cs.limit = 0xFFFFFFFF; + cpu_state.seg_cs.limit_high = 0xFFFFFFFF; + + /* SS */ + sysret_ss_seg_data[0] = 0xFFFF; + sysret_ss_seg_data[1] = 0; + sysret_ss_seg_data[2] = 0xF300; + sysret_ss_seg_data[3] = 0xC0; + do_seg_load(&cpu_state.seg_ss, sysret_ss_seg_data); + cpu_state.seg_ss.seg = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; + stack32 = 1; + + cpu_state.seg_ss.limit = 0xFFFFFFFF; + cpu_state.seg_ss.limit_high = 0xFFFFFFFF; + + cpu_state.seg_ss.checked = 0; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + return 0; +} diff --git a/src/cpu_new/x86_ops_arith.h b/src/cpu_new/x86_ops_arith.h new file mode 100644 index 000000000..489fd5e57 --- /dev/null +++ b/src/cpu_new/x86_ops_arith.h @@ -0,0 +1,818 @@ +#define OP_ARITH(name, operation, setflags, flagops, gettempc) \ + static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + 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); \ + } \ + return 0; \ + } \ + static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + 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, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _b_rm_a16(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + 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; \ + setr8(cpu_reg, operation); \ + 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); \ + return 0; \ + } \ + static int op ## name ## _b_rm_a32(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + 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; \ + setr8(cpu_reg, operation); \ + 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); \ + return 0; \ + } \ + \ + static int op ## name ## _w_rm_a16(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + 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; \ + cpu_state.regs[cpu_reg].w = operation; \ + 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); \ + return 0; \ + } \ + static int op ## name ## _w_rm_a32(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + 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; \ + cpu_state.regs[cpu_reg].w = operation; \ + 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); \ + return 0; \ + } \ + \ + static int op ## name ## _l_rm_a16(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + 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; \ + cpu_state.regs[cpu_reg].l = operation; \ + 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); \ + return 0; \ + } \ + static int op ## name ## _l_rm_a32(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + 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; \ + cpu_state.regs[cpu_reg].l = operation; \ + 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); \ + return 0; \ + } \ + \ + static int op ## name ## _AL_imm(uint32_t fetchdat) \ + { \ + uint8_t dst = AL; \ + uint8_t src = getbytef(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 8 flagops; \ + AL = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _AX_imm(uint32_t fetchdat) \ + { \ + uint16_t dst = AX; \ + uint16_t src = getwordf(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 16 flagops; \ + AX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _EAX_imm(uint32_t fetchdat) \ + { \ + uint32_t dst = EAX; \ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 32 flagops; \ + EAX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); \ + return 0; \ + } + +OP_ARITH(ADD, dst + src, setadd, (dst, src), 0) +OP_ARITH(ADC, dst + src + tempc, setadc, (dst, src), 1) +OP_ARITH(SUB, dst - src, setsub, (dst, src), 0) +OP_ARITH(SBB, dst - (src + tempc), setsbc, (dst, src), 1) +OP_ARITH(OR, dst | src, setznp, (dst | src), 0) +OP_ARITH(AND, dst & src, setznp, (dst & src), 0) +OP_ARITH(XOR, dst ^ src, setznp, (dst ^ src), 0) + +static int opCMP_b_rmw_a16(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_16(fetchdat); + 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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +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); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opCMP_b_rm_a16(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_16(fetchdat); + 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); + return 0; +} +static int opCMP_b_rm_a32(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_32(fetchdat); + 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); + return 0; +} + +static int opCMP_w_rm_a16(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_16(fetchdat); + 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); + return 0; +} +static int opCMP_w_rm_a32(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_32(fetchdat); + 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); + return 0; +} + +static int opCMP_l_rm_a16(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_16(fetchdat); + 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); + return 0; +} +static int opCMP_l_rm_a32(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_32(fetchdat); + 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); + return 0; +} + +static int opCMP_AL_imm(uint32_t fetchdat) +{ + uint8_t src = getbytef(); + setsub8(AL, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_AX_imm(uint32_t fetchdat) +{ + uint16_t src = getwordf(); + setsub16(AX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_EAX_imm(uint32_t fetchdat) +{ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; + setsub32(EAX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + +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); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +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); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +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); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +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); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +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); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +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); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opTEST_AL(uint32_t fetchdat) +{ + uint8_t temp = getbytef(); + setznp8(AL & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_AX(uint32_t fetchdat) +{ + uint16_t temp = getwordf(); + setznp16(AX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_EAX(uint32_t fetchdat) +{ + uint32_t temp = getlong(); if (cpu_state.abrt) return 1; + setznp32(EAX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + + +#define ARITH_MULTI(ea_width, flag_width) \ + dst = getea ## ea_width(); if (cpu_state.abrt) return 1; \ + switch (rmdat&0x38) \ + { \ + case 0x00: /*ADD ea, #*/ \ + setea ## ea_width(dst + src); if (cpu_state.abrt) return 1; \ + setadd ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x08: /*OR ea, #*/ \ + dst |= src; \ + setea ## ea_width(dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x10: /*ADC ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst + src + tempc); if (cpu_state.abrt) return 1; \ + setadc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x18: /*SBB ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst - (src + tempc)); if (cpu_state.abrt) return 1; \ + setsbc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x20: /*AND ea, #*/ \ + dst &= src; \ + setea ## ea_width(dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x28: /*SUB ea, #*/ \ + setea ## ea_width(dst - src); if (cpu_state.abrt) return 1; \ + setsub ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x30: /*XOR ea, #*/ \ + dst ^= src; \ + setea ## ea_width(dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x38: /*CMP ea, #*/ \ + setsub ## flag_width(dst, src); \ + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); \ + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 7); \ + break; \ + } + + +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) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +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) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +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) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +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) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +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) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +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) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + +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); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +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); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} + +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); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +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); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + diff --git a/src/cpu_new/x86_ops_atomic.h b/src/cpu_new/x86_ops_atomic.h new file mode 100644 index 000000000..4011a0aa4 --- /dev/null +++ b/src/cpu_new/x86_ops_atomic.h @@ -0,0 +1,292 @@ +static int opCMPXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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; + if (cpu_state.abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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; + if (cpu_state.abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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; + if (cpu_state.abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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; + if (cpu_state.abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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; + if (cpu_state.abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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; + if (cpu_state.abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG8B_a16(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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) + { + seteal(EBX); + writememl(easeg, cpu_state.eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (cpu_state.abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + cpu_state.flags |= Z_FLAG; + else + cpu_state.flags &= ~Z_FLAG; + cycles -= (cpu_mod == 3) ? 6 : 10; + return 0; +} +static int opCMPXCHG8B_a32(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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) + { + seteal(EBX); + writememl(easeg, cpu_state.eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (cpu_state.abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + cpu_state.flags |= Z_FLAG; + else + cpu_state.flags &= ~Z_FLAG; + cycles -= (cpu_mod == 3) ? 6 : 10; + return 0; +} + +static int opXADD_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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)); + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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)); + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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); + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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); + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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); + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + 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); + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} diff --git a/src/cpu_new/x86_ops_bcd.h b/src/cpu_new/x86_ops_bcd.h new file mode 100644 index 000000000..cd29b1405 --- /dev/null +++ b/src/cpu_new/x86_ops_bcd.h @@ -0,0 +1,113 @@ +static int opAAA(uint32_t fetchdat) +{ + flags_rebuild(); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL += 6; + AH++; + cpu_state.flags |= (A_FLAG | C_FLAG); + } + else + 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); + return 0; +} + +static int opAAD(uint32_t fetchdat) +{ + int base = getbytef(); + if (cpu_manufacturer != MANU_INTEL) base = 10; + AL = (AH * base) + AL; + AH = 0; + setznp16(AX); + CLOCK_CYCLES((is486) ? 14 : 19); + PREFETCH_RUN(is486 ? 14 : 19, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opAAM(uint32_t fetchdat) +{ + int base = getbytef(); + if (!base || cpu_manufacturer != MANU_INTEL) base = 10; + AH = AL / base; + AL %= base; + setznp16(AX); + CLOCK_CYCLES((is486) ? 15 : 17); + PREFETCH_RUN(is486 ? 15 : 17, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opAAS(uint32_t fetchdat) +{ + flags_rebuild(); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL -= 6; + AH--; + cpu_state.flags |= (A_FLAG | C_FLAG); + } + else + 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); + return 0; +} + +static int opDAA(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) + 6; + AL += 6; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) cpu_state.flags |= C_FLAG; + } + if ((cpu_state.flags & C_FLAG) || (AL > 0x9f)) + { + AL += 0x60; + cpu_state.flags |= C_FLAG; + } + + tempw = cpu_state.flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + cpu_state.flags |= tempw; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); + + return 0; +} + +static int opDAS(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) - 6; + AL -= 6; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) cpu_state.flags |= C_FLAG; + } + if ((cpu_state.flags & C_FLAG) || (AL > 0x9f)) + { + AL -= 0x60; + cpu_state.flags |= C_FLAG; + } + + tempw = cpu_state.flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + cpu_state.flags |= tempw; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); + + return 0; +} diff --git a/src/cpu_new/x86_ops_bit.h b/src/cpu_new/x86_ops_bit.h new file mode 100644 index 000000000..df2d48619 --- /dev/null +++ b/src/cpu_new/x86_ops_bit.h @@ -0,0 +1,328 @@ +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))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 0); + return 0; +} +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))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 1); + return 0; +} +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))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 0); + return 0; +} +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))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 1); + return 0; +} + +#define opBT(name, operation) \ + static int opBT ## name ## _w_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_16(fetchdat); \ + 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) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 0); \ + return 0; \ + } \ + static int opBT ## name ## _w_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + 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) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 1); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + 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) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 0); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + 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) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 1); \ + return 0; \ + } + +opBT(C, ^=) +opBT(R, &=~) +opBT(S, |=) + +static int opBA_w_a16(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_16(fetchdat); + 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); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + 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; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteaw(temp); if (cpu_state.abrt) return 1; + 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; +} +static int opBA_w_a32(uint32_t fetchdat) +{ + int tempc, count; + 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); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + 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; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteaw(temp); if (cpu_state.abrt) return 1; + 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; +} + +static int opBA_l_a16(uint32_t fetchdat) +{ + int tempc, count; + 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); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + 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; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteal(temp); if (cpu_state.abrt) return 1; + 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; +} +static int opBA_l_a32(uint32_t fetchdat) +{ + int tempc, count; + 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); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + 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; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteal(temp); if (cpu_state.abrt) return 1; + 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/cpu_new/x86_ops_bitscan.h b/src/cpu_new/x86_ops_bitscan.h new file mode 100644 index 000000000..01d9c5795 --- /dev/null +++ b/src/cpu_new/x86_ops_bitscan.h @@ -0,0 +1,159 @@ +#define BS_common(start, end, dir, dest, time) \ + flags_rebuild(); \ + instr_cycles = 0; \ + if (temp) \ + { \ + int c; \ + cpu_state.flags &= ~Z_FLAG; \ + for (c = start; c != end; c += dir) \ + { \ + CLOCK_CYCLES(time); \ + instr_cycles += time; \ + if (temp & (1 << c)) \ + { \ + dest = c; \ + break; \ + } \ + } \ + } \ + else \ + cpu_state.flags |= Z_FLAG; + +static int opBSF_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + 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); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opBSF_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + 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); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opBSF_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + 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); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return 0; +} +static int opBSF_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + 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); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return 0; +} + +static int opBSR_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + 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); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opBSR_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + 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); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opBSR_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + 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); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return 0; +} +static int opBSR_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + 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); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return 0; +} + diff --git a/src/cpu_new/x86_ops_call.h b/src/cpu_new/x86_ops_call.h new file mode 100644 index 000000000..a11bc9c97 --- /dev/null +++ b/src/cpu_new/x86_ops_call.h @@ -0,0 +1,455 @@ +#define CALL_FAR_w(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg, old_pc); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate32) \ + { \ + uint32_t old_esp = ESP; \ + 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) { 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; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg, old_pc); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate16) \ + { \ + uint32_t old_esp = ESP; \ + 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) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ + } + + +static int opCALL_far_w(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint16_t new_cs, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + new_pc = getwordf(); + new_cs = getword(); if (cpu_state.abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 5, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + + return 0; +} +static int opCALL_far_l(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint32_t new_cs, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + new_pc = getlong(); + new_cs = getword(); if (cpu_state.abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 7, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + + return 0; +} + + +static int opFF_w_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint16_t temp; + + fetch_ea_16(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); + 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 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); + 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 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; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 0); + 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; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); + 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(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + 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, 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); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 0); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} +static int opFF_w_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint16_t temp; + + fetch_ea_32(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); + 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 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); + 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 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; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 1); + 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; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 1); + 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(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,0,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + 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, 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); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 1); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} + +static int opFF_l_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint32_t temp; + + fetch_ea_16(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); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + 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); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + 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; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 0); + 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; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 0); + 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(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 0,1,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + 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, 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); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 0); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} +static int opFF_l_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint32_t temp; + + fetch_ea_32(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); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + 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); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + 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; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); + 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; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 1); + 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(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + 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, 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); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} diff --git a/src/cpu_new/x86_ops_flag.h b/src/cpu_new/x86_ops_flag.h new file mode 100644 index 000000000..d21408c8b --- /dev/null +++ b/src/cpu_new/x86_ops_flag.h @@ -0,0 +1,275 @@ +static int opCMC(uint32_t fetchdat) +{ + flags_rebuild(); + cpu_state.flags ^= C_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} + + +static int opCLC(uint32_t fetchdat) +{ + flags_rebuild(); + 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) +{ + cpu_state.flags &= ~D_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCLI(uint32_t fetchdat) +{ + if (!IOPLp) + { + 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 + cpu_state.flags &= ~I_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opSTC(uint32_t fetchdat) +{ + flags_rebuild(); + 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) +{ + cpu_state.flags |= D_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opSTI(uint32_t fetchdat) +{ + if (!IOPLp) + { + 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 + cpu_state.flags |= I_FLAG; + + CPU_BLOCK_END(); + + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opSAHF(uint32_t fetchdat) +{ + flags_rebuild(); + cpu_state.flags = (cpu_state.flags & 0xff00) | (AH & 0xd5) | 2; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + + codegen_flags_changed = 0; + + return 0; +} +static int opLAHF(uint32_t fetchdat) +{ + flags_rebuild(); + AH = cpu_state.flags & 0xff; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opPUSHF(uint32_t fetchdat) +{ + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + 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); + } + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opPUSHFD(uint32_t fetchdat) +{ + uint16_t tempw; + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + 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(cpu_state.flags | (tempw << 16)); + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} + +static int opPOPF_286(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + tempw = POP_W(); if (cpu_state.abrt) return 1; + + 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); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + + codegen_flags_changed = 0; + + return 0; +} +static int opPOPF(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + if (cr4 & CR4_VME) + { + uint32_t old_esp = ESP; + + 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); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + + codegen_flags_changed = 0; + + return 0; +} +static int opPOPFD(uint32_t fetchdat) +{ + uint32_t templ; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + templ = POP_L(); if (cpu_state.abrt) return 1; + + 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 ? 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(); + + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0); + + codegen_flags_changed = 0; + + return 0; +} diff --git a/src/cpu_new/x86_ops_fpu.h b/src/cpu_new/x86_ops_fpu.h new file mode 100644 index 000000000..8c264374f --- /dev/null +++ b/src/cpu_new/x86_ops_fpu.h @@ -0,0 +1,82 @@ +static int opESCAPE_d8_a16(uint32_t fetchdat) +{ + return x86_opcodes_d8_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_d8_a32(uint32_t fetchdat) +{ + return x86_opcodes_d8_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_d9_a16(uint32_t fetchdat) +{ + return x86_opcodes_d9_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_d9_a32(uint32_t fetchdat) +{ + return x86_opcodes_d9_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_da_a16(uint32_t fetchdat) +{ + return x86_opcodes_da_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_da_a32(uint32_t fetchdat) +{ + return x86_opcodes_da_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_db_a16(uint32_t fetchdat) +{ + return x86_opcodes_db_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_db_a32(uint32_t fetchdat) +{ + return x86_opcodes_db_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_dc_a16(uint32_t fetchdat) +{ + return x86_opcodes_dc_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_dc_a32(uint32_t fetchdat) +{ + return x86_opcodes_dc_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_dd_a16(uint32_t fetchdat) +{ + return x86_opcodes_dd_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_dd_a32(uint32_t fetchdat) +{ + return x86_opcodes_dd_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_de_a16(uint32_t fetchdat) +{ + return x86_opcodes_de_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_de_a32(uint32_t fetchdat) +{ + return x86_opcodes_de_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_df_a16(uint32_t fetchdat) +{ + return x86_opcodes_df_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_df_a32(uint32_t fetchdat) +{ + return x86_opcodes_df_a32[fetchdat & 0xff](fetchdat); +} + +static int opWAIT(uint32_t fetchdat) +{ + if ((cr0 & 0xa) == 0xa) + { + x86_int(7); + return 1; + } + CLOCK_CYCLES(4); + return 0; +} diff --git a/src/cpu_new/x86_ops_i686.h b/src/cpu_new/x86_ops_i686.h new file mode 100644 index 000000000..b4c1ed7ff --- /dev/null +++ b/src/cpu_new/x86_ops_i686.h @@ -0,0 +1,514 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x86 i686 (Pentium Pro/Pentium II) CPU Instructions. + * + * Version: @(#)x86_ops_i686.h 1.0.5 2018/10/17 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ + +/* 0 = Limit 0-15 + 1 = Base 0-15 + 2 = Base 16-23 (bits 0-7), Access rights + 8-11 Type + 12 S + 13, 14 DPL + 15 P + 3 = Limit 16-19 (bits 0-3), Base 24-31 (bits 8-15), granularity, etc. + 4 A + 6 DB + 7 G */ + +static void make_seg_data(uint16_t *seg_data, uint32_t base, uint32_t limit, uint8_t type, uint8_t s, uint8_t dpl, uint8_t p, uint8_t g, uint8_t db, uint8_t a) +{ + seg_data[0] = limit & 0xFFFF; + seg_data[1] = base & 0xFFFF; + seg_data[2] = ((base >> 16) & 0xFF) | (type << 8) | (p << 15) | (dpl << 13) | (s << 12); + seg_data[3] = ((limit >> 16) & 0xF) | (a << 4) | (db << 6) | (g << 7) | ((base >> 16) & 0xFF00); +} + +static int opSYSENTER(uint32_t fetchdat) +{ + uint16_t sysenter_cs_seg_data[4]; + uint16_t sysenter_ss_seg_data[4]; + +#ifdef SYSENTER_LOG + x386_dynarec_log("SYSENTER called\n"); +#endif + + if (!(msw & 1)) return internal_illegal("SYSENTER: CPU not in protected mode"); + if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSENTER: CS MSR is zero"); + +#ifdef SYSENTER_LOG + x386_dynarec_log("SYSENTER started:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32); +#endif + + if (cpu_state.abrt) return 1; + + ESP = esp_msr; + cpu_state.pc = eip_msr; + + optype = CALL; \ + cgate16 = cgate32 = 0; \ + + /* Set VM, RF, and IF to 0. */ + cpu_state.eflags &= ~0x0003; + cpu_state.flags &= ~0x0200; + + CS = (cs_msr & 0xFFFC); + make_seg_data(sysenter_cs_seg_data, 0, 0xFFFFF, 11, 1, 0, 1, 1, 1, 0); + do_seg_load(&cpu_state.seg_cs, sysenter_cs_seg_data); + use32 = 0x300; + + SS = ((cs_msr + 8) & 0xFFFC); + make_seg_data(sysenter_ss_seg_data, 0, 0xFFFFF, 3, 1, 0, 1, 1, 1, 0); + do_seg_load(&cpu_state.seg_ss, sysenter_ss_seg_data); + stack32 = 1; + + cycles -= timing_call_pm; + + optype = 0; + + CPU_BLOCK_END(); + +#ifdef SYSENTER_LOG + x386_dynarec_log("SYSENTER completed:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32); +#endif + + return 0; +} + +static int opSYSEXIT(uint32_t fetchdat) +{ + uint16_t sysexit_cs_seg_data[4]; + uint16_t sysexit_ss_seg_data[4]; + +#ifdef SYSEXIT_LOG + x386_dynarec_log("SYSEXIT called\n"); +#endif + + if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSEXIT: CS MSR is zero"); + if (!(msw & 1)) return internal_illegal("SYSEXIT: CPU not in protected mode"); + if (CPL) return internal_illegal("SYSEXIT: CPL not 0"); + +#ifdef SYSEXIT_LOG + x386_dynarec_log("SYSEXIT start:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32, ECX, EDX); +#endif + + if (cpu_state.abrt) return 1; + + ESP = ECX; + cpu_state.pc = EDX; + + optype = CALL; \ + cgate16 = cgate32 = 0; \ + + CS = ((cs_msr + 16) & 0xFFFC) | 3; + make_seg_data(sysexit_cs_seg_data, 0, 0xFFFFF, 11, 1, 3, 1, 1, 1, 0); + do_seg_load(&cpu_state.seg_cs, sysexit_cs_seg_data); + use32 = 0x300; + + SS = CS + 8; + make_seg_data(sysexit_ss_seg_data, 0, 0xFFFFF, 3, 1, 3, 1, 1, 1, 0); + do_seg_load(&cpu_state.seg_ss, sysexit_ss_seg_data); + stack32 = 1; + + flushmmucache_cr3(); + + cycles -= timing_call_pm; + + optype = 0; + + CPU_BLOCK_END(); + +#ifdef SYSEXIT_LOG + x386_dynarec_log("SYSEXIT completed:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32, ECX, EDX); +#endif + + return 0; +} + +static int opFXSAVESTOR_a16(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint16_t old_eaaddr = 0; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + uint64_t *p; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_16(fetchdat); + + if (cpu_state.eaaddr & 0xf) + { + x386_dynarec_log("Effective address %04X not on 16-byte boundary\n", cpu_state.eaaddr); + x86gpf(NULL, 0); + return cpu_state.abrt; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (cpu_mod == 3)) + { + x86illegal(); + return cpu_state.abrt; + } + + FP_ENTER(); + + old_eaaddr = cpu_state.eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + fpus = readmemw(easeg, cpu_state.eaaddr + 2); + cpu_state.npxc = (cpu_state.npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.TOP = (fpus >> 11) & 7; + cpu_state.npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, cpu_state.eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, cpu_state.eaaddr+8); + x87_pc_seg = readmemw(easeg, cpu_state.eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((cpu_state.seg_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, cpu_state.eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, cpu_state.eaaddr+16); + x87_op_off |= (readmemw(easeg, cpu_state.eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, cpu_state.eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + cpu_state.eaaddr = old_eaaddr + 32; + x87_ldmmx(&(cpu_state.MM[0]), &(cpu_state.MM_w4[0])); x87_ld_frstor(0); + + cpu_state.eaaddr = old_eaaddr + 48; + x87_ldmmx(&(cpu_state.MM[1]), &(cpu_state.MM_w4[1])); x87_ld_frstor(1); + + cpu_state.eaaddr = old_eaaddr + 64; + x87_ldmmx(&(cpu_state.MM[2]), &(cpu_state.MM_w4[2])); x87_ld_frstor(2); + + cpu_state.eaaddr = old_eaaddr + 80; + x87_ldmmx(&(cpu_state.MM[3]), &(cpu_state.MM_w4[3])); x87_ld_frstor(3); + + cpu_state.eaaddr = old_eaaddr + 96; + x87_ldmmx(&(cpu_state.MM[4]), &(cpu_state.MM_w4[4])); x87_ld_frstor(4); + + cpu_state.eaaddr = old_eaaddr + 112; + x87_ldmmx(&(cpu_state.MM[5]), &(cpu_state.MM_w4[5])); x87_ld_frstor(5); + + cpu_state.eaaddr = old_eaaddr + 128; + x87_ldmmx(&(cpu_state.MM[6]), &(cpu_state.MM_w4[6])); x87_ld_frstor(6); + + cpu_state.eaaddr = old_eaaddr + 144; + x87_ldmmx(&(cpu_state.MM[7]), &(cpu_state.MM_w4[7])); x87_ld_frstor(7); + + cpu_state.ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + p = (uint64_t *)cpu_state.tag; + 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 && !(*p)) + cpu_state.ismmx = 1; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(cpu_state.abrt) x386_dynarec_log("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + if ((twd & 0x0003) == 0x0003) ftwb |= 0x01; + if ((twd & 0x000C) == 0x000C) ftwb |= 0x02; + if ((twd & 0x0030) == 0x0030) ftwb |= 0x04; + if ((twd & 0x00C0) == 0x00C0) ftwb |= 0x08; + if ((twd & 0x0300) == 0x0300) ftwb |= 0x10; + if ((twd & 0x0C00) == 0x0C00) ftwb |= 0x20; + if ((twd & 0x3000) == 0x3000) ftwb |= 0x40; + if ((twd & 0xC000) == 0xC000) ftwb |= 0x80; + + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememb(easeg,cpu_state.eaaddr+4,ftwb); + + writememw(easeg,cpu_state.eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,cpu_state.eaaddr+8,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_seg); + + writememl(easeg,cpu_state.eaaddr+16,x87_op_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_seg); + + cpu_state.eaaddr = old_eaaddr + 32; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[0]) : x87_st_fsave(0); + + cpu_state.eaaddr = old_eaaddr + 48; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[1]) : x87_st_fsave(1); + + cpu_state.eaaddr = old_eaaddr + 64; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[2]) : x87_st_fsave(2); + + cpu_state.eaaddr = old_eaaddr + 80; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[3]) : x87_st_fsave(3); + + cpu_state.eaaddr = old_eaaddr + 96; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[4]) : x87_st_fsave(4); + + cpu_state.eaaddr = old_eaaddr + 112; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[5]) : x87_st_fsave(5); + + cpu_state.eaaddr = old_eaaddr + 128; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[6]) : x87_st_fsave(6); + + cpu_state.eaaddr = old_eaaddr + 144; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[7]) : x87_st_fsave(7); + + cpu_state.eaaddr = old_eaaddr; + + cpu_state.npxc = 0x37F; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(cpu_state.abrt) x386_dynarec_log("FXSAVE: abrt != 0\n"); + } + + return cpu_state.abrt; +} + +static int opFXSAVESTOR_a32(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint32_t old_eaaddr = 0; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + uint64_t *p; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_32(fetchdat); + + if (cpu_state.eaaddr & 0xf) + { + x386_dynarec_log("Effective address %08X not on 16-byte boundary\n", cpu_state.eaaddr); + x86gpf(NULL, 0); + return cpu_state.abrt; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (cpu_mod == 3)) + { + x86illegal(); + return cpu_state.abrt; + } + + FP_ENTER(); + + old_eaaddr = cpu_state.eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + fpus = readmemw(easeg, cpu_state.eaaddr + 2); + cpu_state.npxc = (cpu_state.npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.TOP = (fpus >> 11) & 7; + cpu_state.npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, cpu_state.eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, cpu_state.eaaddr+8); + x87_pc_seg = readmemw(easeg, cpu_state.eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((cpu_state.seg_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, cpu_state.eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, cpu_state.eaaddr+16); + x87_op_off |= (readmemw(easeg, cpu_state.eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, cpu_state.eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + cpu_state.eaaddr = old_eaaddr + 32; + x87_ldmmx(&(cpu_state.MM[0]), &(cpu_state.MM_w4[0])); x87_ld_frstor(0); + + cpu_state.eaaddr = old_eaaddr + 48; + x87_ldmmx(&(cpu_state.MM[1]), &(cpu_state.MM_w4[1])); x87_ld_frstor(1); + + cpu_state.eaaddr = old_eaaddr + 64; + x87_ldmmx(&(cpu_state.MM[2]), &(cpu_state.MM_w4[2])); x87_ld_frstor(2); + + cpu_state.eaaddr = old_eaaddr + 80; + x87_ldmmx(&(cpu_state.MM[3]), &(cpu_state.MM_w4[3])); x87_ld_frstor(3); + + cpu_state.eaaddr = old_eaaddr + 96; + x87_ldmmx(&(cpu_state.MM[4]), &(cpu_state.MM_w4[4])); x87_ld_frstor(4); + + cpu_state.eaaddr = old_eaaddr + 112; + x87_ldmmx(&(cpu_state.MM[5]), &(cpu_state.MM_w4[5])); x87_ld_frstor(5); + + cpu_state.eaaddr = old_eaaddr + 128; + x87_ldmmx(&(cpu_state.MM[6]), &(cpu_state.MM_w4[6])); x87_ld_frstor(6); + + cpu_state.eaaddr = old_eaaddr + 144; + x87_ldmmx(&(cpu_state.MM[7]), &(cpu_state.MM_w4[7])); x87_ld_frstor(7); + + cpu_state.ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + p = (uint64_t *)cpu_state.tag; + 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 && !(*p)) + cpu_state.ismmx = 1; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(cpu_state.abrt) x386_dynarec_log("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + if ((twd & 0x0003) == 0x0003) ftwb |= 0x01; + if ((twd & 0x000C) == 0x000C) ftwb |= 0x02; + if ((twd & 0x0030) == 0x0030) ftwb |= 0x04; + if ((twd & 0x00C0) == 0x00C0) ftwb |= 0x08; + if ((twd & 0x0300) == 0x0300) ftwb |= 0x10; + if ((twd & 0x0C00) == 0x0C00) ftwb |= 0x20; + if ((twd & 0x3000) == 0x3000) ftwb |= 0x40; + if ((twd & 0xC000) == 0xC000) ftwb |= 0x80; + + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememb(easeg,cpu_state.eaaddr+4,ftwb); + + writememw(easeg,cpu_state.eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,cpu_state.eaaddr+8,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_seg); + + writememl(easeg,cpu_state.eaaddr+16,x87_op_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_seg); + + cpu_state.eaaddr = old_eaaddr + 32; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[0]) : x87_st_fsave(0); + + cpu_state.eaaddr = old_eaaddr + 48; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[1]) : x87_st_fsave(1); + + cpu_state.eaaddr = old_eaaddr + 64; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[2]) : x87_st_fsave(2); + + cpu_state.eaaddr = old_eaaddr + 80; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[3]) : x87_st_fsave(3); + + cpu_state.eaaddr = old_eaaddr + 96; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[4]) : x87_st_fsave(4); + + cpu_state.eaaddr = old_eaaddr + 112; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[5]) : x87_st_fsave(5); + + cpu_state.eaaddr = old_eaaddr + 128; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[6]) : x87_st_fsave(6); + + cpu_state.eaaddr = old_eaaddr + 144; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[7]) : x87_st_fsave(7); + + cpu_state.eaaddr = old_eaaddr; + + cpu_state.npxc = 0x37F; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(cpu_state.abrt) x386_dynarec_log("FXSAVE: abrt != 0\n"); + } + + return cpu_state.abrt; +} diff --git a/src/cpu_new/x86_ops_inc_dec.h b/src/cpu_new/x86_ops_inc_dec.h new file mode 100644 index 000000000..d14bae863 --- /dev/null +++ b/src/cpu_new/x86_ops_inc_dec.h @@ -0,0 +1,93 @@ +#define INC_DEC_OP(name, reg, inc, setflags) \ + static int op ## name (uint32_t fetchdat) \ + { \ + setflags(reg, 1); \ + reg += inc; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 1, -1, 0,0,0,0, 0); \ + return 0; \ + } + +INC_DEC_OP(INC_AX, AX, 1, setadd16nc) +INC_DEC_OP(INC_BX, BX, 1, setadd16nc) +INC_DEC_OP(INC_CX, CX, 1, setadd16nc) +INC_DEC_OP(INC_DX, DX, 1, setadd16nc) +INC_DEC_OP(INC_SI, SI, 1, setadd16nc) +INC_DEC_OP(INC_DI, DI, 1, setadd16nc) +INC_DEC_OP(INC_BP, BP, 1, setadd16nc) +INC_DEC_OP(INC_SP, SP, 1, setadd16nc) + +INC_DEC_OP(INC_EAX, EAX, 1, setadd32nc) +INC_DEC_OP(INC_EBX, EBX, 1, setadd32nc) +INC_DEC_OP(INC_ECX, ECX, 1, setadd32nc) +INC_DEC_OP(INC_EDX, EDX, 1, setadd32nc) +INC_DEC_OP(INC_ESI, ESI, 1, setadd32nc) +INC_DEC_OP(INC_EDI, EDI, 1, setadd32nc) +INC_DEC_OP(INC_EBP, EBP, 1, setadd32nc) +INC_DEC_OP(INC_ESP, ESP, 1, setadd32nc) + +INC_DEC_OP(DEC_AX, AX, -1, setsub16nc) +INC_DEC_OP(DEC_BX, BX, -1, setsub16nc) +INC_DEC_OP(DEC_CX, CX, -1, setsub16nc) +INC_DEC_OP(DEC_DX, DX, -1, setsub16nc) +INC_DEC_OP(DEC_SI, SI, -1, setsub16nc) +INC_DEC_OP(DEC_DI, DI, -1, setsub16nc) +INC_DEC_OP(DEC_BP, BP, -1, setsub16nc) +INC_DEC_OP(DEC_SP, SP, -1, setsub16nc) + +INC_DEC_OP(DEC_EAX, EAX, -1, setsub32nc) +INC_DEC_OP(DEC_EBX, EBX, -1, setsub32nc) +INC_DEC_OP(DEC_ECX, ECX, -1, setsub32nc) +INC_DEC_OP(DEC_EDX, EDX, -1, setsub32nc) +INC_DEC_OP(DEC_ESI, ESI, -1, setsub32nc) +INC_DEC_OP(DEC_EDI, EDI, -1, setsub32nc) +INC_DEC_OP(DEC_EBP, EBP, -1, setsub32nc) +INC_DEC_OP(DEC_ESP, ESP, -1, setsub32nc) + + +static int opINCDEC_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp=geteab(); if (cpu_state.abrt) return 1; + + if (rmdat&0x38) + { + seteab(temp - 1); if (cpu_state.abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (cpu_state.abrt) return 1; + setadd8nc(temp, 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); + return 0; +} +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) + { + seteab(temp - 1); if (cpu_state.abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (cpu_state.abrt) return 1; + setadd8nc(temp, 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); + return 0; +} diff --git a/src/cpu_new/x86_ops_int.h b/src/cpu_new/x86_ops_int.h new file mode 100644 index 000000000..260fcdad5 --- /dev/null +++ b/src/cpu_new/x86_ops_int.h @@ -0,0 +1,91 @@ +static int opINT3(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(3); + CLOCK_CYCLES((is486) ? 44 : 59); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; +} + +static int opINT1(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(1); + CLOCK_CYCLES((is486) ? 44 : 59); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; +} + +static int opINT(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + uint8_t temp = getbytef(); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + 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(NULL,0); + return 1; + } + + x86_int_sw(temp); + PREFETCH_RUN(cycles_old-cycles, 2, -1, 0,0,0,0, 0); + return 1; +} + +static int opINTO(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (VF_SET()) + { + cpu_state.oldpc = cpu_state.pc; + x86_int_sw(4); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; + } + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + diff --git a/src/cpu_new/x86_ops_io.h b/src/cpu_new/x86_ops_io.h new file mode 100644 index 000000000..9fa91a215 --- /dev/null +++ b/src/cpu_new/x86_ops_io.h @@ -0,0 +1,146 @@ +static int opIN_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + AL = inb(port); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + AX = inw(port); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + EAX = inl(port); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, -1, 0,1,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} + +static int opOUT_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + outb(port, AL); + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); + if (port == 0x64) + return x86_was_reset; + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opOUT_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + outw(port, AX); + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opOUT_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + outl(port, EAX); + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, -1, 0,0,0,1, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} + +static int opIN_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + AL = inb(DX); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + AX = inw(DX); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + EAX = inl(DX); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 1, -1, 0,1,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} + +static int opOUT_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + outb(DX, AL); + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return x86_was_reset; +} +static int opOUT_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + outw(DX, AX); + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opOUT_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + outl(DX, EAX); + PREFETCH_RUN(11, 1, -1, 0,0,0,1, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} diff --git a/src/cpu_new/x86_ops_jump.h b/src/cpu_new/x86_ops_jump.h new file mode 100644 index 000000000..c227939a3 --- /dev/null +++ b/src/cpu_new/x86_ops_jump.h @@ -0,0 +1,381 @@ +#define cond_O ( VF_SET()) +#define cond_NO (!VF_SET()) +#define cond_B ( CF_SET()) +#define cond_NB (!CF_SET()) +#define cond_E ( ZF_SET()) +#define cond_NE (!ZF_SET()) +#define cond_BE ( CF_SET() || ZF_SET()) +#define cond_NBE (!CF_SET() && !ZF_SET()) +#define cond_S ( NF_SET()) +#define cond_NS (!NF_SET()) +#define cond_P ( PF_SET()) +#define cond_NP (!PF_SET()) +#define cond_L (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0)) +#define cond_NL (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0)) +#define cond_LE (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0) || (ZF_SET())) +#define cond_NLE (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0) && (!ZF_SET())) + +#define opJ(condition) \ + static int opJ ## condition(uint32_t fetchdat) \ + { \ + int8_t offset = (int8_t)getbytef(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + 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); \ + PREFETCH_FLUSH(); \ + return 1; \ + } \ + PREFETCH_RUN(timing_bnt, 2, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int opJ ## condition ## _w(uint32_t fetchdat) \ + { \ + int16_t offset = (int16_t)getwordf(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + 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); \ + PREFETCH_FLUSH(); \ + return 1; \ + } \ + PREFETCH_RUN(timing_bnt, 3, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int opJ ## condition ## _l(uint32_t fetchdat) \ + { \ + uint32_t offset = getlong(); if (cpu_state.abrt) return 1; \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + PREFETCH_RUN(timing_bt+timing_bnt, 5, -1, 0,0,0,0, 0); \ + PREFETCH_FLUSH(); \ + return 1; \ + } \ + PREFETCH_RUN(timing_bnt, 5, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + +opJ(O) +opJ(NO) +opJ(B) +opJ(NB) +opJ(E) +opJ(NE) +opJ(BE) +opJ(NBE) +opJ(S) +opJ(NS) +opJ(P) +opJ(NP) +opJ(L) +opJ(NL) +opJ(LE) +opJ(NLE) + + + +static int opLOOPNE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (CX && !ZF_SET()) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} +static int opLOOPNE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (ECX && !ZF_SET()) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} + +static int opLOOPE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (CX && ZF_SET()) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} +static int opLOOPE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (ECX && ZF_SET()) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} + +static int opLOOP_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (CX) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} +static int opLOOP_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (ECX) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} + +static int opJCXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + if (!CX) + { + cpu_state.pc += offset; + 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); + PREFETCH_FLUSH(); + return 1; + } + PREFETCH_RUN(5, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opJECXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + 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); + PREFETCH_FLUSH(); + return 1; + } + PREFETCH_RUN(5, 2, -1, 0,0,0,0, 0); + return 0; +} + + +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); + PREFETCH_FLUSH(); + return 0; +} +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); + PREFETCH_FLUSH(); + return 0; +} +static int opJMP_r32(uint32_t fetchdat) +{ + int32_t offset = (int32_t)getlong(); if (cpu_state.abrt) return 1; + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 5, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opJMP_far_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + uint32_t old_pc; + addr = getwordf(); + seg = getword(); if (cpu_state.abrt) return 1; + old_pc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, old_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(11, 5, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opJMP_far_a32(uint32_t fetchdat) +{ + uint16_t seg; + uint32_t addr, old_pc; + addr = getlong(); + seg = getword(); if (cpu_state.abrt) return 1; + old_pc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, old_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(11, 7, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opCALL_r16(uint32_t fetchdat) +{ + int16_t addr = (int16_t)getwordf(); + PUSH_W(cpu_state.pc); + cpu_state.pc += addr; + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 3, -1, 0,0,1,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opCALL_r32(uint32_t fetchdat) +{ + int32_t addr = getlong(); if (cpu_state.abrt) return 1; + PUSH_L(cpu_state.pc); + cpu_state.pc += addr; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 5, -1, 0,0,0,1, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opRET_w(uint32_t fetchdat) +{ + uint16_t ret; + + ret = POP_W(); if (cpu_state.abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 1, -1, 1,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRET_l(uint32_t fetchdat) +{ + uint32_t ret; + + ret = POP_L(); if (cpu_state.abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 1, -1, 0,1,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opRET_w_imm(uint32_t fetchdat) +{ + uint16_t ret; + uint16_t offset = getwordf(); + + ret = POP_W(); if (cpu_state.abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 5, -1, 1,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRET_l_imm(uint32_t fetchdat) +{ + uint32_t ret; + uint16_t offset = getwordf(); + + ret = POP_L(); if (cpu_state.abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 5, -1, 0,1,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + diff --git a/src/cpu_new/x86_ops_misc.h b/src/cpu_new/x86_ops_misc.h new file mode 100644 index 000000000..f8db6c592 --- /dev/null +++ b/src/cpu_new/x86_ops_misc.h @@ -0,0 +1,971 @@ +static int opCBW(uint32_t fetchdat) +{ + AH = (AL & 0x80) ? 0xff : 0; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCWDE(uint32_t fetchdat) +{ + EAX = (AX & 0x8000) ? (0xffff0000 | AX) : AX; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCWD(uint32_t fetchdat) +{ + DX = (AX & 0x8000) ? 0xFFFF : 0; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCDQ(uint32_t fetchdat) +{ + EDX = (EAX & 0x80000000) ? 0xffffffff : 0; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opNOP(uint32_t fetchdat) +{ + CLOCK_CYCLES((is486) ? 1 : 3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opSETALC(uint32_t fetchdat) +{ + AL = (CF_SET()) ? 0xff : 0; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 1, -1, 0,0,0,0, 0); + return 0; +} + + + +static int opF6_a16(uint32_t fetchdat) +{ + 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) + { + case 0x00: /*TEST b,#8*/ + case 0x08: + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + 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); + 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 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + 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; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) 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; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; + } + } + else + { + x86_int(0); + return 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, 0); + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + cpu_state.flags|=0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + PREFETCH_RUN(19, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + + default: + x86illegal(); + } + return 0; +} +static int opF6_a32(uint32_t fetchdat) +{ + 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) + { + case 0x00: /*TEST b,#8*/ + case 0x08: + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + 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); + 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 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + 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; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) 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; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; + } + } + else + { + x86_int(0); + return 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; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + PREFETCH_RUN(19, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + + default: + x86illegal(); + } + return 0; +} + + + +static int opF7_w_a16(uint32_t fetchdat) +{ + uint32_t templ, templ2; + 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) + { + case 0x00: /*TEST w*/ + case 0x08: + src = getword(); if (cpu_state.abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + 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); + 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 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + 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; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) 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; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 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, 0); + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + PREFETCH_RUN(27, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + + default: + x86illegal(); + } + return 0; +} +static int opF7_w_a32(uint32_t fetchdat) +{ + uint32_t templ, templ2; + 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) + { + case 0x00: /*TEST w*/ + case 0x08: + src = getword(); if (cpu_state.abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + 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); + 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 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + 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; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) 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; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); + x86_int(0); + return 1; + } + CLOCK_CYCLES((is486 && !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); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + PREFETCH_RUN(27, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + + default: + x86illegal(); + } + return 0; +} + +static int opF7_l_a16(uint32_t fetchdat) +{ + uint64_t temp64; + 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) + { + case 0x00: /*TEST l*/ + case 0x08: + src = getlong(); if (cpu_state.abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + 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); + 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 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + 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; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) 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; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + PREFETCH_RUN(is486 ? 40:38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + PREFETCH_RUN(43, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + + default: + x86illegal(); + } + return 0; +} +static int opF7_l_a32(uint32_t fetchdat) +{ + uint64_t temp64; + 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) + { + case 0x00: /*TEST l*/ + case 0x08: + src = getlong(); if (cpu_state.abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + 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); + 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 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + 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; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) 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; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + PREFETCH_RUN(is486 ? 40 : 38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + PREFETCH_RUN(43, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + + default: + x86illegal(); + } + return 0; +} + + +static int opHLT(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + if (!((cpu_state.flags & I_FLAG) && pic_intpending)) + { + CLOCK_CYCLES_ALWAYS(100); + cpu_state.pc--; + } + else + CLOCK_CYCLES(5); + + CPU_BLOCK_END(); + PREFETCH_RUN(100, 1, -1, 0,0,0,0, 0); + + return 0; +} + + +static int opLOCK(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 0; + cpu_state.pc++; + + ILLEGAL_ON((fetchdat & 0xff) == 0x90); + + CLOCK_CYCLES(4); + PREFETCH_PREFIX(); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} + + + +static int opBOUND_w_a16(uint32_t fetchdat) +{ + int16_t low, high; + + 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; + + if (((int16_t)cpu_state.regs[cpu_reg].w < low) || ((int16_t)cpu_state.regs[cpu_reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 2,0,0,0, 0); + return 0; +} +static int opBOUND_w_a32(uint32_t fetchdat) +{ + int16_t low, high; + + 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; + + if (((int16_t)cpu_state.regs[cpu_reg].w < low) || ((int16_t)cpu_state.regs[cpu_reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 2,0,0,0, 1); + return 0; +} + +static int opBOUND_l_a16(uint32_t fetchdat) +{ + int32_t low, high; + + 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; + + if (((int32_t)cpu_state.regs[cpu_reg].l < low) || ((int32_t)cpu_state.regs[cpu_reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 1,1,0,0, 0); + return 0; +} +static int opBOUND_l_a32(uint32_t fetchdat) +{ + int32_t low, high; + + 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; + + if (((int32_t)cpu_state.regs[cpu_reg].l < low) || ((int32_t)cpu_state.regs[cpu_reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 1,1,0,0, 1); + return 0; +} + + +static int opCLTS(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + cr0 &= ~8; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(1000); + CPU_BLOCK_END(); + return 0; +} +static int opWBINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(10000); + CPU_BLOCK_END(); + return 0; +} + +static int opLOADALL(uint32_t fetchdat) +{ + if (CPL && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + 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); + ldt.seg = readmemw(0, 0x81C); + DS = readmemw(0, 0x81E); + SS = readmemw(0, 0x820); + CS = readmemw(0, 0x822); + ES = readmemw(0, 0x824); + DI = readmemw(0, 0x826); + SI = readmemw(0, 0x828); + BP = readmemw(0, 0x82A); + SP = readmemw(0, 0x82C); + BX = readmemw(0, 0x82E); + DX = readmemw(0, 0x830); + CX = readmemw(0, 0x832); + AX = readmemw(0, 0x834); + es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16); + cpu_state.seg_es.access = readmemb(0, 0x839); + cpu_state.seg_es.limit = readmemw(0, 0x83A); + cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16); + cpu_state.seg_cs.access = readmemb(0, 0x83F); + cpu_state.seg_cs.limit = readmemw(0, 0x840); + ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16); + 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); + 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); + ldt.access = readmemb(0, 0x857); + ldt.limit = readmemw(0, 0x858); + idt.base = readmemw(0, 0x85A) | (readmemb(0, 0x85C) << 16); + idt.limit = readmemw(0, 0x85E); + tr.base = readmemw(0, 0x860) | (readmemb(0, 0x862) << 16); + tr.access = readmemb(0, 0x863); + tr.limit = readmemw(0, 0x864); + CLOCK_CYCLES(195); + PREFETCH_RUN(195, 1, -1, 51,0,0,0, 0); + return 0; +} + +static void set_segment_limit(x86seg *s, uint8_t segdat3) +{ + if ((s->access & 0x18) != 0x10 || !(s->access & (1 << 2))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat3 & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } +} + +static void loadall_load_segment(uint32_t addr, x86seg *s) +{ + uint32_t attrib = readmeml(0, addr); + uint32_t segdat3 = (attrib >> 16) & 0xff; + s->access = (attrib >> 8) & 0xff; + s->base = readmeml(0, addr + 4); + s->limit = readmeml(0, addr + 8); + + if (s == &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) +{ + uint32_t la_addr = es + EDI; + + cr0 = readmeml(0, la_addr); + 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); + ESI = readmeml(0, la_addr + 0x10); + EBP = readmeml(0, la_addr + 0x14); + ESP = readmeml(0, la_addr + 0x18); + EBX = readmeml(0, la_addr + 0x1C); + EDX = readmeml(0, la_addr + 0x20); + ECX = readmeml(0, la_addr + 0x24); + EAX = readmeml(0, la_addr + 0x28); + dr[6] = readmeml(0, la_addr + 0x2C); + dr[7] = readmeml(0, la_addr + 0x30); + tr.seg = readmemw(0, la_addr + 0x34); + ldt.seg = readmemw(0, la_addr + 0x38); + GS = readmemw(0, la_addr + 0x3C); + FS = readmemw(0, la_addr + 0x40); + DS = readmemw(0, la_addr + 0x44); + SS = readmemw(0, la_addr + 0x48); + CS = readmemw(0, la_addr + 0x4C); + ES = readmemw(0, la_addr + 0x50); + + loadall_load_segment(la_addr + 0x54, &tr); + loadall_load_segment(la_addr + 0x60, &idt); + loadall_load_segment(la_addr + 0x6c, &gdt); + loadall_load_segment(la_addr + 0x78, &ldt); + loadall_load_segment(la_addr + 0x84, &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; +} + +static int opCPUID(uint32_t fetchdat) +{ + if (CPUID) + { + cpu_CPUID(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} + +static int opRDMSR(uint32_t fetchdat) +{ + if (cpu_has_feature(CPU_FEATURE_MSR)) + { + cpu_RDMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} + +static int opWRMSR(uint32_t fetchdat) +{ + if (cpu_has_feature(CPU_FEATURE_MSR)) + { + cpu_WRMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} + +static int opRSM(uint32_t fetchdat) +{ + if(!in_smm) + { + leave_smm(); + if(smi_latched) enter_smm(); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} \ No newline at end of file diff --git a/src/cpu_new/x86_ops_mmx.h b/src/cpu_new/x86_ops_mmx.h new file mode 100644 index 000000000..f9a7f9357 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx.h @@ -0,0 +1,49 @@ +#define SSATB(val) (((val) < -128) ? -128 : (((val) > 127) ? 127 : (val))) +#define SSATW(val) (((val) < -32768) ? -32768 : (((val) > 32767) ? 32767 : (val))) +#define USATB(val) (((val) < 0) ? 0 : (((val) > 255) ? 255 : (val))) +#define USATW(val) (((val) < 0) ? 0 : (((val) > 65535) ? 65535 : (val))) + +#define MMX_GETSRC() \ + if (cpu_mod == 3) \ + { \ + src = cpu_state.MM[cpu_rm]; \ + CLOCK_CYCLES(1); \ + } \ + 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_has_feature(CPU_FEATURE_MMX)) \ + { \ + cpu_state.pc = cpu_state.oldpc; \ + x86illegal(); \ + return 1; \ + } \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + x87_set_mmx() + +static int opEMMS(uint32_t fetchdat) +{ + if (!cpu_has_feature(CPU_FEATURE_MMX)) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + x87_emms(); + CLOCK_CYCLES(100); /*Guess*/ + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_arith.h b/src/cpu_new/x86_ops_mmx_arith.h new file mode 100644 index 000000000..22c34c738 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_arith.h @@ -0,0 +1,629 @@ +static int opPADDB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] += src.b[0]; + cpu_state.MM[cpu_reg].b[1] += src.b[1]; + cpu_state.MM[cpu_reg].b[2] += src.b[2]; + cpu_state.MM[cpu_reg].b[3] += src.b[3]; + cpu_state.MM[cpu_reg].b[4] += src.b[4]; + cpu_state.MM[cpu_reg].b[5] += src.b[5]; + cpu_state.MM[cpu_reg].b[6] += src.b[6]; + cpu_state.MM[cpu_reg].b[7] += src.b[7]; + + return 0; +} +static int opPADDB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] += src.b[0]; + cpu_state.MM[cpu_reg].b[1] += src.b[1]; + cpu_state.MM[cpu_reg].b[2] += src.b[2]; + cpu_state.MM[cpu_reg].b[3] += src.b[3]; + cpu_state.MM[cpu_reg].b[4] += src.b[4]; + cpu_state.MM[cpu_reg].b[5] += src.b[5]; + cpu_state.MM[cpu_reg].b[6] += src.b[6]; + cpu_state.MM[cpu_reg].b[7] += src.b[7]; + + return 0; +} + +static int opPADDW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] += src.w[0]; + cpu_state.MM[cpu_reg].w[1] += src.w[1]; + cpu_state.MM[cpu_reg].w[2] += src.w[2]; + cpu_state.MM[cpu_reg].w[3] += src.w[3]; + + return 0; +} +static int opPADDW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] += src.w[0]; + cpu_state.MM[cpu_reg].w[1] += src.w[1]; + cpu_state.MM[cpu_reg].w[2] += src.w[2]; + cpu_state.MM[cpu_reg].w[3] += src.w[3]; + + return 0; +} + +static int opPADDD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] += src.l[0]; + cpu_state.MM[cpu_reg].l[1] += src.l[1]; + + return 0; +} +static int opPADDD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] += src.l[0]; + cpu_state.MM[cpu_reg].l[1] += src.l[1]; + + return 0; +} + +static int opPADDSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] + src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] + src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] + src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] + src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] + src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] + src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] + src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] + src.sb[7]); + + return 0; +} +static int opPADDSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] + src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] + src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] + src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] + src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] + src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] + src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] + src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] + src.sb[7]); + + return 0; +} + +static int opPADDUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] + src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] + src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] + src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] + src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] + src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] + src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] + src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] + src.b[7]); + + return 0; +} +static int opPADDUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] + src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] + src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] + src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] + src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] + src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] + src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] + src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] + src.b[7]); + + return 0; +} + +static int opPADDSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] + src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] + src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] + src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] + src.sw[3]); + + return 0; +} +static int opPADDSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] + src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] + src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] + src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] + src.sw[3]); + + return 0; +} + +static int opPADDUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] + src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] + src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] + src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] + src.w[3]); + + return 0; +} +static int opPADDUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] + src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] + src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] + src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] + src.w[3]); + + return 0; +} + +static int opPMADDWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + if (cpu_state.MM[cpu_reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + cpu_state.MM[cpu_reg].l[0] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]); + + if (cpu_state.MM[cpu_reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + cpu_state.MM[cpu_reg].l[1] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} +static int opPMADDWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + if (cpu_state.MM[cpu_reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + cpu_state.MM[cpu_reg].l[0] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]); + + if (cpu_state.MM[cpu_reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + cpu_state.MM[cpu_reg].l[1] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} + + +static int opPMULLW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] *= cpu_state.MM[cpu_rm].w[0]; + cpu_state.MM[cpu_reg].w[1] *= cpu_state.MM[cpu_rm].w[1]; + cpu_state.MM[cpu_reg].w[2] *= cpu_state.MM[cpu_rm].w[2]; + cpu_state.MM[cpu_reg].w[3] *= cpu_state.MM[cpu_rm].w[3]; + 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] *= src.w[0]; + cpu_state.MM[cpu_reg].w[1] *= src.w[1]; + cpu_state.MM[cpu_reg].w[2] *= src.w[2]; + cpu_state.MM[cpu_reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULLW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] *= cpu_state.MM[cpu_rm].w[0]; + cpu_state.MM[cpu_reg].w[1] *= cpu_state.MM[cpu_rm].w[1]; + cpu_state.MM[cpu_reg].w[2] *= cpu_state.MM[cpu_rm].w[2]; + cpu_state.MM[cpu_reg].w[3] *= cpu_state.MM[cpu_rm].w[3]; + 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] *= src.w[0]; + cpu_state.MM[cpu_reg].w[1] *= src.w[1]; + cpu_state.MM[cpu_reg].w[2] *= src.w[2]; + cpu_state.MM[cpu_reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPMULHW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (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]) >> 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]) >> 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]) >> 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]) >> 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]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULHW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (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]) >> 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]) >> 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]) >> 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]) >> 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]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPSUBB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] -= src.b[0]; + cpu_state.MM[cpu_reg].b[1] -= src.b[1]; + cpu_state.MM[cpu_reg].b[2] -= src.b[2]; + cpu_state.MM[cpu_reg].b[3] -= src.b[3]; + cpu_state.MM[cpu_reg].b[4] -= src.b[4]; + cpu_state.MM[cpu_reg].b[5] -= src.b[5]; + cpu_state.MM[cpu_reg].b[6] -= src.b[6]; + cpu_state.MM[cpu_reg].b[7] -= src.b[7]; + + return 0; +} +static int opPSUBB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] -= src.b[0]; + cpu_state.MM[cpu_reg].b[1] -= src.b[1]; + cpu_state.MM[cpu_reg].b[2] -= src.b[2]; + cpu_state.MM[cpu_reg].b[3] -= src.b[3]; + cpu_state.MM[cpu_reg].b[4] -= src.b[4]; + cpu_state.MM[cpu_reg].b[5] -= src.b[5]; + cpu_state.MM[cpu_reg].b[6] -= src.b[6]; + cpu_state.MM[cpu_reg].b[7] -= src.b[7]; + + return 0; +} + +static int opPSUBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] -= src.w[0]; + cpu_state.MM[cpu_reg].w[1] -= src.w[1]; + cpu_state.MM[cpu_reg].w[2] -= src.w[2]; + cpu_state.MM[cpu_reg].w[3] -= src.w[3]; + + return 0; +} +static int opPSUBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] -= src.w[0]; + cpu_state.MM[cpu_reg].w[1] -= src.w[1]; + cpu_state.MM[cpu_reg].w[2] -= src.w[2]; + cpu_state.MM[cpu_reg].w[3] -= src.w[3]; + + return 0; +} + +static int opPSUBD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] -= src.l[0]; + cpu_state.MM[cpu_reg].l[1] -= src.l[1]; + + return 0; +} +static int opPSUBD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] -= src.l[0]; + cpu_state.MM[cpu_reg].l[1] -= src.l[1]; + + return 0; +} + +static int opPSUBSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] - src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] - src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] - src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] - src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] - src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] - src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] - src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] - src.sb[7]); + + return 0; +} +static int opPSUBSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] - src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] - src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] - src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] - src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] - src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] - src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] - src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] - src.sb[7]); + + return 0; +} + +static int opPSUBUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] - src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] - src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] - src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] - src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] - src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] - src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] - src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] - src.b[7]); + + return 0; +} +static int opPSUBUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] - src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] - src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] - src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] - src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] - src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] - src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] - src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] - src.b[7]); + + return 0; +} + +static int opPSUBSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] - src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] - src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] - src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] - src.sw[3]); + + return 0; +} +static int opPSUBSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] - src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] - src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] - src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] - src.sw[3]); + + return 0; +} + +static int opPSUBUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] - src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] - src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] - src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] - src.w[3]); + + return 0; +} +static int opPSUBUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] - src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] - src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] - src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] - src.w[3]); + + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_cmp.h b/src/cpu_new/x86_ops_mmx_cmp.h new file mode 100644 index 000000000..0fee95923 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_cmp.h @@ -0,0 +1,205 @@ +static int opPCMPEQB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].b[0] == src.b[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].b[1] == src.b[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].b[2] == src.b[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].b[3] == src.b[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].b[4] == src.b[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] == src.b[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] == src.b[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPEQB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].b[0] == src.b[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].b[1] == src.b[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].b[2] == src.b[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].b[3] == src.b[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].b[4] == src.b[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] == src.b[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] == src.b[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPGTB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].sb[0] > src.sb[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].sb[1] > src.sb[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].sb[2] > src.sb[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].sb[3] > src.sb[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].sb[4] > src.sb[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].sb[5] > src.sb[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].sb[6] > src.sb[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPGTB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].sb[0] > src.sb[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].sb[1] > src.sb[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].sb[2] > src.sb[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].sb[3] > src.sb[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].sb[4] > src.sb[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].sb[5] > src.sb[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].sb[6] > src.sb[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPEQW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].w[0] == src.w[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].w[1] == src.w[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].w[2] == src.w[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPEQW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].w[0] == src.w[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].w[1] == src.w[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].w[2] == src.w[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPGTW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].sw[0] > src.sw[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].sw[1] > src.sw[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].sw[2] > src.sw[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPGTW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].sw[0] > src.sw[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].sw[1] > src.sw[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].sw[2] > src.sw[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPEQD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPEQD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + 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; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} + +static int opPCMPGTD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPGTD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + 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; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_logic.h b/src/cpu_new/x86_ops_mmx_logic.h new file mode 100644 index 000000000..be5132e85 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_logic.h @@ -0,0 +1,91 @@ +static int opPAND_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q &= src.q; + return 0; +} +static int opPAND_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q &= src.q; + return 0; +} + +static int opPANDN_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q = ~cpu_state.MM[cpu_reg].q & src.q; + return 0; +} +static int opPANDN_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q = ~cpu_state.MM[cpu_reg].q & src.q; + return 0; +} + +static int opPOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q |= src.q; + return 0; +} +static int opPOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q |= src.q; + return 0; +} + +static int opPXOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q ^= src.q; + return 0; +} +static int opPXOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q ^= src.q; + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_mov.h b/src/cpu_new/x86_ops_mmx_mov.h new file mode 100644 index 000000000..e17721229 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_mov.h @@ -0,0 +1,169 @@ +static int opMOVD_l_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[0] = cpu_state.regs[cpu_rm].l; + cpu_state.MM[cpu_reg].l[1] = 0; + CLOCK_CYCLES(1); + } + 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; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_l_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[0] = cpu_state.regs[cpu_rm].l; + cpu_state.MM[cpu_reg].l[1] = 0; + CLOCK_CYCLES(1); + } + 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; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVD_mm_l_a16(uint32_t 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_COMMON(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(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_COMMON(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 opMOVQ_q_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].q = cpu_state.MM[cpu_rm].q; + CLOCK_CYCLES(1); + } + else + { + 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); + } + return 0; +} +static int opMOVQ_q_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].q = cpu_state.MM[cpu_rm].q; + CLOCK_CYCLES(1); + } + else + { + 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); + } + return 0; +} + +static int opMOVQ_mm_q_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_rm].q = cpu_state.MM[cpu_reg].q; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(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); + } + return 0; +} +static int opMOVQ_mm_q_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_rm].q = cpu_state.MM[cpu_reg].q; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(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); + } + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_pack.h b/src/cpu_new/x86_ops_mmx_pack.h new file mode 100644 index 000000000..b03ef842e --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_pack.h @@ -0,0 +1,326 @@ +static int opPUNPCKLDQ_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[1] = cpu_state.MM[cpu_rm].l[0]; + CLOCK_CYCLES(1); + } + 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; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opPUNPCKLDQ_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[1] = cpu_state.MM[cpu_rm].l[0]; + CLOCK_CYCLES(1); + } + 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; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPUNPCKHDQ_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = cpu_state.MM[cpu_reg].l[1]; + cpu_state.MM[cpu_reg].l[1] = src.l[1]; + + return 0; +} +static int opPUNPCKHDQ_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = cpu_state.MM[cpu_reg].l[1]; + cpu_state.MM[cpu_reg].l[1] = src.l[1]; + + return 0; +} + +static int opPUNPCKLBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[7] = src.b[3]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[3]; + cpu_state.MM[cpu_reg].b[5] = src.b[2]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[2]; + cpu_state.MM[cpu_reg].b[3] = src.b[1]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[1]; + cpu_state.MM[cpu_reg].b[1] = src.b[0]; + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[0]; + + return 0; +} +static int opPUNPCKLBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[7] = src.b[3]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[3]; + cpu_state.MM[cpu_reg].b[5] = src.b[2]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[2]; + cpu_state.MM[cpu_reg].b[3] = src.b[1]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[1]; + cpu_state.MM[cpu_reg].b[1] = src.b[0]; + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[0]; + + return 0; +} + +static int opPUNPCKHBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[4]; + cpu_state.MM[cpu_reg].b[1] = src.b[4]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[5]; + cpu_state.MM[cpu_reg].b[3] = src.b[5]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[6]; + cpu_state.MM[cpu_reg].b[5] = src.b[6]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[7]; + cpu_state.MM[cpu_reg].b[7] = src.b[7]; + + return 0; +} +static int opPUNPCKHBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[4]; + cpu_state.MM[cpu_reg].b[1] = src.b[4]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[5]; + cpu_state.MM[cpu_reg].b[3] = src.b[5]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[6]; + cpu_state.MM[cpu_reg].b[5] = src.b[6]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[7]; + cpu_state.MM[cpu_reg].b[7] = src.b[7]; + + return 0; +} + +static int opPUNPCKLWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[3] = src.w[1]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[1]; + cpu_state.MM[cpu_reg].w[1] = src.w[0]; + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[0]; + + return 0; +} +static int opPUNPCKLWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[3] = src.w[1]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[1]; + cpu_state.MM[cpu_reg].w[1] = src.w[0]; + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[0]; + + return 0; +} + +static int opPUNPCKHWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[2]; + cpu_state.MM[cpu_reg].w[1] = src.w[2]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[3]; + cpu_state.MM[cpu_reg].w[3] = src.w[3]; + + return 0; +} +static int opPUNPCKHWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[2]; + cpu_state.MM[cpu_reg].w[1] = src.w[2]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[3]; + cpu_state.MM[cpu_reg].w[3] = src.w[3]; + + return 0; +} + +static int opPACKSSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sb[0] = SSATB(dst.sw[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(dst.sw[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(dst.sw[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(dst.sw[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(src.sw[0]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(src.sw[1]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(src.sw[2]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} +static int opPACKSSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sb[0] = SSATB(dst.sw[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(dst.sw[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(dst.sw[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(dst.sw[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(src.sw[0]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(src.sw[1]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(src.sw[2]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} + +static int opPACKUSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].b[0] = USATB(dst.sw[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(dst.sw[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(dst.sw[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(dst.sw[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(src.sw[0]); + cpu_state.MM[cpu_reg].b[5] = USATB(src.sw[1]); + cpu_state.MM[cpu_reg].b[6] = USATB(src.sw[2]); + cpu_state.MM[cpu_reg].b[7] = USATB(src.sw[3]); + + return 0; +} +static int opPACKUSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].b[0] = USATB(dst.sw[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(dst.sw[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(dst.sw[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(dst.sw[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(src.sw[0]); + cpu_state.MM[cpu_reg].b[5] = USATB(src.sw[1]); + cpu_state.MM[cpu_reg].b[6] = USATB(src.sw[2]); + cpu_state.MM[cpu_reg].b[7] = USATB(src.sw[3]); + + return 0; +} + +static int opPACKSSDW_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sw[0] = SSATW(dst.sl[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(dst.sl[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(src.sl[0]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} +static int opPACKSSDW_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sw[0] = SSATW(dst.sl[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(dst.sl[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(src.sl[0]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_shift.h b/src/cpu_new/x86_ops_mmx_shift.h new file mode 100644 index 000000000..a0a4d90c1 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_shift.h @@ -0,0 +1,450 @@ +#define MMX_GETSHIFT() \ + if (cpu_mod == 3) \ + { \ + shift = cpu_state.MM[cpu_rm].b[0]; \ + CLOCK_CYCLES(1); \ + } \ + else \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + shift = readmemb(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; \ + CLOCK_CYCLES(2); \ + } + +static int opPSxxW_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 15) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].w[0] >>= shift; + cpu_state.MM[reg].w[1] >>= shift; + cpu_state.MM[reg].w[2] >>= shift; + cpu_state.MM[reg].w[3] >>= shift; + } + break; + case 0x20: /*PSRAW*/ + if (shift > 15) + shift = 15; + cpu_state.MM[reg].sw[0] >>= shift; + cpu_state.MM[reg].sw[1] >>= shift; + cpu_state.MM[reg].sw[2] >>= shift; + cpu_state.MM[reg].sw[3] >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 15) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].w[0] <<= shift; + cpu_state.MM[reg].w[1] <<= shift; + cpu_state.MM[reg].w[2] <<= shift; + cpu_state.MM[reg].w[3] <<= shift; + } + break; + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] <<= shift; + cpu_state.MM[cpu_reg].w[1] <<= shift; + cpu_state.MM[cpu_reg].w[2] <<= shift; + cpu_state.MM[cpu_reg].w[3] <<= shift; + } + + return 0; +} +static int opPSLLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] <<= shift; + cpu_state.MM[cpu_reg].w[1] <<= shift; + cpu_state.MM[cpu_reg].w[2] <<= shift; + cpu_state.MM[cpu_reg].w[3] <<= shift; + } + + return 0; +} + +static int opPSRLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] >>= shift; + cpu_state.MM[cpu_reg].w[1] >>= shift; + cpu_state.MM[cpu_reg].w[2] >>= shift; + cpu_state.MM[cpu_reg].w[3] >>= shift; + } + + return 0; +} +static int opPSRLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] >>= shift; + cpu_state.MM[cpu_reg].w[1] >>= shift; + cpu_state.MM[cpu_reg].w[2] >>= shift; + cpu_state.MM[cpu_reg].w[3] >>= shift; + } + + return 0; +} + +static int opPSRAW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + cpu_state.MM[cpu_reg].sw[0] >>= shift; + cpu_state.MM[cpu_reg].sw[1] >>= shift; + cpu_state.MM[cpu_reg].sw[2] >>= shift; + cpu_state.MM[cpu_reg].sw[3] >>= shift; + + return 0; +} +static int opPSRAW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + cpu_state.MM[cpu_reg].sw[0] >>= shift; + cpu_state.MM[cpu_reg].sw[1] >>= shift; + cpu_state.MM[cpu_reg].sw[2] >>= shift; + cpu_state.MM[cpu_reg].sw[3] >>= shift; + + return 0; +} + +static int opPSxxD_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLD*/ + if (shift > 31) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].l[0] >>= shift; + cpu_state.MM[reg].l[1] >>= shift; + } + break; + case 0x20: /*PSRAD*/ + if (shift > 31) + shift = 31; + cpu_state.MM[reg].sl[0] >>= shift; + cpu_state.MM[reg].sl[1] >>= shift; + break; + case 0x30: /*PSLLD*/ + if (shift > 31) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].l[0] <<= shift; + cpu_state.MM[reg].l[1] <<= shift; + } + break; + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] <<= shift; + cpu_state.MM[cpu_reg].l[1] <<= shift; + } + + return 0; +} +static int opPSLLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] <<= shift; + cpu_state.MM[cpu_reg].l[1] <<= shift; + } + + return 0; +} + +static int opPSRLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] >>= shift; + cpu_state.MM[cpu_reg].l[1] >>= shift; + } + + return 0; +} +static int opPSRLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] >>= shift; + cpu_state.MM[cpu_reg].l[1] >>= shift; + } + + return 0; +} + +static int opPSRAD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + cpu_state.MM[cpu_reg].sl[0] >>= shift; + cpu_state.MM[cpu_reg].sl[1] >>= shift; + + return 0; +} +static int opPSRAD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + cpu_state.MM[cpu_reg].sl[0] >>= shift; + cpu_state.MM[cpu_reg].sl[1] >>= shift; + + return 0; +} + +static int opPSxxQ_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 63) + cpu_state.MM[reg].q = 0; + else + cpu_state.MM[reg].q >>= shift; + break; + case 0x20: /*PSRAW*/ + if (shift > 63) + shift = 63; + cpu_state.MM[reg].sq >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 63) + cpu_state.MM[reg].q = 0; + else + cpu_state.MM[reg].q <<= shift; + break; + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q <<= shift; + + return 0; +} +static int opPSLLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q <<= shift; + + return 0; +} + +static int opPSRLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q >>= shift; + + return 0; +} +static int opPSRLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q >>= shift; + + return 0; +} diff --git a/src/cpu_new/x86_ops_mov.h b/src/cpu_new/x86_ops_mov.h new file mode 100644 index 000000000..2c96317b7 --- /dev/null +++ b/src/cpu_new/x86_ops_mov.h @@ -0,0 +1,784 @@ +static int opMOV_AL_imm(uint32_t fetchdat) +{ + AL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_AH_imm(uint32_t fetchdat) +{ + AH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BL_imm(uint32_t fetchdat) +{ + BL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BH_imm(uint32_t fetchdat) +{ + BH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_CL_imm(uint32_t fetchdat) +{ + CL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_CH_imm(uint32_t fetchdat) +{ + CH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DL_imm(uint32_t fetchdat) +{ + DL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DH_imm(uint32_t fetchdat) +{ + DH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opMOV_AX_imm(uint32_t fetchdat) +{ + AX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BX_imm(uint32_t fetchdat) +{ + BX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_CX_imm(uint32_t fetchdat) +{ + CX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DX_imm(uint32_t fetchdat) +{ + DX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_SI_imm(uint32_t fetchdat) +{ + SI = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DI_imm(uint32_t fetchdat) +{ + DI = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BP_imm(uint32_t fetchdat) +{ + BP = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_SP_imm(uint32_t fetchdat) +{ + SP = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} + +static int opMOV_EAX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EAX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EBX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EBX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_ECX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + ECX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EDX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EDX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_ESI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + ESI = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EDI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EDI = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EBP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EBP = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_ESP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + ESP = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + +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; + seteab(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 0); + return cpu_state.abrt; +} +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); + PREFETCH_RUN(timing_rr, 3, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 1); + return cpu_state.abrt; +} + +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); + PREFETCH_RUN(timing_rr, 4, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 0); + return cpu_state.abrt; +} +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); + PREFETCH_RUN(timing_rr, 4, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 1); + return cpu_state.abrt; +} +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); + PREFETCH_RUN(timing_rr, 6, rmdat, 0,0,0,(cpu_mod == 3) ? 1:0, 0); + return cpu_state.abrt; +} +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); + PREFETCH_RUN(timing_rr, 6, rmdat, 0,0,0,(cpu_mod == 3) ? 1:0, 1); + return cpu_state.abrt; +} + + +static int opMOV_AL_a16(uint32_t fetchdat) +{ + uint8_t temp; + uint16_t addr = getwordf(); + 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); + return 0; +} +static int opMOV_AL_a32(uint32_t fetchdat) +{ + uint8_t temp; + uint32_t addr = getlong(); + 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); + return 0; +} +static int opMOV_AX_a16(uint32_t fetchdat) +{ + uint16_t temp; + uint16_t addr = getwordf(); + 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); + return 0; +} +static int opMOV_AX_a32(uint32_t fetchdat) +{ + uint16_t temp; + uint32_t addr = getlong(); + 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); + return 0; +} +static int opMOV_EAX_a16(uint32_t fetchdat) +{ + uint32_t temp; + uint16_t addr = getwordf(); + 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); + return 0; +} +static int opMOV_EAX_a32(uint32_t fetchdat) +{ + uint32_t temp; + uint32_t addr = getlong(); + 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); + return 0; +} + +static int opMOV_a16_AL(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr); + writememb(cpu_state.ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opMOV_a32_AL(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr); + writememb(cpu_state.ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); + return cpu_state.abrt; +} +static int opMOV_a16_AX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 1); + writememw(cpu_state.ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +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); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 1); + writememw(cpu_state.ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); + return cpu_state.abrt; +} +static int opMOV_a16_EAX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 3); + writememl(cpu_state.ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} +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); + CHECK_WRITE_COMMON(cpu_state.ea_seg, addr, addr + 3); + writememl(cpu_state.ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 5, -1, 0,0,0,1, 1); + return cpu_state.abrt; +} + + +static int opLEA_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opLEA_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opLEA_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].l = cpu_state.eaaddr & 0xffff; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opLEA_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].l = cpu_state.eaaddr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + return 0; +} + + + +static int opXLAT_a16(uint32_t fetchdat) +{ + uint32_t addr = (BX + AL)&0xFFFF; + 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); + return 0; +} +static int opXLAT_a32(uint32_t fetchdat) +{ + uint32_t addr = EBX + AL; + 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); + return 0; +} + +static int opMOV_b_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_rm, getr8(cpu_reg)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteab(getr8(cpu_reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 0); + } + return cpu_state.abrt; +} +static int opMOV_b_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_rm, getr8(cpu_reg)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteab(getr8(cpu_reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 1); + } + return cpu_state.abrt; +} +static int opMOV_w_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].w = cpu_state.regs[cpu_reg].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(cpu_state.regs[cpu_reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 0); + } + return cpu_state.abrt; +} +static int opMOV_w_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].w = cpu_state.regs[cpu_reg].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(cpu_state.regs[cpu_reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 1); + } + return cpu_state.abrt; +} +static int opMOV_l_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.regs[cpu_reg].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(cpu_state.regs[cpu_reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,0,1, 0); + } + return cpu_state.abrt; +} +static int opMOV_l_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.regs[cpu_reg].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(cpu_state.regs[cpu_reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,0,1, 1); + } + return cpu_state.abrt; +} + +static int opMOV_r_b_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_reg, getr8(cpu_rm)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + 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); + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 0); + } + return 0; +} +static int opMOV_r_b_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_reg, getr8(cpu_rm)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + 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); + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 1); + } + return 0; +} +static int opMOV_r_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + 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; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 0); + } + return 0; +} +static int opMOV_r_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + 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; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 1); + } + return 0; +} +static int opMOV_r_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + 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; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0,1,0,0, 0); + } + return 0; +} +static int opMOV_r_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + 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; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0,1,0,0, 1); + } + return 0; +} + +#define opCMOV(condition) \ + static int opCMOV ## condition ## _w_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; \ + 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; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _w_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; \ + 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; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; \ + 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; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; \ + else \ + { \ + 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; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } + +opCMOV(O) +opCMOV(NO) +opCMOV(B) +opCMOV(NB) +opCMOV(E) +opCMOV(NE) +opCMOV(BE) +opCMOV(NBE) +opCMOV(S) +opCMOV(NS) +opCMOV(P) +opCMOV(NP) +opCMOV(L) +opCMOV(NL) +opCMOV(LE) +opCMOV(NLE) diff --git a/src/cpu_new/x86_ops_mov_ctrl.h b/src/cpu_new/x86_ops_mov_ctrl.h new file mode 100644 index 000000000..06a89884b --- /dev/null +++ b/src/cpu_new/x86_ops_mov_ctrl.h @@ -0,0 +1,290 @@ +static int opMOV_r_CRx_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + switch (cpu_reg) + { + case 0: + cpu_state.regs[cpu_rm].l = cr0; + if (is486) + cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[cpu_rm].l = cr2; + break; + case 3: + cpu_state.regs[cpu_rm].l = cr3; + break; + case 4: + if (cpu_has_feature(CPU_FEATURE_CR4)) + { + cpu_state.regs[cpu_rm].l = cr4; + break; + } + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_r_CRx_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + switch (cpu_reg) + { + case 0: + cpu_state.regs[cpu_rm].l = cr0; + if (is486) + cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[cpu_rm].l = cr2; + break; + case 3: + cpu_state.regs[cpu_rm].l = cr3; + break; + case 4: + if (cpu_has_feature(CPU_FEATURE_CR4)) + { + cpu_state.regs[cpu_rm].l = cr4; + break; + } + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_r_DRx_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[cpu_rm].l = dr[cpu_reg]; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_r_DRx_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[cpu_rm].l = dr[cpu_reg]; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_CRx_r_a16(uint32_t fetchdat) +{ + uint32_t old_cr0 = cr0; + + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + fetch_ea_16(fetchdat); + switch (cpu_reg) + { + case 0: + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[cpu_rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + if (is486 && !(cr0 & (1 << 30))) + cpu_cache_int_enabled = 1; + else if (isibmcpu) + cpu_cache_int_enabled = 1; + else + 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; + break; + case 3: + cr3 = cpu_state.regs[cpu_rm].l; + flushmmucache(); + break; + case 4: + if (cpu_has_feature(CPU_FEATURE_CR4)) + { + cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; + break; + } + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_CRx_r_a32(uint32_t fetchdat) +{ + uint32_t old_cr0 = cr0; + + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + fetch_ea_32(fetchdat); + switch (cpu_reg) + { + case 0: + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[cpu_rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + if (is486 && !(cr0 & (1 << 30))) + cpu_cache_int_enabled = 1; + else + 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; + break; + case 3: + cr3 = cpu_state.regs[cpu_rm].l; + flushmmucache(); + break; + case 4: + if (cpu_has_feature(CPU_FEATURE_CR4)) + { + cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; + break; + } + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_DRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[cpu_reg] = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_DRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[cpu_reg] = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_r_TRx_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[cpu_rm].l = 0; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_r_TRx_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[cpu_rm].l = 0; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_TRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_TRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + diff --git a/src/cpu_new/x86_ops_mov_seg.h b/src/cpu_new/x86_ops_mov_seg.h new file mode 100644 index 000000000..da7727143 --- /dev/null +++ b/src/cpu_new/x86_ops_mov_seg.h @@ -0,0 +1,434 @@ +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*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return cpu_state.abrt; +} +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*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return cpu_state.abrt; +} + +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*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return cpu_state.abrt; +} +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*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return cpu_state.abrt; +} + +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, &cpu_state.seg_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &cpu_state.seg_ds); + break; + case 0x10: /*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 = &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, &cpu_state.seg_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &cpu_state.seg_gs); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return cpu_state.abrt; +} +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, &cpu_state.seg_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &cpu_state.seg_ds); + break; + case 0x10: /*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 = &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, &cpu_state.seg_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &cpu_state.seg_gs); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return cpu_state.abrt; +} + + +static int opLDS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + 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, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); + return 0; +} +static int opLDS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + 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, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); + return 0; +} +static int opLDS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + 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, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 0); + return 0; +} +static int opLDS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + 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, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 1); + return 0; +} + +static int opLSS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + 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, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); + return 1; +} +static int opLSS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + 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, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); + return 1; +} +static int opLSS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + 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, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); + return 1; +} +static int opLSS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + 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, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); + return 1; +} + +#define opLsel(name, sel) \ + static int opL ## name ## _w_a16(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; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); \ + return 0; \ + } \ + \ + static int opL ## name ## _w_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; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a16(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + 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; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 0); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a32(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + 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; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 1); \ + return 0; \ + } + +opLsel(ES, cpu_state.seg_es) +opLsel(FS, cpu_state.seg_fs) +opLsel(GS, cpu_state.seg_gs) diff --git a/src/cpu_new/x86_ops_movx.h b/src/cpu_new/x86_ops_movx.h new file mode 100644 index 000000000..2e4fa2001 --- /dev/null +++ b/src/cpu_new/x86_ops_movx.h @@ -0,0 +1,209 @@ +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; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +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; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +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; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +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; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +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; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +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; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +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; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +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; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} + +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) + cpu_state.regs[cpu_reg].w |= 0xff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +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) + cpu_state.regs[cpu_reg].w |= 0xff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +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) + cpu_state.regs[cpu_reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +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) + cpu_state.regs[cpu_reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +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) + cpu_state.regs[cpu_reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +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) + cpu_state.regs[cpu_reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} diff --git a/src/cpu_new/x86_ops_msr.h b/src/cpu_new/x86_ops_msr.h new file mode 100644 index 000000000..2a8bdcf4c --- /dev/null +++ b/src/cpu_new/x86_ops_msr.h @@ -0,0 +1,30 @@ +static int opRDTSC(uint32_t fetchdat) +{ + if (!cpu_has_feature(CPU_FEATURE_RDTSC)) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + if ((cr4 & CR4_TSD) && CPL) + { + x86gpf("RDTSC when TSD set and CPL != 0", 0); + return 1; + } + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + CLOCK_CYCLES(1); + return 0; +} + +static int opRDPMC(uint32_t fetchdat) +{ + if (ECX > 1 || (!(cr4 & CR4_PCE) && (cr0 & 1) && CPL)) + { + x86gpf("RDPMC not allowed", 0); + return 1; + } + EAX = EDX = 0; + CLOCK_CYCLES(1); + return 0; +} diff --git a/src/cpu_new/x86_ops_mul.h b/src/cpu_new/x86_ops_mul.h new file mode 100644 index 000000000..f3e10e5a0 --- /dev/null +++ b/src/cpu_new/x86_ops_mul.h @@ -0,0 +1,264 @@ +static int opIMUL_w_iw_a16(uint32_t fetchdat) +{ + int32_t templ; + 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) 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); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 4, rmdat, 1,0,0,0, 0); + return 0; +} +static int opIMUL_w_iw_a32(uint32_t fetchdat) +{ + int32_t templ; + 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) 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); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 4, rmdat, 1,0,0,0, 1); + return 0; +} + +static int opIMUL_l_il_a16(uint32_t fetchdat) +{ + int64_t temp64; + 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) 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); + PREFETCH_RUN(25, 6, rmdat, 0,1,0,0, 0); + return 0; +} +static int opIMUL_l_il_a32(uint32_t fetchdat) +{ + int64_t temp64; + 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) 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); + PREFETCH_RUN(25, 6, rmdat, 0,1,0,0, 1); + return 0; +} + +static int opIMUL_w_ib_a16(uint32_t fetchdat) +{ + int32_t templ; + 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) 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); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 3, rmdat, 1,0,0,0, 0); + return 0; +} +static int opIMUL_w_ib_a32(uint32_t fetchdat) +{ + int32_t templ; + 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) 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); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 3, rmdat, 1,0,0,0, 1); + return 0; +} + +static int opIMUL_l_ib_a16(uint32_t fetchdat) +{ + int64_t temp64; + 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) 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); + PREFETCH_RUN(20, 3, rmdat, 0,1,0,0, 0); + return 0; +} +static int opIMUL_l_ib_a32(uint32_t fetchdat) +{ + int64_t temp64; + 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) 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); + PREFETCH_RUN(20, 3, rmdat, 0,1,0,0, 1); + return 0; +} + + + +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) 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); + return 0; +} +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) 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); + return 0; +} + +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) 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); + return 0; +} +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) 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); + return 0; +} + diff --git a/src/cpu_new/x86_ops_pmode.h b/src/cpu_new/x86_ops_pmode.h new file mode 100644 index 000000000..7fe5d4938 --- /dev/null +++ b/src/cpu_new/x86_ops_pmode.h @@ -0,0 +1,456 @@ +static int opARPL_a16(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp_seg = geteaw(); if (cpu_state.abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[cpu_reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); + seteaw(temp_seg); if (cpu_state.abrt) return 1; + cpu_state.flags |= Z_FLAG; + } + else + cpu_state.flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 0); + return 0; +} +static int opARPL_a32(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp_seg = geteaw(); if (cpu_state.abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[cpu_reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); + seteaw(temp_seg); if (cpu_state.abrt) return 1; + cpu_state.flags |= Z_FLAG; + } + else + cpu_state.flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 1); + return 0; +} + +#define opLAR(name, fetch_ea, is32, ea32) \ + static int opLAR_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc = 0; \ + \ + 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)) { cpu_state.flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (cpu_state.abrt) return 1; \ + } \ + cpu_state.flags &= ~Z_FLAG; \ + if ((desc & 0x1f00) == 0x000) valid = 0; \ + if ((desc & 0x1f00) == 0x800) valid = 0; \ + if ((desc & 0x1f00) == 0xa00) valid = 0; \ + if ((desc & 0x1f00) == 0xd00) valid = 0; \ + if ((desc & 0x1c00) < 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int dpl = (desc >> 13) & 3; \ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + 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; \ + else \ + cpu_state.regs[cpu_reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xff00; \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(11); \ + PREFETCH_RUN(11, 2, rmdat, 2,0,0,0, ea32); \ + return cpu_state.abrt; \ + } + +opLAR(w_a16, fetch_ea_16, 0, 0) +opLAR(w_a32, fetch_ea_32, 0, 1) +opLAR(l_a16, fetch_ea_16, 1, 0) +opLAR(l_a32, fetch_ea_32, 1, 1) + +#define opLSL(name, fetch_ea, is32, ea32) \ + static int opLSL_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc = 0; \ + \ + 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(); \ + cpu_state.flags &= ~Z_FLAG; \ + if (!(sel & 0xfffc)) return 0; /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (cpu_state.abrt) return 1; \ + } \ + if ((desc & 0x1400) == 0x400) valid = 0; /*Interrupt or trap or call gate*/ \ + if ((desc & 0x1f00) == 0x000) valid = 0; /*Invalid*/ \ + if ((desc & 0x1f00) == 0xa00) valid = 0; /*Invalid*/ \ + if ((desc & 0x1c00) != 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int rpl = (desc >> 13) & 3; \ + if (rpl < CPL || rpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + cpu_state.flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + { \ + cpu_state.regs[cpu_reg].l = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpu_state.regs[cpu_reg].l |= (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0xF) << 16; \ + if (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0x80) \ + { \ + cpu_state.regs[cpu_reg].l <<= 12; \ + cpu_state.regs[cpu_reg].l |= 0xFFF; \ + } \ + } \ + else \ + cpu_state.regs[cpu_reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(10); \ + PREFETCH_RUN(10, 2, rmdat, 4,0,0,0, ea32); \ + return cpu_state.abrt; \ + } + +opLSL(w_a16, fetch_ea_16, 0, 0) +opLSL(w_a32, fetch_ea_32, 0, 1) +opLSL(l_a16, fetch_ea_16, 1, 0) +opLSL(l_a32, fetch_ea_32, 1, 1) + + +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; + + 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 || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + 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); + granularity = readmemb(0, addr + 6) & 0x80; + if (cpu_state.abrt) return 1; + ldt.limit = limit; + ldt.access = access; + if (granularity) + { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base = base; + ldt.seg = sel; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32); + break; + case 0x18: /*LTR*/ + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + 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); + 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.access = access; + if (granularity) + { + tr.limit <<= 12; + tr.limit |= 0xFFF; + } + tr.base = base; + CLOCK_CYCLES(20); + 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(); + cpu_state.flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (cpu_state.abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + if ((desc & 0xC00) != 0xC00) /*Exclude conforming code segments*/ + { + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + } + if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/ + if (valid) 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(); + cpu_state.flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (cpu_state.abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + if (desc & 0x0800) valid = 0; /*Code*/ + if (!(desc & 0x0200)) valid = 0; /*Read-only data*/ + if (valid) cpu_state.flags |= Z_FLAG; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32); + break; + + default: + cpu_state.pc -= 3; + x86illegal(); + break; + } + return cpu_state.abrt; +} + +static int op0F00_a16(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_16(fetchdat); + + return op0F00_common(fetchdat, 0); +} +static int op0F00_a32(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_32(fetchdat); + + return op0F00_common(fetchdat, 1); +} + +static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) +{ + uint32_t base; + uint16_t limit, tempw; + 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) + base |= 0xff000000; + writememl(easeg, cpu_state.eaaddr + 2, base); + CLOCK_CYCLES(7); + 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) + base |= 0xff000000; + writememl(easeg, cpu_state.eaaddr + 2, base); + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32); + break; + case 0x10: /*LGDT*/ + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + x86gpf(NULL,0); + break; + } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + limit = geteaw(); + base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + gdt.limit = limit; + gdt.base = base; + if (!is32) gdt.base &= 0xffffff; + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 2, rmdat, 1,1,0,0, ea32); + break; + case 0x18: /*LIDT*/ + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + x86gpf(NULL,0); + break; + } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + limit = geteaw(); + base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + idt.limit = limit; + idt.base = base; + if (!is32) idt.base &= 0xffffff; + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 2, rmdat, 1,1,0,0, 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); + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); + break; + case 0x30: /*LMSW*/ + if ((CPL || cpu_state.eflags&VM_FLAG) && (msw&1)) + { + 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 &= ~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 || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + 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); + break; + } + + default: + cpu_state.pc -= 3; + x86illegal(); + break; + } + return cpu_state.abrt; +} + +static int op0F01_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 0, 0); +} +static int op0F01_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 0, 0, 1); +} +static int op0F01_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 1, 0, 0); +} +static int op0F01_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 1, 0, 1); +} + +static int op0F01_286(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 1, 0); +} diff --git a/src/cpu_new/x86_ops_prefix.h b/src/cpu_new/x86_ops_prefix.h new file mode 100644 index 000000000..8d191103d --- /dev/null +++ b/src/cpu_new/x86_ops_prefix.h @@ -0,0 +1,161 @@ +#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); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + 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) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + 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) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + 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) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + 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, 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*/ +{ + 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(); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_67(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(); + 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/cpu_new/x86_ops_rep.h b/src/cpu_new/x86_ops_rep.h new file mode 100644 index 000000000..efbb088ef --- /dev/null +++ b/src/cpu_new/x86_ops_rep.h @@ -0,0 +1,713 @@ +#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); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + 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); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 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); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 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); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + 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); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + 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); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + 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_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + 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_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + 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_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + 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) \ + { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + 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) \ + { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + 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) \ + { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + 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); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + 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); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + 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); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + 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)) \ + { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + 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)) \ + { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + 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)) \ + { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + 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) +{ + 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) +{ + 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/cpu_new/x86_ops_ret.h b/src/cpu_new/x86_ops_ret.h new file mode 100644 index 000000000..133c6153b --- /dev/null +++ b/src/cpu_new/x86_ops_ret.h @@ -0,0 +1,256 @@ +#define RETF_a16(stack_offset) \ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) \ + { \ + pmoderetf(0, stack_offset); \ + return 1; \ + } \ + if (stack32) \ + { \ + cpu_state.pc = readmemw(ss, ESP); \ + loadcs(readmemw(ss, ESP + 2)); \ + } \ + else \ + { \ + cpu_state.pc = readmemw(ss, SP); \ + loadcs(readmemw(ss, SP + 2)); \ + } \ + if (cpu_state.abrt) return 1; \ + if (stack32) ESP += 4 + stack_offset; \ + else SP += 4 + stack_offset; \ + cycles -= timing_retf_rm; + +#define RETF_a32(stack_offset) \ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) \ + { \ + pmoderetf(1, stack_offset); \ + return 1; \ + } \ + if (stack32) \ + { \ + cpu_state.pc = readmeml(ss, ESP); \ + loadcs(readmeml(ss, ESP + 4) & 0xffff); \ + } \ + else \ + { \ + cpu_state.pc = readmeml(ss, SP); \ + loadcs(readmeml(ss, SP + 4) & 0xffff); \ + } \ + if (cpu_state.abrt) return 1; \ + if (stack32) ESP += 8 + stack_offset; \ + else SP += 8 + stack_offset; \ + cycles -= timing_retf_rm; + +static int opRETF_a16(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a16(0); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRETF_a32(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a32(0); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,2,0,0, 1); + PREFETCH_FLUSH(); + return 0; +} + +static int opRETF_a16_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a16(offset); + + PREFETCH_RUN(cycles_old-cycles, 3, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRETF_a32_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a32(offset); + + PREFETCH_RUN(cycles_old-cycles, 3, -1, 0,2,0,0, 1); + PREFETCH_FLUSH(); + return 0; +} + +static int opIRET_286(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + 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; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 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)); + cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + +static int opIRET(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + if (cr4 & CR4_VME) + { + 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 + { + x86gpf(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; + } + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + +static int opIRETD(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw & 1) + { + optype = IRET; + pmodeiret(1); + optype = 0; + } + else + { + uint16_t new_cs; + if (stack32) + { + cpu_state.pc = readmeml(ss, ESP); + new_cs = readmemw(ss, ESP + 4); + 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)); + cpu_state.flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2; + cpu_state.eflags = readmemw(ss, (SP + 10) & 0xffff); + SP += 12; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,2,0,0, 1); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + diff --git a/src/cpu_new/x86_ops_set.h b/src/cpu_new/x86_ops_set.h new file mode 100644 index 000000000..f6fd50e69 --- /dev/null +++ b/src/cpu_new/x86_ops_set.h @@ -0,0 +1,37 @@ +#define opSET(condition) \ + 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; \ + } \ + \ + 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; \ + } + +opSET(O) +opSET(NO) +opSET(B) +opSET(NB) +opSET(E) +opSET(NE) +opSET(BE) +opSET(NBE) +opSET(S) +opSET(NS) +opSET(P) +opSET(NP) +opSET(L) +opSET(NL) +opSET(LE) +opSET(NLE) diff --git a/src/cpu_new/x86_ops_shift.h b/src/cpu_new/x86_ops_shift.h new file mode 100644 index 000000000..106a5701a --- /dev/null +++ b/src/cpu_new/x86_ops_shift.h @@ -0,0 +1,607 @@ +#define OP_SHIFT_b(c, ea32) \ + { \ + uint8_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL b, c*/ \ + 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*/ \ + 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 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + 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 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + 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; \ + case 0x20: case 0x30: /*SHL b,CL*/ \ + seteab(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL8, temp_orig, c, (temp << c) & 0xff); \ + 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 0x28: /*SHR b,CL*/ \ + seteab(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR8, temp_orig, c, temp >> c); \ + 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 0x38: /*SAR b,CL*/ \ + temp = (int8_t)temp >> c; \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR8, temp_orig, c, 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; \ + } \ + } + +#define OP_SHIFT_w(c, ea32) \ + { \ + uint16_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL w, c*/ \ + 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,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 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x8000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + 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 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x8000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + 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; \ + case 0x20: case 0x30: /*SHL w, c*/ \ + seteaw(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL16, temp_orig, c, (temp << c) & 0xffff); \ + 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 0x28: /*SHR w, c*/ \ + seteaw(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR16, temp_orig, c, temp >> c); \ + 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 0x38: /*SAR w, c*/ \ + temp = (int16_t)temp >> c; \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR16, temp_orig, c, 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; \ + } \ + } + +#define OP_SHIFT_l(c, ea32) \ + { \ + uint32_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL l, c*/ \ + 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,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(); \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80000000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + 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 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80000000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + 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; \ + case 0x20: case 0x30: /*SHL l, c*/ \ + seteal(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL32, temp_orig, c, temp << c); \ + 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); \ + break; \ + case 0x28: /*SHR l, c*/ \ + seteal(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR32, temp_orig, c, temp >> c); \ + 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); \ + break; \ + case 0x38: /*SAR l, c*/ \ + temp = (int32_t)temp >> c; \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR32, temp_orig, c, temp); \ + 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); \ + break; \ + } \ + } + +static int opC0_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + 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; + OP_SHIFT_b(c, 0); + return 0; +} +static int opC0_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + 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; + OP_SHIFT_b(c, 1); + return 0; +} +static int opC1_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + 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; + OP_SHIFT_w(c, 0); + return 0; +} +static int opC1_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + 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; + OP_SHIFT_w(c, 1); + return 0; +} +static int opC1_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + 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; + OP_SHIFT_l(c, 0); + return 0; +} +static int opC1_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + 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; + OP_SHIFT_l(c, 1); + return 0; +} + +static int opD0_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2 = 0; + + 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; +} +static int opD0_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2 = 0; + + 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; +} +static int opD1_w_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2 = 0; + + 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; +} +static int opD1_w_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2 = 0; + + 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; +} +static int opD1_l_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2 = 0; + + 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; +} +static int opD1_l_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2 = 0; + + 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; +} + +static int opD2_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + 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); + return 0; +} +static int opD2_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + 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); + return 0; +} +static int opD3_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + 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); + return 0; +} +static int opD3_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + 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); + return 0; +} +static int opD3_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + 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); + return 0; +} +static int opD3_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + 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); + return 0; +} + + +#define SHLD_w() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ; \ + uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \ + templ = (tempw << 16) | cpu_state.regs[cpu_reg].w; \ + if (count <= 16) tempw = templ >> (16 - count); \ + else tempw = (templ << count) >> 16; \ + seteaw(tempw); if (cpu_state.abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + } + +#define SHLD_l() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ + tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \ + templ = (templ << count) | (cpu_state.regs[cpu_reg].l >> (32 - count)); \ + seteal(templ); if (cpu_state.abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + } + + +#define SHRD_w() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ; \ + uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = (tempw >> (count - 1)) & 1; \ + templ = tempw | (cpu_state.regs[cpu_reg].w << 16); \ + tempw = templ >> count; \ + seteaw(tempw); if (cpu_state.abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + } + +#define SHRD_l() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ + tempc = (templ >> (count - 1)) & 1; \ + templ = (templ >> count) | (cpu_state.regs[cpu_reg].l << (32 - count)); \ + seteal(templ); if (cpu_state.abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + } + +#define opSHxD(operation) \ + static int op ## operation ## _i_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + count = getbyte() & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ + return 0; \ + } \ + static int op ## operation ## _CL_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + count = CL & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ + return 0; \ + } \ + static int op ## operation ## _i_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(); \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ + return 0; \ + } \ + static int op ## operation ## _CL_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(); \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ + return 0; \ + } + +opSHxD(SHLD_w) +opSHxD(SHLD_l) +opSHxD(SHRD_w) +opSHxD(SHRD_l) diff --git a/src/cpu_new/x86_ops_stack.h b/src/cpu_new/x86_ops_stack.h new file mode 100644 index 000000000..9ca1171a0 --- /dev/null +++ b/src/cpu_new/x86_ops_stack.h @@ -0,0 +1,525 @@ +#define PUSH_W_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_W(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + PREFETCH_RUN(2, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } + +#define PUSH_L_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_L(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + PREFETCH_RUN(2, 1, -1, 0,0,0,1, 0); \ + return cpu_state.abrt; \ + } + +#define POP_W_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_W(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + PREFETCH_RUN(4, 1, -1, 1,0,0,0, 0); \ + return cpu_state.abrt; \ + } + +#define POP_L_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_L(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + PREFETCH_RUN(4, 1, -1, 0,1,0,0, 0); \ + return cpu_state.abrt; \ + } + +PUSH_W_OP(AX) +PUSH_W_OP(BX) +PUSH_W_OP(CX) +PUSH_W_OP(DX) +PUSH_W_OP(SI) +PUSH_W_OP(DI) +PUSH_W_OP(BP) +PUSH_W_OP(SP) + +PUSH_L_OP(EAX) +PUSH_L_OP(EBX) +PUSH_L_OP(ECX) +PUSH_L_OP(EDX) +PUSH_L_OP(ESI) +PUSH_L_OP(EDI) +PUSH_L_OP(EBP) +PUSH_L_OP(ESP) + +POP_W_OP(AX) +POP_W_OP(BX) +POP_W_OP(CX) +POP_W_OP(DX) +POP_W_OP(SI) +POP_W_OP(DI) +POP_W_OP(BP) +POP_W_OP(SP) + +POP_L_OP(EAX) +POP_L_OP(EBX) +POP_L_OP(ECX) +POP_L_OP(EDX) +POP_L_OP(ESI) +POP_L_OP(EDI) +POP_L_OP(EBP) +POP_L_OP(ESP) + + +static int opPUSHA_w(uint32_t fetchdat) +{ + if (stack32) + { + writememw(ss, ESP - 2, AX); + writememw(ss, ESP - 4, CX); + writememw(ss, ESP - 6, DX); + writememw(ss, ESP - 8, BX); + writememw(ss, ESP - 10, SP); + writememw(ss, ESP - 12, BP); + writememw(ss, ESP - 14, SI); + writememw(ss, ESP - 16, DI); + if (!cpu_state.abrt) ESP -= 16; + } + else + { + writememw(ss, ((SP - 2) & 0xFFFF), AX); + writememw(ss, ((SP - 4) & 0xFFFF), CX); + writememw(ss, ((SP - 6) & 0xFFFF), DX); + writememw(ss, ((SP - 8) & 0xFFFF), BX); + writememw(ss, ((SP - 10) & 0xFFFF), SP); + writememw(ss, ((SP - 12) & 0xFFFF), BP); + writememw(ss, ((SP - 14) & 0xFFFF), SI); + writememw(ss, ((SP - 16) & 0xFFFF), DI); + if (!cpu_state.abrt) SP -= 16; + } + CLOCK_CYCLES((is486) ? 11 : 18); + PREFETCH_RUN(18, 1, -1, 0,0,8,0, 0); + return cpu_state.abrt; +} +static int opPUSHA_l(uint32_t fetchdat) +{ + if (stack32) + { + writememl(ss, ESP - 4, EAX); + writememl(ss, ESP - 8, ECX); + writememl(ss, ESP - 12, EDX); + writememl(ss, ESP - 16, EBX); + writememl(ss, ESP - 20, ESP); + writememl(ss, ESP - 24, EBP); + writememl(ss, ESP - 28, ESI); + writememl(ss, ESP - 32, EDI); + if (!cpu_state.abrt) ESP -= 32; + } + else + { + writememl(ss, ((SP - 4) & 0xFFFF), EAX); + writememl(ss, ((SP - 8) & 0xFFFF), ECX); + writememl(ss, ((SP - 12) & 0xFFFF), EDX); + writememl(ss, ((SP - 16) & 0xFFFF), EBX); + writememl(ss, ((SP - 20) & 0xFFFF), ESP); + writememl(ss, ((SP - 24) & 0xFFFF), EBP); + writememl(ss, ((SP - 28) & 0xFFFF), ESI); + writememl(ss, ((SP - 32) & 0xFFFF), EDI); + if (!cpu_state.abrt) SP -= 32; + } + CLOCK_CYCLES((is486) ? 11 : 18); + PREFETCH_RUN(18, 1, -1, 0,0,0,8, 0); + return cpu_state.abrt; +} + +static int opPOPA_w(uint32_t fetchdat) +{ + if (stack32) + { + DI = readmemw(ss, ESP); if (cpu_state.abrt) return 1; + SI = readmemw(ss, ESP + 2); if (cpu_state.abrt) return 1; + BP = readmemw(ss, ESP + 4); if (cpu_state.abrt) return 1; + BX = readmemw(ss, ESP + 8); if (cpu_state.abrt) return 1; + DX = readmemw(ss, ESP + 10); if (cpu_state.abrt) return 1; + CX = readmemw(ss, ESP + 12); if (cpu_state.abrt) return 1; + AX = readmemw(ss, ESP + 14); if (cpu_state.abrt) return 1; + ESP += 16; + } + else + { + DI = readmemw(ss, ((SP) & 0xFFFF)); if (cpu_state.abrt) return 1; + SI = readmemw(ss, ((SP + 2) & 0xFFFF)); if (cpu_state.abrt) return 1; + BP = readmemw(ss, ((SP + 4) & 0xFFFF)); if (cpu_state.abrt) return 1; + BX = readmemw(ss, ((SP + 8) & 0xFFFF)); if (cpu_state.abrt) return 1; + DX = readmemw(ss, ((SP + 10) & 0xFFFF)); if (cpu_state.abrt) return 1; + CX = readmemw(ss, ((SP + 12) & 0xFFFF)); if (cpu_state.abrt) return 1; + AX = readmemw(ss, ((SP + 14) & 0xFFFF)); if (cpu_state.abrt) return 1; + SP += 16; + } + CLOCK_CYCLES((is486) ? 9 : 24); + PREFETCH_RUN(24, 1, -1, 7,0,0,0, 0); + return 0; +} +static int opPOPA_l(uint32_t fetchdat) +{ + if (stack32) + { + EDI = readmeml(ss, ESP); if (cpu_state.abrt) return 1; + ESI = readmeml(ss, ESP + 4); if (cpu_state.abrt) return 1; + EBP = readmeml(ss, ESP + 8); if (cpu_state.abrt) return 1; + EBX = readmeml(ss, ESP + 16); if (cpu_state.abrt) return 1; + EDX = readmeml(ss, ESP + 20); if (cpu_state.abrt) return 1; + ECX = readmeml(ss, ESP + 24); if (cpu_state.abrt) return 1; + EAX = readmeml(ss, ESP + 28); if (cpu_state.abrt) return 1; + ESP += 32; + } + else + { + EDI = readmeml(ss, ((SP) & 0xFFFF)); if (cpu_state.abrt) return 1; + ESI = readmeml(ss, ((SP + 4) & 0xFFFF)); if (cpu_state.abrt) return 1; + EBP = readmeml(ss, ((SP + 8) & 0xFFFF)); if (cpu_state.abrt) return 1; + EBX = readmeml(ss, ((SP + 16) & 0xFFFF)); if (cpu_state.abrt) return 1; + EDX = readmeml(ss, ((SP + 20) & 0xFFFF)); if (cpu_state.abrt) return 1; + ECX = readmeml(ss, ((SP + 24) & 0xFFFF)); if (cpu_state.abrt) return 1; + EAX = readmeml(ss, ((SP + 28) & 0xFFFF)); if (cpu_state.abrt) return 1; + SP += 32; + } + CLOCK_CYCLES((is486) ? 9 : 24); + PREFETCH_RUN(24, 1, -1, 0,7,0,0, 0); + return 0; +} + +static int opPUSH_imm_w(uint32_t fetchdat) +{ + uint16_t val = getwordf(); + PUSH_W(val); + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opPUSH_imm_l(uint32_t fetchdat) +{ + uint32_t val = getlong(); if (cpu_state.abrt) return 1; + PUSH_L(val); + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} + +static int opPUSH_imm_bw(uint32_t fetchdat) +{ + uint16_t tempw = getbytef(); + + if (tempw & 0x80) tempw |= 0xFF00; + PUSH_W(tempw); + + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 2, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opPUSH_imm_bl(uint32_t fetchdat) +{ + uint32_t templ = getbytef(); + + if (templ & 0x80) templ |= 0xFFFFFF00; + PUSH_L(templ); + + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 2, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} + +static int opPOPW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + 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) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 1,0,(cpu_mod == 3) ? 0:1,0, 0); + return cpu_state.abrt; +} +static int opPOPW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + 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) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 1,0,(cpu_mod == 3) ? 0:1,0, 1); + return cpu_state.abrt; +} + +static int opPOPL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + 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) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 0,1,0,(cpu_mod == 3) ? 0:1, 0); + return cpu_state.abrt; +} +static int opPOPL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + 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) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 0,1,0,(cpu_mod == 3) ? 0:1, 1); + return cpu_state.abrt; +} + + +static int opENTER_w(uint32_t fetchdat) +{ + uint16_t offset; + int count; + uint32_t tempEBP, tempESP, frame_ptr; + int reads = 0, writes = 1, instr_cycles = 0; + uint16_t tempw; + + offset = getwordf(); + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + tempEBP = EBP; + tempESP = ESP; + + PUSH_W(BP); if (cpu_state.abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + BP -= 2; + tempw = readmemw(ss, BP); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_W(tempw); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + reads++; writes++; instr_cycles += (is486) ? 3 : 4; + } + PUSH_W(frame_ptr); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + writes++; instr_cycles += (is486) ? 3 : 5; + } + BP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + instr_cycles += (is486) ? 14 : 10; + PREFETCH_RUN(instr_cycles, 3, -1, reads,0,writes,0, 0); + return 0; +} +static int opENTER_l(uint32_t fetchdat) +{ + uint16_t offset; + int count; + uint32_t tempEBP, tempESP, frame_ptr; + int reads = 0, writes = 1, instr_cycles = 0; + uint32_t templ; + + offset = getwordf(); + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + tempEBP = EBP; tempESP = ESP; + + PUSH_L(EBP); if (cpu_state.abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + EBP -= 4; + templ = readmeml(ss, EBP); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_L(templ); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + reads++; writes++; instr_cycles += (is486) ? 3 : 4; + } + PUSH_L(frame_ptr); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + writes++; instr_cycles += (is486) ? 3 : 5; + } + EBP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + instr_cycles += (is486) ? 14 : 10; + PREFETCH_RUN(instr_cycles, 3, -1, reads,0,writes,0, 0); + return 0; +} + + +static int opLEAVE_w(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint16_t temp; + + SP = BP; + temp = POP_W(); + if (cpu_state.abrt) { ESP = tempESP; return 1; } + BP = temp; + + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opLEAVE_l(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint32_t temp; + + ESP = EBP; + temp = POP_L(); + if (cpu_state.abrt) { ESP = tempESP; return 1; } + EBP = temp; + + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,1,0,0, 0); + return 0; +} + + +#define PUSH_SEG_OPS(seg) \ + static int opPUSH_ ## seg ## _w(uint32_t fetchdat) \ + { \ + PUSH_W(seg); \ + CLOCK_CYCLES(2); \ + PREFETCH_RUN(2, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } \ + static int opPUSH_ ## seg ## _l(uint32_t fetchdat) \ + { \ + PUSH_L(seg); \ + CLOCK_CYCLES(2); \ + PREFETCH_RUN(2, 1, -1, 0,0,0,1, 0); \ + return cpu_state.abrt; \ + } + +#define POP_SEG_OPS(seg, realseg) \ + static int opPOP_ ## seg ## _w(uint32_t fetchdat) \ + { \ + uint16_t temp_seg; \ + uint32_t temp_esp = ESP; \ + temp_seg = POP_W(); if (cpu_state.abrt) return 1; \ + loadseg(temp_seg, realseg); if (cpu_state.abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } \ + static int opPOP_ ## seg ## _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, realseg); if (cpu_state.abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } + + +PUSH_SEG_OPS(CS); +PUSH_SEG_OPS(DS); +PUSH_SEG_OPS(ES); +PUSH_SEG_OPS(FS); +PUSH_SEG_OPS(GS); +PUSH_SEG_OPS(SS); + +POP_SEG_OPS(DS, &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) +{ + uint16_t temp_seg; + uint32_t temp_esp = ESP; + temp_seg = POP_W(); if (cpu_state.abrt) 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 = &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; +} +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, &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 = &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; +} diff --git a/src/cpu_new/x86_ops_string.h b/src/cpu_new/x86_ops_string.h new file mode 100644 index 000000000..c02725138 --- /dev/null +++ b/src/cpu_new/x86_ops_string.h @@ -0,0 +1,597 @@ +static int opMOVSB_a16(uint32_t fetchdat) +{ + 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 (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; + + 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 (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; +} + +static int opMOVSW_a16(uint32_t fetchdat) +{ + 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 (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; + + 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 (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; +} + +static int opMOVSL_a16(uint32_t fetchdat) +{ + 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 (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; + + 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 (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; +} + + +static int opCMPSB_a16(uint32_t fetchdat) +{ + 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 (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, 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 (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; +} + +static int opCMPSW_a16(uint32_t fetchdat) +{ + 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 (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, 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 (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; +} + +static int opCMPSL_a16(uint32_t fetchdat) +{ + 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 (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, 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 (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; +} + +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 (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 (cpu_state.flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); + return 0; +} + +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 (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 (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; +} + +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 (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 (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; +} + + +static int opLODSB_a16(uint32_t fetchdat) +{ + 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 (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; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + AL = temp; + if (cpu_state.flags & D_FLAG) ESI--; + else ESI++; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opLODSW_a16(uint32_t fetchdat) +{ + 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 (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; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + AX = temp; + 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; +} + +static int opLODSL_a16(uint32_t fetchdat) +{ + 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 (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; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + EAX = temp; + 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; +} + + +static int opSCASB_a16(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemb(es, DI); if (cpu_state.abrt) return 1; + setsub8(AL, temp); + 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; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemb(es, EDI); if (cpu_state.abrt) return 1; + setsub8(AL, temp); + if (cpu_state.flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opSCASW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemw(es, DI); if (cpu_state.abrt) return 1; + setsub16(AX, temp); + 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; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemw(es, EDI); if (cpu_state.abrt) return 1; + setsub16(AX, temp); + 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; +} + +static int opSCASL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmeml(es, DI); if (cpu_state.abrt) return 1; + setsub32(EAX, temp); + 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; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmeml(es, EDI); if (cpu_state.abrt) return 1; + setsub32(EAX, temp); + 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; +} + +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 (cpu_state.flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); + return 0; +} +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 (cpu_state.flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); + return 0; +} + +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 (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; +} +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 (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; +} + +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 (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; +} +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 (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; +} + +static int opOUTSB_a16(uint32_t fetchdat) +{ + 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 (cpu_state.flags & D_FLAG) SI--; + else SI++; + outb(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opOUTSB_a32(uint32_t fetchdat) +{ + 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 (cpu_state.flags & D_FLAG) ESI--; + else ESI++; + outb(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opOUTSW_a16(uint32_t fetchdat) +{ + 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 (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); + return 0; +} +static int opOUTSW_a32(uint32_t fetchdat) +{ + 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 (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); + return 0; +} + +static int opOUTSL_a16(uint32_t fetchdat) +{ + 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 (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); + return 0; +} +static int opOUTSL_a32(uint32_t fetchdat) +{ + 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 (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); + return 0; +} diff --git a/src/cpu_new/x86_ops_xchg.h b/src/cpu_new/x86_ops_xchg.h new file mode 100644 index 000000000..6a787273e --- /dev/null +++ b/src/cpu_new/x86_ops_xchg.h @@ -0,0 +1,234 @@ +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); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +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); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + return 0; +} + +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; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +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; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + return 0; +} + +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; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + return 0; +} +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; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + return 0; +} + + +static int opXCHG_AX_BX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BX; + BX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_CX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = CX; + CX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_DX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DX; + DX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_SI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SI; + SI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_DI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DI; + DI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_BP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BP; + BP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_SP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SP; + SP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opXCHG_EAX_EBX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBX; + EBX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_ECX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ECX; + ECX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_EDX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDX; + EDX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_ESI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESI; + ESI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_EDI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDI; + EDI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_EBP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBP; + EBP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_ESP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESP; + ESP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + + +#define opBSWAP(reg) \ + static int opBSWAP_ ## reg(uint32_t fetchdat) \ + { \ + reg = (reg >> 24) | ((reg >> 8) & 0xff00) | ((reg << 8) & 0xff0000) | ((reg << 24) & 0xff000000); \ + CLOCK_CYCLES(1); \ + PREFETCH_RUN(1, 1, -1, 0,0,0,0, 0); \ + return 0; \ + } + +opBSWAP(EAX) +opBSWAP(EBX) +opBSWAP(ECX) +opBSWAP(EDX) +opBSWAP(ESI) +opBSWAP(EDI) +opBSWAP(EBP) +opBSWAP(ESP) diff --git a/src/cpu_new/x86seg.c b/src/cpu_new/x86seg.c new file mode 100644 index 000000000..2a438d862 --- /dev/null +++ b/src/cpu_new/x86seg.c @@ -0,0 +1,2577 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x86 CPU segment emulation. + * + * Version: @(#)x86seg.c 1.0.9 2018/11/14 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "../device.h" +#include "../timer.h" +#include "../machine/machine.h" +#include "../mem.h" +#include "../nvr.h" +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" + + +extern FILE *stdlog; /* file to log output to */ + + +/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ +#define CS_ACCESSED + +/*Controls whether the accessed bit in a descriptor is set when a data or stack + selector is loaded.*/ +#define SEL_ACCESSED +int stimes = 0; +int dtimes = 0; +int btimes = 0; + +uint32_t abrt_error; +int cgate16, cgate32; + +#define breaknullsegs 0 + +int intgatesize; + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); +void taskswitch386(uint16_t seg, uint16_t *segdat); + +void pmodeint(int num, int soft); +/*NOT PRESENT is INT 0B + GPF is INT 0D*/ + + +#ifdef ENABLE_X86SEG_LOG +int x86seg_do_log = ENABLE_X86SEG_LOG; + + +static void +x86seg_log(const char *fmt, ...) +{ + va_list ap; + + if (x86seg_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define x86seg_log(fmt, ...) +#endif + + +void x86abort(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + + nvr_save(); +#ifdef ENABLE_808X_LOG + dumpregs(1); +#endif + fflush(stdlog); + exit(-1); +} + +uint8_t opcode2; + +static void seg_reset(x86seg *s) +{ + s->access = (0 << 5) | 2 | 0x80; + s->limit = 0xFFFF; + s->limit_low = 0; + s->limit_high = 0xffff; + 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(&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) +{ + cpu_state.pc = cpu_state.oldpc; + cpu_state.seg_cs.access = (oldcpl << 5) | 0x80; + + if (msw & 1) + pmodeint(x86_abrt, 0); + else + { + uint32_t addr = (x86_abrt << 2) + idt.base; + 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)); + return; + } + + if (cpu_state.abrt || x86_was_reset) return; + + if (intgatesize == 16) + { + if (stack32) + { + writememw(ss, ESP-2, abrt_error); + ESP-=2; + } + else + { + writememw(ss, ((SP-2)&0xFFFF), abrt_error); + SP-=2; + } + } + else + { + if (stack32) + { + writememl(ss, ESP-4, abrt_error); + ESP-=4; + } + else + { + writememl(ss, ((SP-4)&0xFFFF), abrt_error); + SP-=4; + } + } +} +void x86gpf(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_GPF; + abrt_error = error; +} +void x86ss(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_SS; + abrt_error = error; +} +void x86ts(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_TS; + abrt_error = error; +} +void x86np(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_NP; + abrt_error = 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; + } +} + +void do_seg_load(x86seg *s, uint16_t *segdat) +{ + s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); + if (segdat[3] & 0x80) + s->limit = (s->limit << 12) | 0xFFF; + s->base = segdat[1] | ((segdat[2] & 0xFF) << 16); + if (is386) + s->base |= ((segdat[3] >> 8) << 24); + s->access = segdat[2] >> 8; + + if ((segdat[2] & 0x1800) != 0x1000 || !(segdat[2] & (1 << 10))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } + + if (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 | 0x80; + s->limit = 0xffff; + s->limit_low = 0; + s->limit_high = 0xffff; +} + +static void check_seg_valid(x86seg *s) +{ + int dpl = (s->access >> 5) & 3; + int valid = 1; + + if (s->seg & 4) + { + if ((s->seg & ~7) >= ldt.limit) + { + valid = 0; + } + } + else + { + if ((s->seg & ~7) >= gdt.limit) + { + valid = 0; + } + } + + switch (s->access & 0x1f) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ + if ((s->seg & 3) > dpl || (CPL) > dpl) + { + valid = 0; + break; + } + break; + + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + + default: + valid = 0; + break; + } + + if (!valid) + loadseg(0, s); +} + +int loadseg(uint16_t seg, x86seg *s) +{ + uint16_t segdat[4]; + uint32_t addr; + int dpl; + + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + if (s==&cpu_state.seg_ss) + { + x86ss(NULL,0); + return 1; + } + s->seg=0; + s->access = 0x80; + s->base=-1; + if (s == &cpu_state.seg_ds) + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + return 0; + } + addr=seg&~7; + if (seg&4) + { + if ((addr+7)>ldt.limit) + { + x86gpf("loadseg(): Bigger than LDT limit",seg&~3); + return 1; + } + addr+=ldt.base; + } + else + { + if ((addr+7)>gdt.limit) + { + x86gpf("loadseg(): Bigger than GDT limit",seg&~3); + return 1; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return 1; + dpl=(segdat[2]>>13)&3; + if (s==&cpu_state.seg_ss) + { + if (!(seg&~3)) + { + x86gpf(NULL,seg&~3); + return 1; + } + if ((seg&3)!=CPL || dpl!=CPL) + { + x86gpf(NULL,seg&~3); + return 1; + } + switch ((segdat[2]>>8)&0x1F) + { + case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ + break; + default: + x86gpf(NULL,seg&~3); + return 1; + } + if (!(segdat[2]&0x8000)) + { + x86ss(NULL,seg&~3); + return 1; + } + set_stack32((segdat[3] & 0x40) ? 1 : 0); + } + else if (s!=&cpu_state.seg_cs) + { + x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + x86seg_log("Seg type %03X\n",segdat[2]&0x1F00); + switch ((segdat[2]>>8)&0x1F) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ + if ((seg&3)>dpl || (CPL)>dpl) + { + x86gpf(NULL,seg&~3); + return 1; + } + break; + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + default: + x86gpf(NULL,seg&~3); + return 1; + } + } + + if (!(segdat[2] & 0x8000)) + { + x86np("Load data seg not present", seg & 0xfffc); + return 1; + } + s->seg = seg; + do_seg_load(s, segdat); + +#ifndef CS_ACCESSED + if (s != &_cs) + { +#endif +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif +#ifndef CS_ACCESSED + } +#endif + s->checked = 0; +#ifdef USE_DYNAREC + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; +#endif + } + else + { + s->access = (3 << 5) | 2 | 0x80; + s->base = seg << 4; + s->seg = seg; + s->checked = 1; +#ifdef USE_DYNAREC + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; +#endif + 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) +#define DPL2 ((segdat2[2]>>13)&3) +#define DPL3 ((segdat3[2]>>13)&3) + +void loadcs(uint16_t seg) +{ + uint16_t segdat[4]; + uint32_t addr; + x86seg_log("Load CS %04X\n",seg); + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf(NULL,seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf("loadcs(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcs(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS not present", seg & 0xfffc); + return; + } + set_use32(segdat[3] & 0x40); + CS=(seg&~3)|CPL; + 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; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS system seg not present\n", seg & 0xfffc); + return; + } + switch (segdat[2]&0xF00) + { + default: + x86gpf(NULL,seg&~3); + return; + } + } + } + else + { + 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 & 0xFFFF; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + } +} + +void loadcsjmp(uint16_t seg, uint32_t old_pc) +{ + uint16_t segdat[4]; + uint32_t addr; + uint16_t type,seg2; + uint32_t newpc; + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + x86seg_log("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf("loadcsjmp(): segment PL > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf("loadcsjmp(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcsjmp(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP not present\n", seg & 0xfffc); + return; + } + set_use32(segdat[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + cycles -= timing_jmp_pm; + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP system selector not present\n", seg & 0xfffc); + return; + } + type=segdat[2]&0xF00; + newpc=segdat[0]; + if (type&0x800) newpc|=segdat[3]<<16; + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: + cgate32=(type&0x800); + cgate16=!cgate32; + cpu_state.oldpc = cpu_state.pc; + if ((DPL < CPL) || (DPL < (seg&3))) + { + x86gpf(NULL,seg&~3); + return; + } + if (DPL < CPL) + { + x86gpf("loadcsjmp(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcsjmp(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + if (!(seg2&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + + if (DPL > CPL) + { + x86gpf("loadcsjmp(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP from call gate not present\n", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL > CPL) + { + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + CS=seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + break; + + default: + x86gpf(NULL,seg2&~3); + return; + } + cycles -= timing_jmp_pm_gate; + break; + + + case 0x100: /*286 Task gate*/ + case 0x900: /*386 Task gate*/ + cpu_state.pc = old_pc; + optype=JMP; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + cpu_state.flags &= ~NT_FLAG; + cpl_override=0; + return; + + default: + x86gpf(NULL,0); + return; + } + } + } + else + { + 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 (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + cycles -= timing_jmp_rm; + } +} + +void PUSHW(uint16_t v) +{ + if (stack32) + { + writememw(ss,ESP-2,v); + if (cpu_state.abrt) return; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),v); + if (cpu_state.abrt) return; + SP-=2; + } +} +void PUSHL(uint32_t v) +{ + if (stack32) + { + writememl(ss,ESP-4,v); + if (cpu_state.abrt) return; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),v); + if (cpu_state.abrt) return; + SP-=4; + } +} +uint16_t POPW() +{ + uint16_t tempw; + if (stack32) + { + tempw=readmemw(ss,ESP); + if (cpu_state.abrt) return 0; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); + if (cpu_state.abrt) return 0; + SP+=2; + } + return tempw; +} +uint32_t POPL() +{ + uint32_t templ; + if (stack32) + { + templ=readmeml(ss,ESP); + if (cpu_state.abrt) return 0; + ESP+=4; + } + else + { + templ=readmeml(ss,SP); + if (cpu_state.abrt) return 0; + SP+=4; + } + return templ; +} + +void loadcscall(uint16_t seg, uint32_t old_pc) +{ + uint16_t seg2; + uint16_t segdat[4],segdat2[4],newss; + uint32_t addr,oldssbase=ss, oaddr; + uint32_t newpc; + int count; + uint32_t oldss,oldsp,newsp, oldsp2; + int type; + uint16_t tempw; + + int csout = output; + + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) + { + if (csout) x86seg_log("Protected mode CS load! %04X\n",seg); + if (!(seg&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + type=segdat[2]&0xF00; + newpc=segdat[0]; + if (type&0x800) newpc|=segdat[3]<<16; + + if (csout) x86seg_log("Code seg call - %04X - %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2]); + if (segdat[2]&0x1000) + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf("loadcscall(): segment > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf(NULL,seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS call not present", seg & 0xfffc); + return; + } + set_use32(segdat[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + /*Conforming segments don't change CPL, so preserve existing CPL*/ + if (segdat[2]&0x400) + { + seg = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + } + else /*On non-conforming segments, set RPL = CPL*/ + seg = (seg & ~3) | CPL; + CS=seg; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + if (csout) x86seg_log("Complete\n"); + cycles -= timing_call_pm; + } + else + { + type=segdat[2]&0xF00; + if (csout) x86seg_log("Type %03X\n",type); + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: /*386 Call gate*/ + x86seg_log("Callgate %08X\n", cpu_state.pc); + cgate32=(type&0x800); + cgate16=!cgate32; + count=segdat[2]&31; + if (DPL < CPL) + { + x86gpf("loadcscall(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcscall(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86seg_log("Call gate not present %04X\n",seg); + x86np("Call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + x86seg_log("New address : %04X:%08X\n", seg2, newpc); + + if (!(seg2&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + + x86seg_log("Code seg2 call - %04X - %04X %04X %04X\n",seg2,segdat[0],segdat[1],segdat[2]); + + if (DPL > CPL) + { + x86gpf("loadcscall(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86seg_log("Call gate CS not present %04X\n",seg2); + x86np("Call gate CS not present", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL < CPL) + { + uint16_t oldcs = CS; + oaddr = addr; + /*Load new stack*/ + oldss=SS; + oldsp=oldsp2=ESP; + cpl_override=1; + if (tr.access&8) + { + addr = 4 + tr.base + (DPL * 8); + newss=readmemw(0,addr+4); + newsp=readmeml(0,addr); + } + else + { + addr = 2 + tr.base + (DPL * 4); + newss=readmemw(0,addr+2); + newsp=readmemw(0,addr); + } + cpl_override=0; + if (cpu_state.abrt) return; + x86seg_log("New stack %04X:%08X\n",newss,newsp); + if (!(newss&~3)) + { + x86ts(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if ((addr+7)>ldt.limit) + { + x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if ((addr+7)>gdt.limit) + { + x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + x86seg_log("Read stack seg\n"); + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + x86seg_log("Read stack seg done!\n"); + if (((newss & 3) != DPL) || (DPL2 != DPL)) + { + x86ts(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + x86ts(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + x86ss("Call gate loading SS not present\n", newss & 0xfffc); + return; + } + if (!stack32) oldsp &= 0xFFFF; + SS=newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + + do_seg_load(&cpu_state.seg_ss, segdat2); + + x86seg_log("Set access 1\n"); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS=seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + + x86seg_log("Set access 2\n"); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + x86seg_log("Type %04X\n",type); + if (type==0xC00) + { + PUSHL(oldss); + PUSHL(oldsp2); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + CS = oldcs; + return; + } + if (count) + { + while (count) + { + count--; + PUSHL(readmeml(oldssbase,oldsp+(count*4))); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + CS = oldcs; + return; + } + } + } + } + else + { + x86seg_log("Stack %04X\n",SP); + PUSHW(oldss); + x86seg_log("Write SS to %04X:%04X\n",SS,SP); + PUSHW(oldsp2); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + CS = oldcs; + return; + } + x86seg_log("Write SP to %04X:%04X\n",SS,SP); + if (count) + { + while (count) + { + count--; + tempw=readmemw(oldssbase,(oldsp&0xFFFF)+(count*2)); + x86seg_log("PUSH %04X\n",tempw); + PUSHW(tempw); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + CS = oldcs; + return; + } + } + } + } + cycles -= timing_call_pm_gate_inner; + break; + } + else if (DPL > CPL) + { + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + CS=seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_call_pm_gate; + break; + + default: + x86gpf(NULL,seg2&~3); + return; + } + break; + + case 0x100: /*286 Task gate*/ + case 0x900: /*386 Task gate*/ + cpu_state.pc = old_pc; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + cpl_override=0; + break; + + default: + x86gpf(NULL,seg&~3); + return; + } + } + } + else + { + 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 (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + } +} + +void pmoderetf(int is32, uint16_t off) +{ + uint32_t newpc; + uint32_t newsp; + uint32_t addr, oaddr; + uint16_t segdat[4],segdat2[4],seg,newss; + uint32_t oldsp=ESP; + x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,cpu_state.eflags); + if (is32) + { + newpc=POPL(); + seg=POPL(); if (cpu_state.abrt) return; + } + else + { + x86seg_log("PC read from %04X:%04X\n",SS,SP); + newpc=POPW(); + x86seg_log("CS read from %04X:%04X\n",SS,SP); + seg=POPW(); if (cpu_state.abrt) return; + } + x86seg_log("Return to %04X:%08X\n",seg,newpc); + if ((seg&3)=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } + oaddr = addr; + + x86seg_log("CPL %i RPL %i %i\n",CPL,seg&3,is32); + + if (stack32) ESP+=off; + else SP+=off; + + if (CPL==(seg&3)) + { + x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (CPL != DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (CPL < DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + cpu_state.pc=newpc; + if (segdat[2] & 0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + CS = seg; + do_seg_load(&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(); + oldcpl = CPL; + set_use32(segdat[3] & 0x40); + + cycles -= timing_retf_pm; + } + else + { + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((seg&3) != DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + x86seg_log("RETF non-conforming, %i %i\n",seg&3, DPL); + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((seg&3) < DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + x86seg_log("RETF conforming, %i %i\n",seg&3, DPL); + break; + default: + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + if (is32) + { + newsp=POPL(); + newss=POPL(); if (cpu_state.abrt) return; + } + else + { + x86seg_log("SP read from %04X:%04X\n",SS,SP); + newsp=POPW(); + x86seg_log("SS read from %04X:%04X\n",SS,SP); + newss=POPW(); if (cpu_state.abrt) return; + } + x86seg_log("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); + if (!(newss&~3)) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } + x86seg_log("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); + if ((newss & 3) != (seg & 3)) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + ESP=oldsp; + x86np("RETF loading SS not present\n", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 3)) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + SS=newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&cpu_state.seg_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + cpu_state.pc=newpc; + CS=seg; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3] & 0x40); + + if (stack32) ESP+=off; + else SP+=off; + + 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_retf_pm_outer; + } +} + +void pmodeint(int num, int soft) +{ + uint16_t segdat[4],segdat2[4],segdat3[4]; + uint32_t addr, oaddr; + uint16_t newss; + uint32_t oldss,oldsp; + int type; + uint32_t newsp; + uint16_t seg = 0; + int new_cpl; + + if (cpu_state.eflags&VM_FLAG && IOPL!=3 && soft) + { + x86seg_log("V86 banned int\n"); + x86gpf(NULL,0); + return; + } + addr=(num<<3); + if (addr>=idt.limit) + { + if (num==8) + { + /*Triple fault - reset!*/ + softresetx86(); + cpu_set_edx(); + } + else if (num==0xD) + { + pmodeint(8,0); + } + else + { + x86gpf(NULL,(num*8)+2+((soft)?0:1)); + } + x86seg_log("addr >= IDT.limit\n"); + return; + } + addr+=idt.base; + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(2,addr); + segdat[2]=readmemw(4,addr); + segdat[3]=readmemw(6,addr); cpl_override=0; + if (cpu_state.abrt) { + x86seg_log("Abrt reading from %08X\n",addr); + return; + } + oaddr = addr; + + x86seg_log("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); + if (!(segdat[2]&0x1F00)) + { + x86gpf(NULL,(num*8)+2); + return; + } + if (DPL=0x800)?32:16; + if (!(segdat[2]&0x8000)) + { + x86np("Int gate not present\n", (num << 3) | 2); + return; + } + seg=segdat[1]; + new_cpl = seg & 3; + + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + oaddr = addr; + + if (DPL2 > CPL) + { + x86gpf(NULL,seg&~3); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (DPL2=ldt.limit) + { + x86ss(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86ss(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat3[0]=readmemw(0,addr); + segdat3[1]=readmemw(0,addr+2); + segdat3[2]=readmemw(0,addr+4); + segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + if (((newss & 3) != DPL2) || (DPL3 != DPL2)) + { + x86ss(NULL,newss&~3); + return; + } + if ((segdat3[2]&0x1A00)!=0x1200) + { + x86ss(NULL,newss&~3); + return; + } + if (!(segdat3[2]&0x8000)) + { + x86np("Int gate loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + set_stack32((segdat3[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&cpu_state.seg_ss, segdat3); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat3[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + x86seg_log("New stack %04X:%08X\n",SS,ESP); + cpl_override=1; + if (type>=0x800) + { + if (cpu_state.eflags & VM_FLAG) + { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); if (cpu_state.abrt) return; + 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(cpu_state.flags | (cpu_state.eflags << 16)); + PUSHL(CS); + PUSHL(cpu_state.pc); if (cpu_state.abrt) return; + } + else + { + PUSHW(oldss); + PUSHW(oldsp); + PUSHW(cpu_state.flags); + PUSHW(CS); + PUSHW(cpu_state.pc); if (cpu_state.abrt) return; + } + cpl_override=0; + cpu_state.seg_cs.access=0 | 0x80; + cycles -= timing_int_pm_outer - timing_int_pm; + break; + } + else if (DPL2!=CPL) + { + x86gpf(NULL,seg&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (!(segdat2[2]&0x8000)) + { + x86np("Int gate CS not present\n", segdat[1] & 0xfffc); + return; + } + if ((cpu_state.eflags & VM_FLAG) && DPL20x800) + { + PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); + PUSHL(CS); + PUSHL(cpu_state.pc); if (cpu_state.abrt) return; + } + else + { + PUSHW(cpu_state.flags); + PUSHW(CS); + PUSHW(cpu_state.pc); if (cpu_state.abrt) return; + } + new_cpl = CS & 3; + break; + default: + x86gpf(NULL,seg&~3); + return; + } + do_seg_load(&cpu_state.seg_cs, segdat2); + CS = (seg & ~3) | new_cpl; + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | (new_cpl << 5); + 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]; + set_use32(segdat2[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + cpu_state.eflags &= ~VM_FLAG; + cpu_cur_status &= ~CPU_STATUS_V86; + if (!(type&0x100)) + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~(T_FLAG|NT_FLAG); + cycles -= timing_int_pm; + break; + + case 0x500: /*Task gate*/ + seg=segdat[1]; + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + cpl_override=0; if (cpu_state.abrt) return; + if (!(segdat2[2]&0x8000)) + { + x86np("Int task gate not present\n", segdat[1] & 0xfffc); + return; + } + optype=OPTYPE_INT; + cpl_override=1; + taskswitch286(seg,segdat2,segdat2[2]&0x800); + cpl_override=0; + break; + + default: + x86gpf(NULL,seg&~3); + return; + } +} + +void pmodeiret(int is32) +{ + uint32_t newsp; + uint16_t newss; + uint32_t tempflags,flagmask; + uint32_t newpc; + uint16_t segdat[4],segdat2[4]; + uint16_t segs[4]; + uint16_t seg = 0; + uint32_t addr, oaddr; + uint32_t oldsp=ESP; + if (is386 && (cpu_state.eflags & VM_FLAG)) + { + if (IOPL!=3) + { + x86gpf(NULL,0); + return; + } + if (is32) + { + newpc=POPL(); + seg=POPL(); + tempflags=POPL(); if (cpu_state.abrt) return; + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (cpu_state.abrt) return; + } + cpu_state.pc=newpc; + 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; + cpu_state.seg_cs.access |= 0x80; + CS=seg; + cpu_state.flags = (cpu_state.flags & 0x3000) | (tempflags & 0xCFD5) | 2; + cycles -= timing_iret_rm; + return; + } + + if (cpu_state.flags & NT_FLAG) + { + seg=readmemw(tr.base,0); + addr=seg&~7; + if (seg&4) + { + x86seg_log("TS LDT %04X %04X IRET\n",seg,gdt.limit); + x86ts(NULL,seg&~3); + return; + } + else + { + if (addr>=gdt.limit) + { + x86ts(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); + taskswitch286(seg,segdat,segdat[2] & 0x800); + cpl_override=0; + return; + } + flagmask=0xFFFF; + if (CPL) flagmask&=~0x3000; + if (IOPL>16)&VM_FLAG)) + { + newsp=POPL(); + newss=POPL(); + segs[0]=POPL(); + segs[1]=POPL(); + segs[2]=POPL(); + segs[3]=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } + 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); + + 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; + cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + + ESP=newsp; + loadseg(newss,&cpu_state.seg_ss); + do_seg_v86_init(&cpu_state.seg_ss); + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + use32=0; + cpu_cur_status &= ~CPU_STATUS_USE32; + cpu_state.flags = (tempflags&0xFFD5)|2; + cycles -= timing_iret_v86; + return; + } + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } + } + if (!(seg&~3)) + { + ESP = oldsp; + x86gpf(NULL,0); + return; + } + + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + if ((seg&3) < CPL) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if ((seg&3) != DPL) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ + if ((seg&3) < DPL) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + ESP = oldsp; + x86np("IRET CS not present\n", seg & 0xfffc); + return; + } + if ((seg&3) == CPL) + { + CS=seg; + 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(); + oldcpl = CPL; + set_use32(segdat[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_iret_pm; + } + else /*Return to outer level*/ + { + oaddr = addr; + x86seg_log("Outer level\n"); + if (is32) + { + newsp=POPL(); + newss=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } + } + else + { + newsp=POPW(); + newss=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } + } + + x86seg_log("IRET load stack %04X:%04X\n",newss,newsp); + + if (!(newss&~3)) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } + if ((newss & 3) != (seg & 3)) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (DPL2 != (seg & 3)) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + ESP = oldsp; + x86np("IRET loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&cpu_state.seg_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + CS=seg; + do_seg_load(&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(); + oldcpl = CPL; + set_use32(segdat[3] & 0x40); + + 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; + cpu_state.flags = (cpu_state.flags&~flagmask) | (tempflags&flagmask&0xFFD5)|2; + if (is32) cpu_state.eflags = tempflags>>16; +} + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) +{ + uint32_t base; + uint32_t limit; + uint32_t templ; + uint16_t tempw; + + uint32_t new_cr3=0; + uint16_t new_es,new_cs,new_ss,new_ds,new_fs,new_gs; + uint16_t new_ldt; + + uint32_t new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi,new_pc,new_flags; + + uint32_t addr; + + uint16_t segdat2[4]; + + base=segdat[1]|((segdat[2]&0xFF)<<16); + limit=segdat[0]; + if(is386) + { + base |= (segdat[3]>>8)<<24; + limit |= (segdat[3]&0xF)<<16; + } + + if (is32) + { + if (limit < 103) + { + 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; + + cpu_386_flags_rebuild(); + writememl(tr.base,0x1C,cr3); + writememl(tr.base,0x20,cpu_state.pc); + writememl(tr.base,0x24,cpu_state.flags | (cpu_state.eflags<<16)); + + writememl(tr.base,0x28,EAX); + writememl(tr.base,0x2C,ECX); + writememl(tr.base,0x30,EDX); + writememl(tr.base,0x34,EBX); + writememl(tr.base,0x38,ESP); + writememl(tr.base,0x3C,EBP); + writememl(tr.base,0x40,ESI); + writememl(tr.base,0x44,EDI); + + writememl(tr.base,0x48,ES); + writememl(tr.base,0x4C,CS); + writememl(tr.base,0x50,SS); + writememl(tr.base,0x54,DS); + writememl(tr.base,0x58,FS); + writememl(tr.base,0x5C,GS); + + 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) + { + 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); + 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; + flushmmucache(); + + cpu_state.pc=new_pc; + cpu_state.flags = new_flags; + cpu_state.eflags = new_flags>>16; + cpu_386_flags_extract(); + + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+gdt.base; + ldt.limit=readmemw(0,templ); + if (readmemb(0,templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + + if (cpu_state.eflags & VM_FLAG) + { + loadcs(new_cs); + set_use32(0); + cpu_cur_status |= CPU_STATUS_V86; + } + else + { + if (!(new_cs&~3)) + { + x86ts(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=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)) + { + 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) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + default: + x86ts(NULL,new_cs&~3); + return; + } + + 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; + + loadseg(new_es,&cpu_state.seg_es); + loadseg(new_ss,&cpu_state.seg_ss); + loadseg(new_ds,&cpu_state.seg_ds); + loadseg(new_fs,&cpu_state.seg_fs); + loadseg(new_gs,&cpu_state.seg_gs); + } + else + { + if (limit < 43) + { + 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; + + 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); + 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); + 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; + cpu_state.flags = new_flags; + cpu_386_flags_extract(); + + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+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 (!(new_cs&~3)) + { + x86ts(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=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)) + { + 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) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + default: + x86ts(NULL,new_cs&~3); + return; + } + + CS=new_cs; + do_seg_load(&cpu_state.seg_cs, segdat2); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(0); + + 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; + + loadseg(new_es,&cpu_state.seg_es); + loadseg(new_ss,&cpu_state.seg_ss); + loadseg(new_ds,&cpu_state.seg_ds); + if (is386) + { + loadseg(0,&cpu_state.seg_fs); + loadseg(0,&cpu_state.seg_gs); + } + } + + tr.seg=seg; + tr.base=base; + tr.limit=limit; + tr.access=segdat[2]>>8; +} + diff --git a/src/memregs.h b/src/cpu_new/x86seg.h similarity index 50% rename from src/memregs.h rename to src/cpu_new/x86seg.h index c44cc21ed..4f12a8d65 100644 --- a/src/memregs.h +++ b/src/cpu_new/x86seg.h @@ -6,20 +6,13 @@ * * This file is part of the 86Box distribution. * - * Emulation of the memory I/O scratch registers on ports 0xE1 - * and 0xE2, used by just about any emulated machine. + * x86 CPU segment emulation. * - * Version: @(#)memregs.h 1.0.1 2017/08/23 + * Version: @(#)x86seg.h 1.0.1 2017/10/12 * * Author: Miran Grca, - * Copyright 2016,2017 Miran Grca. + * + * Copyright 2016-2017 Miran Grca. */ -#ifndef EMU_MEMREGS_H -# define EMU_MEMREGS_H - -extern void powermate_memregs_init(void); -extern void memregs_init(void); - - -#endif /*EMU_MEMREGS_H*/ +extern void do_seg_load(x86seg *s, uint16_t *segdat); diff --git a/src/cpu_new/x87.c b/src/cpu_new/x87.c new file mode 100644 index 000000000..367948656 --- /dev/null +++ b/src/cpu_new/x87.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#define fplog 0 +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" +#include "../pic.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "386_common.h" + + +#ifdef ENABLE_FPU_LOG +int fpu_do_log = ENABLE_FPU_LOG; + + +static void +fpu_log(const char *fmt, ...) +{ + va_list ap; + + if (fpu_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define fpu_log(fmt, ...) +#endif + + +#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; + int c; + + for (c = 0; c < 8; c++) + { + 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 |= X87_TAG_VALID << (c * 2); + } + + return ret; +} + +void x87_settag(uint16_t new_tag) +{ + 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; + } +} + + +#ifdef ENABLE_808X_LOG +void x87_dumpregs() +{ + if (cpu_state.ismmx) + { + fpu_log("MM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\n", cpu_state.MM[0].q, cpu_state.MM[1].q, cpu_state.MM[2].q, cpu_state.MM[3].q); + fpu_log("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", cpu_state.MM[4].q, cpu_state.MM[5].q, cpu_state.MM[6].q, cpu_state.MM[7].q); + } + else + { + fpu_log("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]); + fpu_log("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]); + } + fpu_log("Status = %04X Control = %04X Tag = %04X\n", cpu_state.npxs, cpu_state.npxc, x87_gettag()); +} +#endif diff --git a/src/cpu_new/x87.h b/src/cpu_new/x87.h new file mode 100644 index 000000000..2d61c14ae --- /dev/null +++ b/src/cpu_new/x87.h @@ -0,0 +1,37 @@ +#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 = 0x0101010101010101ull; + cpu_state.ismmx = 1; +} + +static inline void x87_emms() +{ + *(uint64_t *)cpu_state.tag = 0; + cpu_state.ismmx = 0; +} + +uint16_t x87_gettag(); +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 << 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/cpu_new/x87_ops.h b/src/cpu_new/x87_ops.h new file mode 100644 index 000000000..783a49382 --- /dev/null +++ b/src/cpu_new/x87_ops.h @@ -0,0 +1,1983 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x87 FPU instructions core. + * + * Version: @(#)x87_ops.h 1.0.8 2019/06/11 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 leilei. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. + */ +#include +#include +#ifdef _MSC_VER +# include +#endif + +#ifdef ENABLE_FPU_LOG +extern void fpu_log(const char *fmt, ...); +#else +#ifndef fpu_log +#define fpu_log(fmt, ...) +#endif +#endif + +static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}; + +#define ST(x) cpu_state.ST[((cpu_state.TOP+(x))&7)] + +#define STATUS_ZERODIVIDE 4 + +#ifdef FPU_8087 +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + fpu_log("FPU : divide by zero\n"); \ + if (!(cpu_state.npxc & 0x80)) { \ + cpu_state.npxs |= 0x80; \ + nmi = 1; \ + } \ + return 1; \ + } \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) +#else +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + fpu_log("FPU : divide by zero\n"); \ + picint(1 << 13); \ + return 1; \ + } \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) +#endif + +static inline void x87_checkexceptions() +{ +} + +static inline void x87_push(double i) +{ + 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&7]; + cpu_state.tag[cpu_state.TOP&7] = TAG_EMPTY; + cpu_state.TOP++; + return t; +} + +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; +} +#define BIAS80 16383 +#define BIAS64 1023 + +static inline double x87_ld80() +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + test.eind.ll = readmeml(easeg,cpu_state.eaaddr); + test.eind.ll |= (uint64_t)readmeml(easeg,cpu_state.eaaddr+4)<<32; + test.begin = readmemw(easeg,cpu_state.eaaddr+8); + + int64_t exp64 = (((test.begin&0x7fff) - BIAS80)); + int64_t blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + int64_t exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + int64_t mant64 = (test.eind.ll >> 11) & (0xfffffffffffff); + int64_t sign = (test.begin&0x8000)?1:0; + + if ((test.begin & 0x7fff) == 0x7fff) + exp64final = 0x7ff; + if ((test.begin & 0x7fff) == 0) + exp64final = 0; + if (test.eind.ll & 0x400) + mant64++; + + test.eind.ll = (sign <<63)|(exp64final << 52)| mant64; + + return test.eind.d; +} + +static inline void x87_st80(double d) +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + + test.eind.d=d; + + int64_t sign80 = (test.eind.ll&(0x8000000000000000))?1:0; + int64_t exp80 = test.eind.ll&(0x7ff0000000000000); + int64_t exp80final = (exp80>>52); + int64_t mant80 = test.eind.ll&(0x000fffffffffffff); + int64_t mant80final = (mant80 << 11); + + if (exp80final == 0x7ff) /*Infinity / Nan*/ + { + exp80final = 0x7fff; + mant80final |= (0x8000000000000000); + } + else if (d != 0){ //Zero is a special case + // Elvira wants the 8 and tcalc doesn't + mant80final |= (0x8000000000000000); + //Ca-cyber doesn't like this when result is zero. + exp80final += (BIAS80 - BIAS64); + } + test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; + test.eind.ll = mant80final; + + writememl(easeg,cpu_state.eaaddr,test.eind.ll); + writememl(easeg,cpu_state.eaaddr+4,test.eind.ll>>32); + writememw(easeg,cpu_state.eaaddr+8,test.begin); +} + +static inline void x87_st_fsave(int reg) +{ + reg = (cpu_state.TOP + reg) & 7; + + if (cpu_state.tag[reg] & TAG_UINT64) + { + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[reg].q & 0xffffffff); + writememl(easeg, cpu_state.eaaddr + 4, cpu_state.MM[reg].q >> 32); + writememw(easeg, cpu_state.eaaddr + 8, 0x5555); + } + else + x87_st80(cpu_state.ST[reg]); +} + +static inline void x87_ld_frstor(int reg) +{ + reg = (cpu_state.TOP + reg) & 7; + + 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] & 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) +{ + r->l[0] = readmeml(easeg, cpu_state.eaaddr); + r->l[1] = readmeml(easeg, cpu_state.eaaddr + 4); + *w4 = readmemw(easeg, cpu_state.eaaddr + 8); +} + +static inline void x87_stmmx(MMX_REG r) +{ + writememl(easeg, cpu_state.eaaddr, r.l[0]); + writememl(easeg, cpu_state.eaaddr + 4, r.l[1]); + writememw(easeg, cpu_state.eaaddr + 8, 0xffff); +} + +#include + +static __inline uint16_t x87_compare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 + uint32_t result; + double ea = a, eb = b; + const uint64_t ia = 0x3fec1a6ff866a936ull; + const uint64_t ib = 0x3fec1a6ff866a938ull; + + /* Hack to make CHKCOP happy. */ + if (!memcmp(&ea, &ia, 8) && !memcmp(&eb, &ib, 8)) + return C3; + + if (!is386 && !(cpu_state.npxc & 0x1000) && + ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + eb = ea; + +#ifndef _MSC_VER + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + __asm volatile ("" : : : "memory"); + + __asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fcompp\n" + "fnstsw %0\n" + : "=m" (result) + : "m" (ea), "m" (eb) + ); +#else + _ReadWriteBarrier(); + _asm + { + fld eb + fld ea + fclex + fcompp + fnstsw result + } +#endif + + return result & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t result = 0; + double ea = a, eb = b; + + if (!is386 && !(cpu_state.npxc & 0x1000) && + ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + eb = ea; + + if (ea == eb) + result |= C3; + else if (ea < eb) + result |= C0; + + return result; +#endif +} + +static inline uint16_t x87_ucompare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 || defined __amd64__ + uint32_t out; + + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + asm volatile ("" : : : "memory"); + + asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fucompp\n" + "fnstsw %0\n" + : "=m" (out) + : "m" (a), "m" (b) + ); + + return out & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t out = 0; + + if (a == b) + out |= C3; + else if (a < b) + out |= C0; + + return out; +#endif +} + +typedef union +{ + float s; + uint32_t i; +} x87_ts; + +typedef union +{ + double d; + uint64_t i; +} x87_td; + +#ifdef FPU_8087 +#define FP_ENTER() { \ + fpucount++; \ + } +#else +#define FP_ENTER() do \ + { \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + fpucount++; \ + } while (0) +#endif + +#include "x87_ops_arith.h" +#include "x87_ops_misc.h" +#include "x87_ops_loadstore.h" + +#ifndef FPU_8087 +static int op_nofpu_a16(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + { + fetch_ea_16(fetchdat); + return 0; + } +} +static int op_nofpu_a32(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + { + fetch_ea_32(fetchdat); + return 0; + } +} +#endif + +#ifdef FPU_8087 +static int FPU_ILLEGAL_a16(uint32_t fetchdat) +{ + geteaw(); + wait(timing_rr, 0); + return 0; +} +#else +static int FPU_ILLEGAL_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int FPU_ILLEGAL_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +#endif + +#define ILLEGAL_a16 FPU_ILLEGAL_a16 + +#ifdef FPU_8087 +const OpFn OP_TABLE(fpu_8087_d8)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +const OpFn OP_TABLE(fpu_8087_d9)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, ILLEGAL_a16, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, ILLEGAL_a16, opFRNDINT, opFSCALE, ILLEGAL_a16, ILLEGAL_a16 +}; + +const OpFn OP_TABLE(fpu_8087_da)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_db)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFI, opFI, opFCLEX, opFINIT, ILLEGAL_a16, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_dc)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, ILLEGAL_a16, ILLEGAL_a16, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_8087_dd)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_de)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_8087_df)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +#else +#define ILLEGAL_a32 FPU_ILLEGAL_a32 + +const OpFn OP_TABLE(fpu_d8_a16)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; +const OpFn OP_TABLE(fpu_d8_a32)[32] = +{ + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +const OpFn OP_TABLE(fpu_287_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, ILLEGAL_a16, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, ILLEGAL_a16, opFRNDINT, opFSCALE, ILLEGAL_a16, ILLEGAL_a16 +}; + +const OpFn OP_TABLE(fpu_287_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a32, ILLEGAL_a32, opFTST, opFXAM, ILLEGAL_a32, ILLEGAL_a32, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a32, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a32, ILLEGAL_a32, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, ILLEGAL_a32, opFRNDINT, opFSCALE, ILLEGAL_a32, ILLEGAL_a32 +}; + +const OpFn OP_TABLE(fpu_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +const OpFn OP_TABLE(fpu_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a32, ILLEGAL_a32, opFTST, opFXAM, ILLEGAL_a32, ILLEGAL_a32, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a32, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a32, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +const OpFn OP_TABLE(fpu_287_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFUCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFUCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_686_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFUCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_686_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFUCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_287_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_686_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_686_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_287_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, ILLEGAL_a16, ILLEGAL_a16, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +const OpFn OP_TABLE(fpu_287_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, ILLEGAL_a32, ILLEGAL_a32, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +const OpFn OP_TABLE(fpu_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_287_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_287_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_287_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, + ILLEGAL_a32, opFCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_287_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_686_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_686_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(nofpu_a16)[256] = +{ + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, +}; +const OpFn OP_TABLE(nofpu_a32)[256] = +{ + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, +}; +#endif + +#undef ILLEGAL diff --git a/src/cpu_new/x87_ops_arith.h b/src/cpu_new/x87_ops_arith.h new file mode 100644 index 000000000..26cab3ca6 --- /dev/null +++ b/src/cpu_new/x87_ops_arith.h @@ -0,0 +1,418 @@ +#define opFPU(name, optype, a_size, load_var, get, use_var) \ +static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + 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&7] = TAG_VALID; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +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); \ + return 0; \ +} \ +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); \ + return 0; \ +} \ +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&7] = TAG_VALID; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +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&7] = TAG_VALID; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +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&7] = TAG_VALID; \ + CLOCK_CYCLES(11); \ + return 0; \ +} \ +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&7] = TAG_VALID; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +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&7] = TAG_VALID; \ + CLOCK_CYCLES(8); \ + return 0; \ +} + + +opFPU(s, x87_ts, 16, t.i, geteal, t.s) +#ifndef FPU_8087 +opFPU(s, x87_ts, 32, t.i, geteal, t.s) +#endif +opFPU(d, x87_td, 16, t.i, geteaq, t.d) +#ifndef FPU_8087 +opFPU(d, x87_td, 32, t.i, geteaq, t.d) +#endif + +opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t) +#ifndef FPU_8087 +opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t) +#endif +opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t) +#ifndef FPU_8087 +opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t) +#endif + + +static int opFADD(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = ST(0) + ST(fetchdat & 7); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + 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); + return 0; +} + +static int opFCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_compare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFCOMPP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + if (*(uint64_t *)&ST(0) == ((uint64_t)1 << 63) && *(uint64_t *)&ST(1) == 0) + cpu_state.npxs |= C0; /*Nasty hack to fix 80387 detection*/ + else + cpu_state.npxs |= x87_compare(ST(0), ST(1)); + + x87_pop(); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} +#ifndef FPU_8087 +static int opFUCOMPP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_ucompare(ST(0), ST(1)); + x87_pop(); + x87_pop(); + CLOCK_CYCLES(5); + return 0; +} + +static int opFCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + flags_rebuild(); + 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(4); + return 0; +} +static int opFCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + flags_rebuild(); + 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); + return 0; +} +#endif + +static int opFDIV(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(0), ST(0), ST(fetchdat & 7)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFDIVR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(0), ST(fetchdat&7), ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFMUL(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(16); + return 0; +} + +static int opFSUB(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFSUBR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +#ifndef FPU_8087 +static int opFUCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + flags_rebuild(); + 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(4); + return 0; +} +static int opFUCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + flags_rebuild(); + 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); + return 0; +} +#endif diff --git a/src/cpu_new/x87_ops_loadstore.h b/src/cpu_new/x87_ops_loadstore.h new file mode 100644 index 000000000..2ed5aec5a --- /dev/null +++ b/src/cpu_new/x87_ops_loadstore.h @@ -0,0 +1,490 @@ +static int opFILDiw_a16(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} +#ifndef FPU_8087 +static int opFILDiw_a32(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} +#endif + +static int opFISTiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFISTiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return cpu_state.abrt; +} +#endif + +static int opFISTPiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + 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); + return 0; +} +#ifndef FPU_8087 +static int opFISTPiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + 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); + return 0; +} +#endif + +static int opFILDiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = geteaq(); if (cpu_state.abrt) return 1; + x87_push((double)temp64); + cpu_state.MM[cpu_state.TOP&7].q = temp64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID | TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} +#ifndef FPU_8087 +static int opFILDiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = geteaq(); if (cpu_state.abrt) return 1; + x87_push((double)temp64); + cpu_state.MM[cpu_state.TOP&7].q = temp64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID | TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} +#endif + +static int FBSTP_a16(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, cpu_state.eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; + x87_pop(); + return 0; +} +#ifndef FPU_8087 +static int FBSTP_a32(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, cpu_state.eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; + x87_pop(); + return 0; +} +#endif + +static int FISTPiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + 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); + return 0; +} +#ifndef FPU_8087 +static int FISTPiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + 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); + return 0; +} +#endif + +static int opFILDil_a16(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} +#ifndef FPU_8087 +static int opFILDil_a32(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} +#endif + +static int opFISTil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFISTil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return cpu_state.abrt; +} +#endif + +static int opFISTPil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + 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); + return 0; +} +#ifndef FPU_8087 +static int opFISTPil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + 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); + return 0; +} +#endif + +static int opFLDe_a16(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + t=x87_ld80(); if (cpu_state.abrt) return 1; + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} +#ifndef FPU_8087 +static int opFLDe_a32(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + t=x87_ld80(); if (cpu_state.abrt) return 1; + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} +#endif + +static int opFSTPe_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + x87_st80(ST(0)); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} +#ifndef FPU_8087 +static int opFSTPe_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + x87_st80(ST(0)); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} +#endif + +static int opFLDd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + t.i = geteaq(); if (cpu_state.abrt) return 1; + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} +#ifndef FPU_8087 +static int opFLDd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + t.i = geteaq(); if (cpu_state.abrt) return 1; + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} +#endif + +static int opFSTd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return cpu_state.abrt; +} +#endif + +static int opFSTPd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + t.d = ST(0); + seteaq(t.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} +#ifndef FPU_8087 +static int opFSTPd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + t.d = ST(0); + seteaq(t.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} +#endif + +static int opFLDs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + ts.i = geteal(); if (cpu_state.abrt) return 1; + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} +#ifndef FPU_8087 +static int opFLDs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + ts.i = geteal(); if (cpu_state.abrt) return 1; + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} +#endif + +static int opFSTs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return cpu_state.abrt; +} +#endif + +static int opFSTPs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + ts.s = (float)ST(0); + seteal(ts.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} +#ifndef FPU_8087 +static int opFSTPs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + ts.s = (float)ST(0); + seteal(ts.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} +#endif diff --git a/src/cpu_new/x87_ops_misc.h b/src/cpu_new/x87_ops_misc.h new file mode 100644 index 000000000..6cccfd429 --- /dev/null +++ b/src/cpu_new/x87_ops_misc.h @@ -0,0 +1,861 @@ +#ifdef FPU_8087 +static int opFI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxc &= ~0x80; + if (rmdat == 0xe1) + cpu_state.npxc |= 0x80; + wait(3, 0); + return 0; +} +#else +static int opFSTSW_AX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + AX = cpu_state.npxs; + CLOCK_CYCLES(3); + return 0; +} +#endif + + +static int opFNOP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + CLOCK_CYCLES(4); + return 0; +} + +static int opFCLEX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= 0xff00; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINIT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; +#ifdef FPU_8087 + cpu_state.npxc = 0x3FF; +#else + cpu_state.npxc = 0x37F; +#endif + codegen_set_rounding_mode(X87_ROUNDING_NEAREST); + cpu_state.npxs = 0; + *(uint64_t *)cpu_state.tag = 0; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + CLOCK_CYCLES(17); + CPU_BLOCK_END(); + return 0; +} + + +static int opFFREE(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_EMPTY; + CLOCK_CYCLES(3); + return 0; +} + +static int opFFREEP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + fpu_log("FFREE\n"); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(3); + return 0; +} + +static int opFST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + 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); + return 0; +} + + + + +static int FSTOR() +{ + FP_ENTER(); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + 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; + cpu_state.eaaddr += 14; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + 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; + cpu_state.eaaddr += 28; + break; + } + x87_ld_frstor(0); cpu_state.eaaddr += 10; + x87_ld_frstor(1); cpu_state.eaaddr += 10; + x87_ld_frstor(2); cpu_state.eaaddr += 10; + x87_ld_frstor(3); cpu_state.eaaddr += 10; + x87_ld_frstor(4); cpu_state.eaaddr += 10; + x87_ld_frstor(5); cpu_state.eaaddr += 10; + x87_ld_frstor(6); cpu_state.eaaddr += 10; + x87_ld_frstor(7); + + cpu_state.ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + if (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 == 0x0101010101010101ull)) + cpu_state.ismmx = 1; + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + return cpu_state.abrt; +} +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; +} +#ifndef FPU_8087 +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; +} +#endif + +static int FSAVE() +{ + FP_ENTER(); + 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*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + cpu_state.eaaddr+=14; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+8,x87_pc_seg); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + writememw(easeg,cpu_state.eaaddr+12,x87_op_seg); + cpu_state.eaaddr+=14; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,(x87_op_off>>16)<<12); + cpu_state.eaaddr+=28; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememl(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememl(easeg,cpu_state.eaaddr+16,x87_pc_seg); + writememl(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,x87_op_seg); + cpu_state.eaaddr+=28; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + } + + cpu_state.npxc = 0x37F; + codegen_set_rounding_mode(X87_ROUNDING_NEAREST); + cpu_state.npxs = 0; + *(uint64_t *)cpu_state.tag = 0; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + 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; +} +#ifndef FPU_8087 +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; +} +#endif + +static int opFSTSW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11)); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTSW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11)); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +#endif + + +static int opFLD(uint32_t fetchdat) +{ + int old_tag; + uint64_t old_i64; + + FP_ENTER(); + cpu_state.pc++; + 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&7] = old_tag; + cpu_state.MM[cpu_state.TOP&7].q = old_i64; + CLOCK_CYCLES(4); + return 0; +} + +static int opFXCH(uint32_t fetchdat) +{ + double td; + uint8_t old_tag; + uint64_t old_i64; + FP_ENTER(); + cpu_state.pc++; + td = ST(0); + ST(0) = ST(fetchdat&7); + ST(fetchdat&7) = td; + 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&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); + return 0; +} + +static int opFCHS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = -ST(0); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(6); + return 0; +} + +static int opFABS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = fabs(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(3); + return 0; +} + +static int opFTST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + 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); + return 0; +} + +static int opFXAM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C1|C2|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); + return 0; +} + +static int opFLD1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(1.0); + CLOCK_CYCLES(4); + return 0; +} + +static int opFLDL2T(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(3.3219280948873623); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDL2E(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(1.4426950408889634); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDPI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(3.141592653589793); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDEG2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(0.3010299956639812); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDLN2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push_u64(0x3fe62e42fefa39f0ull); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDZ(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(0.0); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(4); + return 0; +} + +static int opF2XM1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = pow(2.0, ST(0)) - 1.0; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(200); + return 0; +} + +static int opFYL2X(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(1) = ST(1) * (log(ST(0)) / log(2.0)); + cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFYL2XP1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(1) = ST(1) * (log(ST(0)+1.0) / log(2.0)); + cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFPTAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = tan(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + x87_push(1.0); + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(235); + return 0; +} + +static int opFPATAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(1) = atan2(ST(1), ST(0)); + cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFDECSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.TOP--; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINCSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.TOP++; + CLOCK_CYCLES(4); + return 0; +} + +static int opFPREM(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + 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); + return 0; +} +#ifndef FPU_8087 +static int opFPREM1(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + 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); + return 0; +} +#endif + +static int opFSQRT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = sqrt(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(83); + return 0; +} + +#ifndef FPU_8087 +static int opFSINCOS(uint32_t fetchdat) +{ + double td; + FP_ENTER(); + cpu_state.pc++; + td = ST(0); + ST(0) = sin(td); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + x87_push(cos(td)); + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(330); + return 0; +} +#endif + +static int opFRNDINT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = (double)x87_fround(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(21); + return 0; +} + +static int opFSCALE(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + temp64 = (int64_t)ST(1); + ST(0) = ST(0) * pow(2.0, (double)temp64); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(30); + return 0; +} + +#ifndef FPU_8087 +static int opFSIN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = sin(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} + +static int opFCOS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = cos(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} +#endif + + +static int FLDENV() +{ + FP_ENTER(); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + 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; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + 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); + return cpu_state.abrt; +} + +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; +} +#ifndef FPU_8087 +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; +} +#endif + +static int opFLDCW_a16(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + tempw = geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.npxc = tempw; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + CLOCK_CYCLES(4); + return 0; +} +#ifndef FPU_8087 +static int opFLDCW_a32(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + tempw = geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.npxc = tempw; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + CLOCK_CYCLES(4); + return 0; +} +#endif + +static int FSTENV() +{ + FP_ENTER(); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+8,x87_pc_seg); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + writememw(easeg,cpu_state.eaaddr+12,x87_op_seg); + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,(x87_op_off>>16)<<12); + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememl(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememl(easeg,cpu_state.eaaddr+16,x87_pc_seg); + writememl(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,x87_op_seg); + break; + } + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + return cpu_state.abrt; +} + +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; +} +#ifndef FPU_8087 +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; +} +#endif + +static int opFSTCW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(cpu_state.npxc); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTCW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(cpu_state.npxc); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +#endif + +#ifndef FPU_8087 +#define opFCMOV(condition) \ + static int opFCMOV ## condition(uint32_t fetchdat) \ + { \ + FP_ENTER(); \ + cpu_state.pc++; \ + if (cond_ ## condition) \ + { \ + 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); \ + return 0; \ + } + +#define cond_U ( PF_SET()) +#define cond_NU (!PF_SET()) + +opFCMOV(B) +opFCMOV(E) +opFCMOV(BE) +opFCMOV(U) +opFCMOV(NB) +opFCMOV(NE) +opFCMOV(NBE) +opFCMOV(NU) +#endif diff --git a/src/device.c b/src/device.c index 2d1cd5df9..97318c50d 100644 --- a/src/device.c +++ b/src/device.c @@ -9,15 +9,15 @@ * Implementation of the generic device interface to handle * all devices attached to the emulator. * - * Version: @(#)device.c 1.0.8 2018/04/29 + * Version: @(#)device.c 1.0.24 2019/03/014 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. * * 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 @@ -39,12 +39,12 @@ */ #include #include +#include #include #include #include #define HAVE_STDARG_H #include "86box.h" -#include "cpu/cpu.h" #include "config.h" #include "device.h" #include "machine/machine.h" @@ -54,31 +54,32 @@ #define DEVICE_MAX 256 /* max # of devices */ -static void *device_priv[DEVICE_MAX]; -static device_t *devices[DEVICE_MAX]; -static device_t *device_current; +static device_t *devices[DEVICE_MAX]; +static void *device_priv[DEVICE_MAX]; +static device_context_t device_current, device_prev; #ifdef ENABLE_DEVICE_LOG int device_do_log = ENABLE_DEVICE_LOG; -#endif static void -device_log(const char *format, ...) +device_log(const char *fmt, ...) { -#ifdef ENABLE_DEVICE_LOG va_list ap; if (device_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define device_log(fmt, ...) +#endif +/* Initialize the module for use. */ void device_init(void) { @@ -86,66 +87,159 @@ device_init(void) } -void * -device_add(const device_t *d) +void +device_set_context(device_context_t *c, const device_t *d, int inst) +{ + memset(c, 0, sizeof(device_context_t)); + c->dev = d; + if (inst) + sprintf(c->name, "%s #%i", d->name, inst); + else + sprintf(c->name, "%s", d->name); +} + + +static void +device_context_common(const device_t *d, int inst) +{ + memcpy(&device_prev, &device_current, sizeof(device_context_t)); + device_set_context(&device_current, d, inst); +} + + +void +device_context(const device_t *d) +{ + device_context_common(d, 0); +} + + +void +device_context_inst(const device_t *d, int inst) +{ + device_context_common(d, inst); +} + + +void +device_context_restore(void) +{ + memcpy(&device_current, &device_prev, sizeof(device_context_t)); +} + + +static void * +device_add_common(const device_t *d, const device_t *cd, void *p, int inst) { void *priv = NULL; int c; - for (c=0; c<256; c++) { - if (devices[c] == (device_t *)d) { + for (c = 0; c < 256; c++) { + if (!inst && (devices[c] == (device_t *) d)) { device_log("DEVICE: device already exists!\n"); - return(NULL); + return (NULL); } if (devices[c] == NULL) break; } if (c >= DEVICE_MAX) fatal("DEVICE: too many devices\n"); - device_current = (device_t *)d; - + /* Do this so that a chained device_add will not identify the same ID + its master device is already trying to assign. */ devices[c] = (device_t *)d; - if (d->init != NULL) { - priv = d->init(d); - if (priv == NULL) { - if (d->name) - device_log("DEVICE: device '%s' init failed\n", d->name); - else - device_log("DEVICE: device init failed\n"); + if (p == NULL) { + memcpy(&device_prev, &device_current, sizeof(device_context_t)); + device_set_context(&device_current, cd, inst); - device_priv[c] = NULL; + if (d->init != NULL) { + priv = d->init(d); + if (priv == NULL) { + if (d->name) + device_log("DEVICE: device '%s' init failed\n", d->name); + else + device_log("DEVICE: device init failed\n"); - return(NULL); + devices[c] = NULL; + device_priv[c] = NULL; + + return(NULL); + } } - } - device_priv[c] = priv; + if (d->name) + device_log("DEVICE: device '%s' init successful\n", d->name); + else + device_log("DEVICE: device init successful\n"); + + memcpy(&device_current, &device_prev, sizeof(device_context_t)); + device_priv[c] = priv; + } else + device_priv[c] = p; return(priv); } +void * +device_add(const device_t *d) +{ + return device_add_common(d, d, NULL, 0); +} + + /* For devices that do not have an init function (internal video etc.) */ void device_add_ex(const device_t *d, void *priv) { - int c; + device_add_common(d, d, priv, 0); +} - for (c=0; c<256; c++) { - if (devices[c] == (device_t *)d) { - fatal("device_add: device already exists!\n"); - break; - } - if (devices[c] == NULL) break; - } - if (c >= DEVICE_MAX) - fatal("device_add: too many devices\n"); - device_current = (device_t *)d; +void * +device_add_inst(const device_t *d, int inst) +{ + return device_add_common(d, d, NULL, inst); +} - devices[c] = (device_t *)d; - device_priv[c] = priv; + +/* For devices that do not have an init function (internal video etc.) */ +void +device_add_inst_ex(const device_t *d, void *priv, int inst) +{ + device_add_common(d, d, priv, inst); +} + + +/* These four are to add a device with another device's context - will be + used to add machines' internal devices. */ +void * +device_cadd(const device_t *d, const device_t *cd) +{ + return device_add_common(d, cd, NULL, 0); +} + + +/* For devices that do not have an init function (internal video etc.) */ +void +device_cadd_ex(const device_t *d, const device_t *cd, void *priv) +{ + device_add_common(d, cd, priv, 0); +} + + +void * +device_cadd_inst(const device_t *d, const device_t *cd, int inst) +{ + return device_add_common(d, cd, NULL, inst); +} + + +/* For devices that do not have an init function (internal video etc.) */ +void +device_cadd_inst_ex(const device_t *d, const device_t *cd, void *priv, int inst) +{ + device_add_common(d, cd, priv, inst); } @@ -154,8 +248,10 @@ device_close_all(void) { int c; - for (c=0; c= 0; c--) { if (devices[c] != NULL) { + if (devices[c]->name) + device_log("Closing device: \"%s\"...\n", devices[c]->name); if (devices[c]->close != NULL) devices[c]->close(device_priv[c]); devices[c] = device_priv[c] = NULL; @@ -169,7 +265,7 @@ device_reset_all(void) { int c; - for (c=0; creset != NULL) devices[c]->reset(device_priv[c]); @@ -198,7 +294,7 @@ device_get_priv(const device_t *d) { int c; - for (c=0; cspeed_changed != NULL) devices[c]->speed_changed(device_priv[c]); @@ -243,7 +339,7 @@ device_force_redraw(void) { int c; - for (c=0; cforce_redraw != NULL) devices[c]->force_redraw(device_priv[c]); @@ -252,14 +348,14 @@ device_force_redraw(void) } -char * -device_get_config_string(char *s) +const char * +device_get_config_string(const char *s) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) - return(config_get_string((char *)device_current->name, s, (char *)c->default_string)); + return(config_get_string((char *) device_current.name, (char *) s, (char *) c->default_string)); c++; } @@ -269,13 +365,13 @@ device_get_config_string(char *s) int -device_get_config_int(char *s) +device_get_config_int(const char *s) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) - return(config_get_int((char *)device_current->name, s, c->default_int)); + return(config_get_int((char *) device_current.name, (char *) s, c->default_int)); c++; } @@ -285,29 +381,29 @@ device_get_config_int(char *s) int -device_get_config_int_ex(char *s, int default_int) +device_get_config_int_ex(const char *s, int def) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) - return(config_get_int((char *)device_current->name, s, default_int)); + return(config_get_int((char *) device_current.name, (char *) s, def)); c++; } - return(default_int); + return(def); } int -device_get_config_hex16(char *s) +device_get_config_hex16(const char *s) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) - return(config_get_hex16((char *)device_current->name, s, c->default_int)); + return(config_get_hex16((char *) device_current.name, (char *) s, c->default_int)); c++; } @@ -317,13 +413,13 @@ device_get_config_hex16(char *s) int -device_get_config_hex20(char *s) +device_get_config_hex20(const char *s) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) - return(config_get_hex20((char *)device_current->name, s, c->default_int)); + return(config_get_hex20((char *) device_current.name, (char *) s, c->default_int)); c++; } @@ -333,29 +429,29 @@ device_get_config_hex20(char *s) int -device_get_config_mac(char *s, int default_int) +device_get_config_mac(const char *s, int def) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) - return(config_get_mac((char *)device_current->name, s, default_int)); + return(config_get_mac((char *) device_current.name, (char *) s, def)); c++; } - return(default_int); + return(def); } void -device_set_config_int(char *s, int val) +device_set_config_int(const char *s, int val) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) { - config_set_int((char *)device_current->name, s, val); + config_set_int((char *) device_current.name, (char *) s, val); break; } @@ -365,13 +461,13 @@ device_set_config_int(char *s, int val) void -device_set_config_hex16(char *s, int val) +device_set_config_hex16(const char *s, int val) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) { - config_set_hex16((char *)device_current->name, s, val); + config_set_hex16((char *) device_current.name, (char *) s, val); break; } @@ -381,13 +477,13 @@ device_set_config_hex16(char *s, int val) void -device_set_config_hex20(char *s, int val) +device_set_config_hex20(const char *s, int val) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) { - config_set_hex20((char *)device_current->name, s, val); + config_set_hex20((char *) device_current.name, (char *) s, val); break; } @@ -397,13 +493,13 @@ device_set_config_hex20(char *s, int val) void -device_set_config_mac(char *s, int val) +device_set_config_mac(const char *s, int val) { - const device_config_t *c = device_current->config; + const device_config_t *c = device_current.dev->config; while (c && c->type != -1) { if (! strcmp(s, c->name)) { - config_set_mac((char *)device_current->name, s, val); + config_set_mac((char *) device_current.name, (char *) s, val); break; } @@ -431,7 +527,6 @@ device_is_valid(const device_t *device, int mflags) if ((device->flags & DEVICE_PCI) && !(mflags & MACHINE_PCI)) return(0); - if ((device->flags & DEVICE_PS2) && !(mflags & MACHINE_HDC_PS2)) return(0); if ((device->flags & DEVICE_AGP) && !(mflags & MACHINE_AGP)) return(0); return(1); diff --git a/src/device.h b/src/device.h index 6256a3ea5..dbf9976a2 100644 --- a/src/device.h +++ b/src/device.h @@ -8,15 +8,15 @@ * * Definitions for the device handler. * - * Version: @(#)device.h 1.0.5 2018/04/26 + * Version: @(#)device.h 1.0.12 2019/03/14 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. * * 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 @@ -50,19 +50,21 @@ #define CONFIG_HEX16 7 #define CONFIG_HEX20 8 #define CONFIG_MAC 9 +#define CONFIG_MIDI_IN 10 enum { - DEVICE_NOT_WORKING = 1, /* does not currently work correctly and will be disabled in a release build*/ - DEVICE_AT = 2, /* requires an AT-compatible system */ - DEVICE_PS2 = 4, /* requires a PS/1 or PS/2 system */ - DEVICE_ISA = 8, /* requires the ISA bus */ - DEVICE_CBUS = 0x10, /* requires the C-BUS bus */ - DEVICE_MCA = 0x20, /* requires the MCA bus */ - DEVICE_EISA = 0x40, /* requires the EISA bus */ - DEVICE_VLB = 0x80, /* requires the PCI bus */ - DEVICE_PCI = 0x100, /* requires the VLB bus */ - DEVICE_AGP = 0x200 /* requires the AGP bus */ + DEVICE_NOT_WORKING = 1, /* does not currently work correctly and will be disabled in a release build */ + DEVICE_PCJR = 2, /* requires an IBM PCjr */ + DEVICE_AT = 4, /* requires an AT-compatible system */ + DEVICE_PS2 = 8, /* requires a PS/1 or PS/2 system */ + DEVICE_ISA = 0x10, /* requires the ISA bus */ + DEVICE_CBUS = 0x20, /* requires the C-BUS bus */ + DEVICE_MCA = 0x40, /* requires the MCA bus */ + DEVICE_EISA = 0x80, /* requires the EISA bus */ + DEVICE_VLB = 0x100, /* requires the PCI bus */ + DEVICE_PCI = 0x200, /* requires the VLB bus */ + DEVICE_AGP = 0x400 /* requires the AGP bus */ }; @@ -99,42 +101,58 @@ typedef struct _device_ { uint32_t local; /* flags local to device */ void *(*init)(const struct _device_ *); - void (*close)(void *p); - void (*reset)(void *p); + void (*close)(void *priv); + void (*reset)(void *priv); int (*available)(/*void*/); - void (*speed_changed)(void *p); - void (*force_redraw)(void *p); + void (*speed_changed)(void *priv); + void (*force_redraw)(void *priv); const device_config_t *config; } device_t; +typedef struct { + const device_t *dev; + char name[2048]; +} device_context_t; + #ifdef __cplusplus extern "C" { #endif -extern void device_init(void); -extern void *device_add(const device_t *d); -extern void device_add_ex(const device_t *d, void *priv); -extern void device_close_all(void); -extern void device_reset_all(void); -extern void device_reset_all_pci(void); -extern void *device_get_priv(const device_t *d); -extern int device_available(const device_t *d); -extern void device_speed_changed(void); -extern void device_force_redraw(void); +extern void device_init(void); +extern void device_set_context(device_context_t *c, const device_t *d, int inst); +extern void device_context(const device_t *d); +extern void device_context_inst(const device_t *d, int inst); +extern void device_context_restore(void); +extern void *device_add(const device_t *d); +extern void device_add_ex(const device_t *d, void *priv); +extern void *device_add_inst(const device_t *d, int inst); +extern void device_add_inst_ex(const device_t *d, void *priv, int inst); +extern void *device_cadd(const device_t *d, const device_t *cd); +extern void device_cadd_ex(const device_t *d, const device_t *cd, void *priv); +extern void *device_cadd_inst(const device_t *d, const device_t *cd, int inst); +extern void device_cadd_inst_ex(const device_t *d, const device_t *cd, void *priv, int inst); +extern void device_close_all(void); +extern void device_reset_all(void); +extern void device_reset_all_pci(void); +extern void *device_get_priv(const device_t *d); +extern int device_available(const device_t *d); +extern void device_speed_changed(void); +extern void device_force_redraw(void); -extern int device_get_config_int(char *name); -extern int device_get_config_int_ex(char *s, int default_int); -extern int device_get_config_hex16(char *name); -extern int device_get_config_hex20(char *name); -extern int device_get_config_mac(char *name, int default_int); -extern void device_set_config_int(char *s, int val); -extern void device_set_config_hex16(char *s, int val); -extern void device_set_config_hex20(char *s, int val); -extern void device_set_config_mac(char *s, int val); -extern char *device_get_config_string(char *name); -extern int device_is_valid(const device_t *device, int machine_flags); +extern int device_is_valid(const device_t *, int machine_flags); + +extern int device_get_config_int(const char *name); +extern int device_get_config_int_ex(const char *s, int dflt_int); +extern int device_get_config_hex16(const char *name); +extern int device_get_config_hex20(const char *name); +extern int device_get_config_mac(const char *name, int dflt_int); +extern void device_set_config_int(const char *s, int val); +extern void device_set_config_hex16(const char *s, int val); +extern void device_set_config_hex20(const char *s, int val); +extern void device_set_config_mac(const char *s, int val); +extern const char *device_get_config_string(const char *name); extern int machine_get_config_int(char *s); extern char *machine_get_config_string(char *s); diff --git a/src/disk/hdc.c b/src/disk/hdc.c index 37d036e99..4b1313cb1 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -8,7 +8,7 @@ * * Common code to handle all sorts of disk controllers. * - * Version: @(#)hdc.c 1.0.15 2018/04/29 + * Version: @(#)hdc.c 1.0.17 2018/11/18 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -30,19 +30,16 @@ #include "hdd.h" -char *hdc_name; /* configured HDC name */ int hdc_current; #ifdef ENABLE_HDC_LOG int hdc_do_log = ENABLE_HDC_LOG; -#endif static void hdc_log(const char *fmt, ...) { -#ifdef ENABLE_HDC_LOG va_list ap; if (hdc_do_log) { @@ -50,8 +47,10 @@ hdc_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define hdc_log(fmt, ...) +#endif static void * @@ -105,14 +104,26 @@ static const struct { { "Internal Controller", "internal", &inthdc_device }, - { "[ISA] [MFM] IBM PC Fixed Disk Adapter", "mfm_xt", - &mfm_xt_xebec_device }, + { "[ISA] [MFM] IBM PC Fixed Disk Adapter", "st506_xt", + &st506_xt_xebec_device }, - { "[ISA] [MFM] DTC-5150X Fixed Disk Adapter", "mfm_dtc5150x", - &mfm_xt_dtc5150x_device }, + { "[ISA] [MFM] DTC-5150X Fixed Disk Adapter", "st506_xt_dtc5150x", + &st506_xt_dtc5150x_device }, - { "[ISA] [MFM] IBM PC/AT Fixed Disk Adapter", "mfm_at", - &mfm_at_wd1003_device }, + { "[ISA] [MFM] ST-11M Fixed Disk Adapter", "st506_xt_st11_m", + &st506_xt_st11_m_device }, + + { "[ISA] [MFM] WD1002A-WX1 Fixed Disk Adapter", "st506_xt_wd1002a_wx1", + &st506_xt_wd1002a_wx1_device }, + + { "[ISA] [MFM/RLL] IBM PC/AT Fixed Disk Adapter", "st506_at", + &st506_at_wd1003_device }, + + { "[ISA] [RLL] ST-11R Fixed Disk Adapter", "st506_xt_st11_r", + &st506_xt_st11_r_device }, + + { "[ISA] [RLL] WD1002A-27X Fixed Disk Adapter", "st506_xt_wd1002a_27x", + &st506_xt_wd1002a_27x_device }, { "[ISA] [ESDI] PC/AT ESDI Fixed Disk Adapter", "esdi_at", &esdi_at_wd1007vse1_device }, @@ -160,19 +171,10 @@ static const struct { /* Initialize the 'hdc_current' value based on configured HDC name. */ void -hdc_init(char *name) +hdc_init(void) { - int c; - hdc_log("HDC: initializing..\n"); - for (c = 0; controllers[c].device; c++) { - if (! strcmp(name, (char *) controllers[c].internal_name)) { - hdc_current = c; - break; - } - } - /* Zero all the hard disk image arrays. */ hdd_image_init(); } @@ -211,6 +213,22 @@ hdc_get_internal_name(int hdc) } +int +hdc_get_id(char *s) +{ + int c = 0; + + while (strlen((char *) controllers[c].name)) + { + if (!strcmp((char *) controllers[c].name, s)) + return c; + c++; + } + + return 0; +} + + int hdc_get_from_internal_name(char *s) { diff --git a/src/disk/hdc.h b/src/disk/hdc.h index 89e34a1d9..c5e8d624c 100644 --- a/src/disk/hdc.h +++ b/src/disk/hdc.h @@ -8,13 +8,13 @@ * * Definitions for the common disk controller handler. * - * Version: @(#)hdc.h 1.0.8 2018/04/05 + * Version: @(#)hdc.h 1.0.11 2019/03/03 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_HDC_H # define EMU_HDC_H @@ -23,18 +23,21 @@ #define MFM_NUM 2 /* 2 drives per controller supported */ #define ESDI_NUM 2 /* 2 drives per controller supported */ #define XTA_NUM 2 /* 2 drives per controller supported */ -#define IDE_NUM 8 +#define IDE_NUM 10 /* 8 drives per AT IDE + 2 for XT IDE */ #define SCSI_NUM 16 /* theoretically the controller can have at * least 7 devices, with each device being * able to support 8 units, but hey... */ -extern char *hdc_name; extern int hdc_current; -extern const device_t mfm_xt_xebec_device; /* mfm_xt_xebec */ -extern const device_t mfm_xt_dtc5150x_device; /* mfm_xt_dtc */ -extern const device_t mfm_at_wd1003_device; /* mfm_at_wd1003 */ +extern const device_t st506_xt_xebec_device; /* st506_xt_xebec */ +extern const device_t st506_xt_dtc5150x_device; /* st506_xt_dtc */ +extern const device_t st506_xt_st11_m_device; /* st506_xt_st11_m */ +extern const device_t st506_xt_st11_r_device; /* st506_xt_st11_m */ +extern const device_t st506_xt_wd1002a_wx1_device; /* st506_xt_wd1002a_wx1 */ +extern const device_t st506_xt_wd1002a_27x_device; /* st506_xt_wd1002a_27x */ +extern const device_t st506_at_wd1003_device; /* st506_at_wd1003 */ extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */ extern const device_t esdi_ps2_device; /* esdi_mca */ @@ -59,11 +62,12 @@ extern const device_t xtide_acculogic_device; /* xtide_ps2 */ extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ -extern void hdc_init(char *name); +extern void hdc_init(void); extern void hdc_reset(void); extern char *hdc_get_name(int hdc); extern char *hdc_get_internal_name(int hdc); +extern int hdc_get_id(char *s); extern int hdc_get_from_internal_name(char *s); extern int hdc_has_config(int hdc); extern const device_t *hdc_get_device(int hdc); diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index 1a4539388..6e3946a80 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -8,15 +8,15 @@ * * Driver for the ESDI controller (WD1007-vse1) for PC/AT. * - * Version: @(#)hdc_esdi_at.c 1.0.13 2018/05/02 + * Version: @(#)hdc_esdi_at.c 1.0.15 2018/10/31 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE @@ -98,7 +98,7 @@ typedef struct { uint16_t buffer[256]; int irqstat; - int64_t callback; + pc_timer_t callback_timer; drive_t drives[2]; @@ -108,13 +108,11 @@ typedef struct { #ifdef ENABLE_ESDI_AT_LOG int esdi_at_do_log = ENABLE_ESDI_AT_LOG; -#endif static void esdi_at_log(const char *fmt, ...) { -#ifdef ENABLE_ESDI_AT_LOG va_list ap; if (esdi_at_do_log) { @@ -122,11 +120,13 @@ esdi_at_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define esdi_at_log(fmt, ...) +#endif -static inline void +static __inline void irq_raise(esdi_t *esdi) { if (!(esdi->fdisk & 2)) @@ -136,15 +136,18 @@ irq_raise(esdi_t *esdi) } -static inline void +static __inline void irq_lower(esdi_t *esdi) { - if (esdi->irqstat) { - if (!(esdi->fdisk & 2)) - picintc(1 << 14); + picintc(1 << 14); +} - esdi->irqstat = 0; - } + +static __inline void +irq_update(esdi_t *esdi) +{ + if (esdi->irqstat && !((pic2.pend | pic2.ins) & 0x40) && !(esdi->fdisk & 2)) + picint(1 << 14); } @@ -220,10 +223,8 @@ esdi_writew(uint16_t port, uint16_t val, void *priv) if (esdi->pos >= 512) { esdi->pos = 0; esdi->status = STAT_BUSY; - timer_clock(); /* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */ - esdi->callback = (3125LL * TIMER_USEC) / 8LL; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, (3125 * TIMER_USEC) / 8); } } @@ -263,11 +264,10 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case 0x1f6: /* drive/Head */ esdi->head = val & 0xF; esdi->drive_sel = (val & 0x10) ? 1 : 0; - if (esdi->drives[esdi->drive_sel].present) { - esdi->status = STAT_READY|STAT_DSC; - } else { + if (esdi->drives[esdi->drive_sel].present) + esdi->status = STAT_READY | STAT_DSC; + else esdi->status = 0; - } return; case 0x1f7: /* command register */ @@ -281,26 +281,20 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case CMD_RESTORE: esdi->command &= ~0x0f; /*mask off step rate*/ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME); break; case CMD_SEEK: esdi->command &= ~0x0f; /*mask off step rate*/ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME); break; default: switch (val) { case CMD_NOP: esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME); break; case CMD_READ: @@ -313,9 +307,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case 0xa0: esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME); break; case CMD_WRITE: @@ -333,9 +325,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case CMD_VERIFY+1: esdi->command &= ~0x01; esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME); break; case CMD_FORMAT: @@ -345,33 +335,25 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 30LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 30 * HDC_TIME); break; case CMD_DIAGNOSE: /* Execute Drive Diagnostics */ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME); break; case 0xe0: /*???*/ case CMD_READ_PARAMETERS: esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME); break; default: esdi_at_log("WD1007: bad command %02X\n", val); case 0xe8: /*???*/ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME); break; } } @@ -379,24 +361,18 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case 0x3f6: /* Device control */ if ((esdi->fdisk & 0x04) && !(val & 0x04)) { - timer_clock(); - esdi->callback = 500LL*HDC_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, 500 * HDC_TIME); esdi->reset = 1; esdi->status = STAT_BUSY; } if (val & 0x04) { - /*Drive held in reset*/ - timer_clock(); - esdi->callback = 0LL; - timer_update_outstanding(); + /* Drive held in reset. */ + timer_disable(&esdi->callback_timer); esdi->status = STAT_BUSY; } esdi->fdisk = val; - /* Lower IRQ on IRQ disable. */ - if ((val & 2) && !(esdi->fdisk & 0x02)) - picintc(1 << 14); + irq_update(esdi); break; } } @@ -419,10 +395,8 @@ esdi_readw(uint16_t port, void *priv) if (esdi->secount) { next_sector(esdi); esdi->status = STAT_BUSY; - timer_clock(); /* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */ - esdi->callback = (3125LL * TIMER_USEC) / 8LL; - timer_update_outstanding(); + timer_set_delay_u64(&esdi->callback_timer, (3125 * TIMER_USEC) / 8); } else { ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 0); } @@ -457,15 +431,15 @@ esdi_read(uint16_t port, void *priv) break; case 0x1f4: /* cylinder low */ - temp = (uint8_t)(esdi->cylinder&0xff); + temp = (uint8_t) (esdi->cylinder&0xff); break; case 0x1f5: /* cylinder high */ - temp = (uint8_t)(esdi->cylinder>>8); + temp = (uint8_t) (esdi->cylinder>>8); break; case 0x1f6: /* drive/Head */ - temp = (uint8_t)(0xa0|esdi->head|(esdi->drive_sel?0x10:0)); + temp = (uint8_t) (esdi->head | (esdi->drive_sel ? 0x10 : 0) | 0xa0); break; case 0x1f7: /* status */ @@ -487,7 +461,6 @@ esdi_callback(void *priv) drive_t *drive = &esdi->drives[esdi->drive_sel]; off64_t addr; - esdi->callback = 0LL; if (esdi->reset) { esdi->status = STAT_READY|STAT_DSC; esdi->error = 1; @@ -498,11 +471,10 @@ esdi_callback(void *priv) esdi->reset = 0; ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 0); - return; } - esdi_at_log("WD1007: command %02x\n", esdi->command); + esdi_at_log("WD1007: command %02x on drive %i\n", esdi->command, esdi->drive_sel); switch (esdi->command) { case CMD_RESTORE: @@ -520,9 +492,8 @@ esdi_callback(void *priv) if (! drive->present) { esdi->status = STAT_READY|STAT_ERR|STAT_DSC; esdi->error = ERR_ABRT; - } else { + } else esdi->status = STAT_READY|STAT_DSC; - } irq_raise(esdi); break; @@ -531,23 +502,26 @@ esdi_callback(void *priv) esdi->status = STAT_READY|STAT_ERR|STAT_DSC; esdi->error = ERR_ABRT; irq_raise(esdi); - break; - } + } else { + if (get_sector(esdi, &addr)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(esdi); + break; + } - if (get_sector(esdi, &addr)) { - esdi->error = ERR_ID_NOT_FOUND; - esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + if (hdd_image_read_ex(drive->hdd_num, addr, 1, (uint8_t *)esdi->buffer)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + irq_raise(esdi); + break; + } + + esdi->pos = 0; + esdi->status = STAT_DRQ|STAT_READY|STAT_DSC; irq_raise(esdi); - break; + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); } - - hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *)esdi->buffer); - - esdi->pos = 0; - esdi->status = STAT_DRQ|STAT_READY|STAT_DSC; - irq_raise(esdi); - ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); break; case CMD_WRITE: @@ -556,28 +530,31 @@ esdi_callback(void *priv) esdi->error = ERR_ABRT; irq_raise(esdi); break; - } - - if (get_sector(esdi, &addr)) { - esdi->error = ERR_ID_NOT_FOUND; - esdi->status = STAT_READY|STAT_DSC|STAT_ERR; - irq_raise(esdi); - break; - } - - hdd_image_write(drive->hdd_num, addr, 1, - (uint8_t *)esdi->buffer); - - irq_raise(esdi); - esdi->secount = (esdi->secount - 1) & 0xff; - if (esdi->secount) { - esdi->status = STAT_DRQ|STAT_READY|STAT_DSC; - esdi->pos = 0; - next_sector(esdi); } else { - esdi->status = STAT_READY|STAT_DSC; + if (get_sector(esdi, &addr)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(esdi); + break; + } + + if (hdd_image_write_ex(drive->hdd_num, addr, 1, (uint8_t *)esdi->buffer)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + irq_raise(esdi); + break; + } + + irq_raise(esdi); + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) { + esdi->status = STAT_DRQ|STAT_READY|STAT_DSC; + esdi->pos = 0; + next_sector(esdi); + } else + esdi->status = STAT_READY|STAT_DSC; + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); } - ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); break; case CMD_VERIFY: @@ -586,27 +563,31 @@ esdi_callback(void *priv) esdi->error = ERR_ABRT; irq_raise(esdi); break; - } + } else { + if (get_sector(esdi, &addr)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(esdi); + break; + } - if (get_sector(esdi, &addr)) { - esdi->error = ERR_ID_NOT_FOUND; - esdi->status = STAT_READY|STAT_DSC|STAT_ERR; - irq_raise(esdi); - break; - } + if (hdd_image_read_ex(drive->hdd_num, addr, 1, (uint8_t *)esdi->buffer)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + irq_raise(esdi); + break; + } - hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *)esdi->buffer); - - ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); - next_sector(esdi); - esdi->secount = (esdi->secount - 1) & 0xff; - if (esdi->secount) - esdi->callback = 6LL*HDC_TIME; - else { - esdi->pos = 0; - esdi->status = STAT_READY|STAT_DSC; - irq_raise(esdi); + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); + next_sector(esdi); + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) + timer_set_delay_u64(&esdi->callback_timer, 6 * HDC_TIME); + else { + esdi->pos = 0; + esdi->status = STAT_READY|STAT_DSC; + irq_raise(esdi); + } } break; @@ -616,45 +597,54 @@ esdi_callback(void *priv) esdi->error = ERR_ABRT; irq_raise(esdi); break; - } + } else { + if (get_sector(esdi, &addr)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(esdi); + break; + } - if (get_sector(esdi, &addr)) { - esdi->error = ERR_ID_NOT_FOUND; - esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + if (hdd_image_zero_ex(drive->hdd_num, addr, esdi->secount)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + irq_raise(esdi); + break; + } + + esdi->status = STAT_READY|STAT_DSC; irq_raise(esdi); - break; + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); } - - hdd_image_zero(drive->hdd_num, addr, esdi->secount); - - esdi->status = STAT_READY|STAT_DSC; - irq_raise(esdi); - ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); break; case CMD_DIAGNOSE: + /* This is basically controller diagnostics - it resets drive select to 0, + and resets error and status to ready, DSC, and no error detected. */ + esdi->drive_sel = 0; + drive = &esdi->drives[esdi->drive_sel]; + esdi->error = 1; /*no error detected*/ esdi->status = STAT_READY|STAT_DSC; irq_raise(esdi); break; case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ - if (drive->present == 0) { + if (! drive->present) { esdi->status = STAT_READY|STAT_ERR|STAT_DSC; esdi->error = ERR_ABRT; irq_raise(esdi); - break; + } else { + drive->cfg_spt = esdi->secount; + drive->cfg_hpc = esdi->head+1; + + esdi_at_log("WD1007: parameters: spt=%i hpc=%i\n", drive->cfg_spt,drive->cfg_hpc); + + if (! esdi->secount) + fatal("WD1007: secount=0\n"); + esdi->status = STAT_READY|STAT_DSC; + irq_raise(esdi); } - - drive->cfg_spt = esdi->secount; - drive->cfg_hpc = esdi->head+1; - - esdi_at_log("WD1007: parameters: spt=%i hpc=%i\n", drive->cfg_spt,drive->cfg_hpc); - - if (! esdi->secount) - fatal("WD1007: secount=0\n"); - esdi->status = STAT_READY|STAT_DSC; - irq_raise(esdi); break; case CMD_NOP: @@ -669,31 +659,30 @@ esdi_callback(void *priv) esdi->error = ERR_ABRT; irq_raise(esdi); break; + } else { + switch (esdi->cylinder >> 8) { + case 0x31: + esdi->cylinder = drive->real_tracks; + break; + + case 0x33: + esdi->cylinder = drive->real_hpc; + break; + + case 0x35: + esdi->cylinder = 0x200; + break; + + case 0x36: + esdi->cylinder = drive->real_spt; + break; + + default: + esdi_at_log("WD1007: bad read config %02x\n", esdi->cylinder >> 8); + } + esdi->status = STAT_READY|STAT_DSC; + irq_raise(esdi); } - - switch (esdi->cylinder >> 8) { - case 0x31: - esdi->cylinder = drive->real_tracks; - break; - - case 0x33: - esdi->cylinder = drive->real_hpc; - break; - - case 0x35: - esdi->cylinder = 0x200; - break; - - case 0x36: - esdi->cylinder = drive->real_spt; - break; - - default: - esdi_at_log("WD1007: bad read config %02x\n", - esdi->cylinder >> 8); - } - esdi->status = STAT_READY|STAT_DSC; - irq_raise(esdi); break; case 0xa0: @@ -714,35 +703,34 @@ esdi_callback(void *priv) esdi->status = STAT_READY|STAT_ERR|STAT_DSC; esdi->error = ERR_ABRT; irq_raise(esdi); - break; + } else { + memset(esdi->buffer, 0x00, 512); + esdi->buffer[0] = 0x44; /* general configuration */ + esdi->buffer[1] = drive->real_tracks; /* number of non-removable cylinders */ + esdi->buffer[2] = 0; /* number of removable cylinders */ + esdi->buffer[3] = drive->real_hpc; /* number of heads */ + esdi->buffer[4] = 600; /* number of unformatted bytes/sector */ + esdi->buffer[5] = esdi->buffer[4] * drive->real_spt; /* number of unformatted bytes/track */ + esdi->buffer[6] = drive->real_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 */ + esdi->buffer[20] = 2; /* controller type */ + esdi->buffer[21] = 1; /* sector buffer size, in sectors */ + esdi->buffer[22] = 0; /* ecc bytes appended */ + 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; + irq_raise(esdi); } - - memset(esdi->buffer, 0x00, 512); - esdi->buffer[0] = 0x44; /* general configuration */ - esdi->buffer[1] = drive->real_tracks; /* number of non-removable cylinders */ - esdi->buffer[2] = 0; /* number of removable cylinders */ - esdi->buffer[3] = drive->real_hpc; /* number of heads */ - esdi->buffer[4] = 600; /* number of unformatted bytes/track */ - esdi->buffer[5] = esdi->buffer[4] * drive->real_spt; /* number of unformatted bytes/sector */ - esdi->buffer[6] = drive->real_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 */ - esdi->buffer[20] = 2; /* controller type */ - esdi->buffer[21] = 1; /* sector buffer size, in sectors */ - esdi->buffer[22] = 0; /* ecc bytes appended */ - 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; - irq_raise(esdi); break; default: @@ -779,6 +767,18 @@ loadhd(esdi_t *esdi, int hdd_num, int d, const wchar_t *fn) } +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; +} + + static void * wd1007vse1_init(const device_t *info) { @@ -802,6 +802,10 @@ wd1007vse1_init(const device_t *info) rom_init(&esdi->bios_rom, BIOS_FILE, 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, 1, esdi_read, esdi_readw, NULL, esdi_write, esdi_writew, NULL, esdi); @@ -811,7 +815,7 @@ wd1007vse1_init(const device_t *info) io_sethandler(0x03f6, 1, NULL, NULL, NULL, esdi_write, NULL, NULL, esdi); - timer_add(esdi_callback, &esdi->callback, &esdi->callback, esdi); + timer_add(&esdi->callback_timer, esdi_callback, esdi, 0); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index f92301415..f70dd7db7 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -52,7 +52,7 @@ * however, are auto-configured by the system software as * shown above. * - * Version: @(#)hdc_esdi_mca.c 1.0.13 2018/04/29 + * Version: @(#)hdc_esdi_mca.c 1.0.14 2018/10/17 * * Authors: Sarah Walker, * Fred N. van Kempen, @@ -90,7 +90,7 @@ #define BIOS_FILE_H L"roms/hdd/esdi/90x8970.bin" -#define ESDI_TIME (200LL*TIMER_USEC) +#define ESDI_TIME (200*TIMER_USEC) #define CMD_ADAPTER 0 @@ -134,7 +134,8 @@ typedef struct esdi { int cmd_state; int in_reset; - int64_t callback; + uint64_t callback; + pc_timer_t timer; uint32_t rba; @@ -188,6 +189,8 @@ typedef struct esdi { #define CMD_GET_DEV_STATUS 0x08 #define CMD_GET_DEV_CONFIG 0x09 #define CMD_GET_POS_INFO 0x0a +#define CMD_FORMAT_UNIT 0x16 +#define CMD_FORMAT_PREPARE 0x17 #define STATUS_LEN(x) ((x) << 8) #define STATUS_DEVICE(x) ((x) << 5) @@ -196,13 +199,11 @@ typedef struct esdi { #ifdef ENABLE_ESDI_MCA_LOG int esdi_mca_do_log = ENABLE_ESDI_MCA_LOG; -#endif static void esdi_mca_log(const char *fmt, ...) { -#ifdef ENABLE_ESDI_MCA_LOG va_list ap; if (esdi_mca_do_log) { @@ -210,8 +211,10 @@ esdi_mca_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define esdi_mca_log(fmt, ...) +#endif static __inline void @@ -228,6 +231,21 @@ clear_irq(esdi_t *dev) picintc(1 << 14); } +static void +esdi_mca_set_callback(esdi_t *dev, uint64_t callback) +{ + if (!dev) { + return; + } + + if (callback) { + dev->callback = callback; + timer_set_delay_u64(&dev->timer, dev->callback); + } else { + dev->callback = 0; + timer_disable(&dev->timer); + } +} static void @@ -339,7 +357,7 @@ esdi_callback(void *priv) drive_t *drive; int val; - dev->callback = 0LL; + esdi_mca_set_callback(dev, 0); /* If we are returning from a RESET, handle this first. */ if (dev->in_reset) { @@ -377,13 +395,13 @@ esdi_callback(void *priv) set_irq(dev); dev->cmd_state = 1; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; case 1: if (!(dev->basic_ctrl & CTRL_DMA_ENA)) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -399,7 +417,7 @@ esdi_callback(void *priv) val = dma_channel_write(dev->dma, dev->data[dev->data_pos]); if (val == DMA_NODATA) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -413,7 +431,7 @@ esdi_callback(void *priv) dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); break; case 2: @@ -452,13 +470,13 @@ esdi_callback(void *priv) set_irq(dev); dev->cmd_state = 1; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; case 1: if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -467,7 +485,7 @@ esdi_callback(void *priv) val = dma_channel_read(dev->dma); if (val == DMA_NODATA) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -487,7 +505,7 @@ esdi_callback(void *priv) dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); break; case 2: @@ -630,13 +648,13 @@ esdi_callback(void *priv) set_irq(dev); dev->cmd_state = 1; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; case 1: if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } while (dev->sector_pos < dev->sector_count) { @@ -644,7 +662,7 @@ esdi_callback(void *priv) val = dma_channel_read(dev->dma); if (val == DMA_NODATA) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -657,7 +675,7 @@ esdi_callback(void *priv) dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); break; case 2: @@ -684,13 +702,13 @@ esdi_callback(void *priv) set_irq(dev); dev->cmd_state = 1; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; case 1: if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -701,7 +719,7 @@ esdi_callback(void *priv) val = dma_channel_write(dev->dma, dev->data[dev->data_pos]); if (val == DMA_NODATA) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -713,7 +731,7 @@ esdi_callback(void *priv) dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); break; case 2: @@ -740,6 +758,59 @@ esdi_callback(void *priv) set_irq(dev); break; + case CMD_FORMAT_UNIT: + case CMD_FORMAT_PREPARE: + ESDI_DRIVE_ONLY(); + + if (! drive->present) { + device_not_present(dev); + return; + } + + switch (dev->cmd_state) { + case 0: + dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff; + + dev->sector_count = dev->cmd_data[1]; + + if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) { + rba_out_of_range(dev); + return; + } + + dev->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + dev->irq_status = dev->cmd_dev | IRQ_DATA_TRANSFER_READY; + dev->irq_in_progress = 1; + set_irq(dev); + + dev->cmd_state = 1; + esdi_mca_set_callback(dev, ESDI_TIME); + break; + + case 1: + if (!(dev->basic_ctrl & CTRL_DMA_ENA)) { + esdi_mca_set_callback(dev, ESDI_TIME); + return; + } + + hdd_image_zero(drive->hdd_num, dev->rba, dev->sector_count); + ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1); + + dev->status = STATUS_CMD_IN_PROGRESS; + dev->cmd_state = 2; + esdi_mca_set_callback(dev, ESDI_TIME); + break; + + case 2: + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + } + break; + default: fatal("BAD COMMAND %02x %i\n", dev->command, dev->cmd_dev); } @@ -781,7 +852,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case 2: /*Basic control register*/ if ((dev->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) { dev->in_reset = 1; - dev->callback = ESDI_TIME * 50LL; + esdi_mca_set_callback(dev, ESDI_TIME * 50); dev->status = STATUS_BUSY; } dev->basic_ctrl = val; @@ -812,7 +883,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case ATTN_RESET: dev->in_reset = 1; - dev->callback = ESDI_TIME * 50LL; + esdi_mca_set_callback(dev, ESDI_TIME * 50); dev->status = STATUS_BUSY; break; @@ -923,7 +994,7 @@ esdi_writew(uint16_t port, uint16_t val, void *priv) if ((dev->cmd_data[0] & CMD_DEVICE_SEL) != dev->cmd_dev) fatal("Command device mismatch with attn\n"); dev->command = dev->cmd_data[0] & CMD_MASK; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->status = STATUS_BUSY; dev->data_pos = 0; } @@ -1007,6 +1078,15 @@ esdi_mca_write(int port, uint8_t val, void *priv) } +static uint8_t +esdi_mca_feedb(void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + + return (dev->pos_regs[2] & 1); +} + + static void * esdi_init(const device_t *info) { @@ -1059,15 +1139,15 @@ esdi_init(const device_t *info) dev->pos_regs[1] = 0xdd; /* Enable the device. */ - mca_add(esdi_mca_read, esdi_mca_write, dev); + mca_add(esdi_mca_read, esdi_mca_write, esdi_mca_feedb, dev); /* Mark for a reset. */ dev->in_reset = 1; - dev->callback = ESDI_TIME * 50LL; + esdi_mca_set_callback(dev, ESDI_TIME * 50); dev->status = STATUS_BUSY; /* Set the reply timer. */ - timer_add(esdi_callback, &dev->callback, &dev->callback, dev); + timer_add(&dev->timer, esdi_callback, dev, 0); return(dev); } diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 8ed9d188e..a9d1e8e59 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,13 +9,13 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.47 2018/06/02 + * Version: @(#)hdc_ide.c 1.0.65 2019/11/19 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #define __USE_LARGEFILE64 #define _LARGEFILE_SOURCE @@ -38,7 +38,7 @@ #include "../rom.h" #include "../timer.h" #include "../device.h" -#include "../scsi/scsi.h" +#include "../scsi/scsi_device.h" #include "../cdrom/cdrom.h" #include "../plat.h" #include "../ui.h" @@ -109,63 +109,40 @@ #define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd #define FEATURE_DISABLE_IRQ_SERVICE 0xde -#if 0 -/* In the future, there's going to be just the IDE_ATAPI type, - leaving it to the common ATAPI/SCSI device handler to know - what type the device is. */ -enum -{ - IDE_NONE = 0, - IDE_HDD, - IDE_ATAPI -}; -#else -enum -{ - IDE_NONE = 0, - IDE_HDD, - IDE_CDROM, - IDE_ZIP -}; -#endif - -#define IDE_PCI (PCI && (romset != ROM_PB640)) +#define IDE_TIME 10.0 typedef struct { - int bit32, cur_dev, - irq; - int64_t callback; + int bit32, cur_dev, + irq, inited, + diag; + uint16_t base_main, side_main; + pc_timer_t timer; } ide_board_t; -static ide_board_t *ide_boards[4]; +typedef struct { + int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv); + void (*set_irq)(int channel, void *priv); + void *priv; +} ide_bm_t; -ide_t *ide_drives[IDE_NUM]; -int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); -int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); -void (*ide_bus_master_set_irq)(int channel, void *priv); -void *ide_bus_master_priv[2]; -int ide_inited = 0; +static ide_board_t *ide_boards[4] = { NULL, NULL, NULL, NULL }; +static ide_bm_t *ide_bm[4] = { NULL, NULL, NULL, NULL }; + +static ide_t *ide_drives[IDE_NUM]; int ide_ter_enabled = 0, ide_qua_enabled = 0; -static uint16_t ide_base_main[4] = { 0x1f0, 0x170, 0x168, 0x1e8 }; -static uint16_t ide_side_main[4] = { 0x3f6, 0x376, 0x36e, 0x3ee }; - +static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); -#define IDE_TIME (20LL * TIMER_USEC) / 3LL - - #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; -#endif static void ide_log(const char *fmt, ...) { -#ifdef ENABLE_IDE_LOG va_list ap; if (ide_do_log) { @@ -173,8 +150,10 @@ ide_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define ide_log(fmt, ...) +#endif uint8_t @@ -183,73 +162,85 @@ getstat(ide_t *ide) { } -int64_t +ide_t * +ide_get_drive(int ch) +{ + if (ch >= 8) + return NULL; + + return ide_drives[ch]; +} + + +double ide_get_period(ide_t *ide, int size) { - double period = 10.0 / 3.0; + double period = (10.0 / 3.0); + /* We assume that 1 MB = 1000000 B in this case, so we have as + many B/us as there are MB/s because 1 s = 1000000 us. */ switch(ide->mdma_mode & 0x300) { case 0x000: /* PIO */ switch(ide->mdma_mode & 0xff) { case 0: - period = 10.0 / 3.0; + period = (10.0 / 3.0); break; case 1: - period = (period * 600.0) / 383.0; + period = (20.0 / 3.83); break; case 2: - period = 25.0 / 3.0; + period = (25.0 / 3.0); break; case 3: - period = 100.0 / 9.0; + period = (100.0 / 9.0); break; case 4: - period = 50.0 / 3.0; + period = (50.0 / 3.0); break; } break; case 0x100: /* Single Word DMA */ switch(ide->mdma_mode & 0xff) { case 0: - period = 25.0 / 12.0; + period = (25.0 / 12.0); break; case 1: - period = 25.0 / 6.0; + period = (25.0 / 6.0); break; case 2: - period = 25.0 / 3.0; + period = (25.0 / 3.0); break; } break; case 0x200: /* Multiword DMA */ switch(ide->mdma_mode & 0xff) { case 0: - period = 25.0 / 6.0; + period = (25.0 / 6.0); break; case 1: - period = 40.0 / 3.0; + period = (40.0 / 3.0); break; case 2: - period = 50.0 / 3.0; + period = (50.0 / 3.0); break; } break; case 0x300: /* Ultra DMA */ switch(ide->mdma_mode & 0xff) { case 0: - period = 50.0 / 3.0; + period = (50.0 / 3.0); break; case 1: period = 25.0; break; case 2: - period = 100.0 / 3.0; + period = (100.0 / 3.0); break; case 3: - period = 400.0 / 9.0; + period = (400.0 / 9.0); break; case 4: - period = 200.0 / 3.0; + period = (200.0 / 3.0); break; case 5: period = 100.0; @@ -258,77 +249,26 @@ ide_get_period(ide_t *ide, int size) break; } - period *= 1048576.0; /* period * MB */ - period = 1000000.0 / period; - period *= (double) TIMER_USEC; - period *= (double) size; - return (int64_t) period; + period = (10.0 / 3.0); + + period = (1.0 / period); /* get us for 1 byte */ + return period * ((double) size); /* multiply by bytes to get period for the entire transfer */ } -#if 0 -int64_t -ide_get_seek_time(ide_t *ide, uint32_t new_pos) +double +ide_atapi_get_period(uint8_t channel) { - double dusec, time; - uint32_t pos = hdd_image_get_pos(ide->hdd_num); - uint32_t t, nt; - t = pos / ide->spt; - nt = new_pos / ide->spt; + ide_t *ide = ide_drives[channel]; + + ide_log("ide_atapi_get_period(%i)\n", channel); - dusec = (double) TIMER_USEC; - time = (1000000.0 / 2800.0) * dusec; /* Revolution (1/2800 s). */ - - if ((t % ide->hpc) != (pos % ide->hpc)) /* Head change. */ - time += (dusec / 250.0); /* 4ns */ - - t /= ide->hpc; - nt /= ide->hpc; - - if (t != nt) { - t = ABS(t - nt); - time += ((40000.0 * dusec) / ((double) ide->tracks)) * ((double) t); + if (!ide) { + ide_log("Get period failed\n"); + return -1.0; } - return (int64_t) time; -} -#endif - -int -ide_drive_is_cdrom(ide_t *ide) -{ - int ch = ide->channel; - - if (ch >= 8) - return 0; - - if (atapi_cdrom_drives[ch] >= CDROM_NUM) - return 0; - else { - if (cdrom_drives[atapi_cdrom_drives[ch]].bus_type == CDROM_BUS_ATAPI) - return 1; - else - return 0; - } -} - - -int -ide_drive_is_zip(ide_t *ide) -{ - int ch = ide->channel; - - if (ch >= 8) - return 0; - - if (atapi_zip_drives[ch] >= ZIP_NUM) - return 0; - else { - if (zip_drives[atapi_zip_drives[ch]].bus_type == ZIP_BUS_ATAPI) - return 1; - else - return 0; - } + return ide_get_period(ide, 1); } @@ -340,15 +280,15 @@ ide_irq_raise(ide_t *ide) /* ide_log("Raising IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ - if (!(ide->fdisk & 2) && (ide_boards[ide->board]->irq != -1)) { - if ((ide->board < 2) && ide_bus_master_set_irq) - ide_bus_master_set_irq(ide->board | 0x40, ide_bus_master_priv[ide->board]); - else + if (!(ide->fdisk & 2)) { + if (ide_bm[ide->board] && ide_bm[ide->board]->set_irq) + ide_bm[ide->board]->set_irq(ide->board | 0x40, ide_bm[ide->board]->priv); + else if (ide_boards[ide->board]->irq != -1) picint(1 << ide_boards[ide->board]->irq); } - ide->irqstat=1; - ide->service=1; + ide->irqstat = 1; + ide->service = 1; } @@ -360,14 +300,39 @@ ide_irq_lower(ide_t *ide) /* ide_log("Lowering IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ - if ((ide_boards[ide->board]->irq != -1) && ide->irqstat) { - if ((ide->board < 2) && ide_bus_master_set_irq) - ide_bus_master_set_irq(ide->board, ide_bus_master_priv[ide->board]); - else + if (ide->irqstat) { + if (ide_bm[ide->board] && ide_bm[ide->board]->set_irq) + ide_bm[ide->board]->set_irq(ide->board, ide_bm[ide->board]->priv); + else if (ide_boards[ide->board]->irq != -1) picintc(1 << ide_boards[ide->board]->irq); } - ide->irqstat=0; + ide->irqstat = 0; +} + + +static void +ide_irq_update(ide_t *ide) +{ + if (!ide_boards[ide->board]) + return; + + /* ide_log("Raising IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ + + if (!(ide->fdisk & 2) && ide->irqstat) { + if (ide_bm[ide->board] && ide_bm[ide->board]->set_irq) { + ide_bm[ide->board]->set_irq(ide->board, ide_bm[ide->board]->priv); + ide_bm[ide->board]->set_irq(ide->board | 0x40, ide_bm[ide->board]->priv); + } else if (ide_boards[ide->board]->irq != -1) { + picintc(1 << ide_boards[ide->board]->irq); + picint(1 << ide_boards[ide->board]->irq); + } + } else if (ide->fdisk & 2) { + if (ide_bm[ide->board] && ide_bm[ide->board]->set_irq) + ide_bm[ide->board]->set_irq(ide->board, ide_bm[ide->board]->priv); + else if (ide_boards[ide->board]->irq != -1) + picintc(1 << ide_boards[ide->board]->irq); + } } @@ -380,7 +345,7 @@ ide_irq_lower(ide_t *ide) * @param len Length of destination buffer to fill in. Strings shorter than * this length will be padded with spaces. */ -static void +void ide_padstr(char *str, const char *src, int len) { int i, v; @@ -417,56 +382,33 @@ void ide_padstr8(uint8_t *buf, int buf_size, const char *src) } -/* Type: - 0 = PIO, - 1 = SDMA, - 2 = MDMA, - 3 = UDMA - Return: - -1 = Not supported, - Anything else = maximum mode - - This will eventually be hookable. */ -enum { - TYPE_PIO = 0, - TYPE_SDMA, - TYPE_MDMA, - TYPE_UDMA -}; - static int ide_get_max(ide_t *ide, int type) { + if (ide->type == IDE_ATAPI) + return ide->get_max(ide_bm[ide->board] != NULL, type); + switch(type) { case TYPE_PIO: /* PIO */ - if (!IDE_PCI || (ide->board >= 2)) - return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ - else { - if (ide_drive_is_zip(ide)) - return 3; - else - return 4; - } - break; + if (ide_bm[ide->board] != NULL) + return 1; + + return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ case TYPE_SDMA: /* SDMA */ - if (!IDE_PCI || (ide->board >= 2) || ide_drive_is_zip(ide)) - return -1; - else + if (ide_bm[ide->board] != NULL) return 2; + + return -1; case TYPE_MDMA: /* MDMA */ - if (!IDE_PCI || (ide->board >= 2)) - return -1; - else { - if (ide_drive_is_zip(ide)) - return 1; - else - return 2; - } - case TYPE_UDMA: /* UDMA */ - if (!IDE_PCI || (ide->board >= 2)) - return -1; - else + if (ide_bm[ide->board] != NULL) return 2; + + return -1; + case TYPE_UDMA: /* UDMA */ + if (ide_bm[ide->board] != NULL) + return 2; + + return -1; default: fatal("Unknown transfer type: %i\n", type); return -1; @@ -474,51 +416,25 @@ ide_get_max(ide_t *ide, int type) } -/* Return: - 0 = Not supported, - Anything else = timings - - This will eventually be hookable. */ -enum { - TIMINGS_DMA = 0, - TIMINGS_PIO, - TIMINGS_PIO_FC -}; - static int ide_get_timings(ide_t *ide, int type) { + if (ide->type == IDE_ATAPI) + return ide->get_timings(ide_bm[ide->board] != NULL, type); + switch(type) { case TIMINGS_DMA: - if (!IDE_PCI || (ide->board >= 2)) - return 0; - else { - if (ide_drive_is_zip(ide)) - return 0x96; - else - return 120; - } - break; + if (ide_bm[ide->board] != NULL) + return 120; + + return 0; case TIMINGS_PIO: - if (!IDE_PCI || (ide->board >= 2)) - return 0; - else { - if (ide_drive_is_zip(ide)) - return 0xb4; - else - return 120; - } - break; + if (ide_bm[ide->board] != NULL) + return 120; + + return 0; case TIMINGS_PIO_FC: - if (!IDE_PCI || (ide->board >= 2)) - return 0; - else { - if (ide_drive_is_zip(ide)) - return 0xb4; - else - return 0; - } - break; + return 0; default: fatal("Unknown transfer type: %i\n", type); return 0; @@ -609,7 +525,7 @@ static void ide_hd_identify(ide_t *ide) ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); } - if (IDE_PCI && (ide->board < 2)) { + if (ide_bm[ide->board]) { ide->buffer[47] = 32 | 0x8000; /*Max sectors on multiple transfer command*/ ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ @@ -620,81 +536,6 @@ static void ide_hd_identify(ide_t *ide) } -/** - * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command - */ -static void -ide_atapi_cdrom_identify(ide_t *ide) -{ - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; - - uint8_t cdrom_id; - - cdrom_id = atapi_cdrom_drives[ide->channel]; - - device_identify[7] = cdrom_id + 0x30; - ide_log("ATAPI Identify: %s\n", device_identify); - - 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 */ -#if 0 - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ -#else - ide_padstr((char *) (ide->buffer + 23), "4.20 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:273 ", 40); /* Model */ -#endif - ide->buffer[49] = 0x200; /* LBA supported */ - ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ - - if (IDE_PCI && (ide->board < 2)) { - ide->buffer[71] = 30; - ide->buffer[72] = 30; - } -} - - -static void -ide_atapi_zip_100_identify(ide_t *ide) -{ - ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ -} - - -static void -ide_atapi_zip_250_identify(ide_t *ide) -{ - ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ - - if (IDE_PCI && (ide->board < 2)) { - ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ - ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ - } -} - - -static void -ide_atapi_zip_identify(ide_t *ide) -{ - uint8_t zip_id; - - zip_id = atapi_zip_drives[ide->channel]; - - /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive - as a LS-120. */ - ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide->buffer[49] = 0x200; /* LBA supported */ - ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ - - if (zip_drives[zip_id].is_250) - ide_atapi_zip_250_identify(ide); - else - ide_atapi_zip_100_identify(ide); -} - static void ide_identify(ide_t *ide) { @@ -704,10 +545,8 @@ ide_identify(ide_t *ide) memset(ide->buffer, 0, 512); - if (ide_drive_is_cdrom(ide)) - ide_atapi_cdrom_identify(ide); - else if (ide_drive_is_zip(ide)) - ide_atapi_zip_identify(ide); + if (ide->type == IDE_ATAPI) + ide->identify(ide, ide_bm[ide->board] != NULL); else if (ide->type != IDE_NONE) ide_hd_identify(ide); else { @@ -719,11 +558,13 @@ ide_identify(ide_t *ide) max_sdma = ide_get_max(ide, TYPE_SDMA); max_mdma = ide_get_max(ide, TYPE_MDMA); max_udma = ide_get_max(ide, TYPE_UDMA); + ide_log("IDE %i: max_pio = %i, max_sdma = %i, max_mdma = %i, max_udma = %i\n", + ide->channel, max_pio, max_sdma, max_mdma, max_udma); if (ide_boards[ide->board]->bit32) ide->buffer[48] |= 1; /*Dword transfers supported*/ ide->buffer[51] = ide_get_timings(ide, TIMINGS_PIO); - ide->buffer[53] &= 0x0006; + ide->buffer[53] &= 0xfff9; ide->buffer[52] = ide->buffer[62] = ide->buffer[63] = ide->buffer[64] = 0x0000; ide->buffer[65] = ide->buffer[66] = ide->buffer[67] = ide->buffer[68] = 0x0000; ide->buffer[88] = 0x0000; @@ -837,23 +678,17 @@ loadhd(ide_t *ide, int d, const wchar_t *fn) void ide_set_signature(ide_t *ide) { - uint8_t cdrom_id = atapi_cdrom_drives[ide->channel]; - uint8_t zip_id = atapi_zip_drives[ide->channel]; - ide->sector=1; ide->head=0; - if (ide_drive_is_zip(ide)) { - zip_set_signature(zip[zip_id]); - ide->secount = zip[zip_id]->phase; - ide->cylinder = zip[zip_id]->request_length; - } else if (ide_drive_is_cdrom(ide)) { - cdrom_set_signature(cdrom[cdrom_id]); - ide->secount = cdrom[cdrom_id]->phase; - ide->cylinder = cdrom[cdrom_id]->request_length; + if (ide->type == IDE_ATAPI) { + ide->sc->phase = 1; + ide->sc->request_length = 0xEB14; + ide->secount = ide->sc->phase; + ide->cylinder = ide->sc->request_length; } else { - ide->secount=1; - ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF); + ide->secount = 1; + ide->cylinder = ((ide->type == IDE_HDD) ? 0 : 0xFFFF); if (ide->type == IDE_HDD) ide->drive = 0; } @@ -969,7 +804,8 @@ static void ide_zero(int d) { ide_t *dev; - ide_drives[d] = (ide_t *) malloc(sizeof(ide_t)); + if (ide_drives[d] == NULL) + ide_drives[d] = (ide_t *) malloc(sizeof(ide_t)); memset(ide_drives[d], 0, sizeof(ide_t)); dev = ide_drives[d]; dev->channel = d; @@ -981,106 +817,32 @@ ide_zero(int d) } -static void -ide_board_close(int board) +void +ide_allocate_buffer(ide_t *dev) { - ide_t *dev; - int c, d; - - /* Close hard disk image files (if previously open) */ - for (d = 0; d < 2; d++) { - c = (board << 1) + d; - dev = ide_drives[c]; - - if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) - hdd_image_close(dev->hdd_num); - - if (board < 4) { - if (ide_drive_is_zip(dev)) - zip[atapi_zip_drives[c]]->status = DRDY_STAT | DSC_STAT; - else if (ide_drive_is_cdrom(dev)) - cdrom[atapi_cdrom_drives[c]]->status = DRDY_STAT | DSC_STAT; - } - - if (dev->buffer) - free(dev->buffer); - - if (dev->sector_buffer) - free(dev->sector_buffer); - - if (dev) - free(dev); - } -} - - -static void -ide_board_init(int board) -{ - ide_t *dev; - int c, d; - int max, ch; - int is_ide, valid_ch; - int min_ch, max_ch; - - min_ch = (board << 1); - max_ch = min_ch + 1; - - ide_log("IDE: board %i: loading disks...\n", board); - for (d = 0; d < 2; d++) { - c = (board << 1) + d; - ide_zero(c); - } - - c = 0; - for (d = 0; d < HDD_NUM; d++) { - is_ide = (hdd[d].bus == HDD_BUS_IDE); - ch = hdd[d].ide_channel; - - if (board == 4) { - valid_ch = ((ch >= 0) && (ch <= 1)); - ch |= 8; - } else - valid_ch = ((ch >= min_ch) && (ch <= max_ch)); - - if (is_ide && valid_ch) { - ide_log("Found IDE hard disk on channel %i\n", ch); - loadhd(ide_drives[ch], d, hdd[d].fn); - ide_drives[ch]->sector_buffer = (uint8_t *) malloc(256*512); - memset(ide_drives[ch]->sector_buffer, 0, 256*512); - if (++c >= 2) break; - } - } - ide_log("IDE: board %i: done, loaded %d disks.\n", board, c); - - for (d = 0; d < 2; d++) { - c = (board << 1) + d; - dev = ide_drives[c]; - - if (board < 4) { - if (ide_drive_is_zip(dev) && (dev->type == IDE_NONE)) - dev->type = IDE_ZIP; - else if (ide_drive_is_cdrom(dev) && (dev->type == IDE_NONE)) - dev->type = IDE_CDROM; - } - - if (dev->type != IDE_NONE) { - dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); - memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); - } - - ide_set_signature(dev); - - max = ide_get_max(dev, TYPE_PIO); - dev->mdma_mode = (1 << max); - dev->error = 1; - dev->cfg_spt = dev->cfg_hpc = 0; - } + if (dev->buffer == NULL) + dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); + memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); } void -ide_set_callback(uint8_t board, int64_t callback) +ide_atapi_attach(ide_t *ide) +{ + if (ide->type != IDE_NONE) + return; + + ide->type = IDE_ATAPI; + ide_allocate_buffer(ide); + ide_set_signature(ide); + ide->mdma_mode = (1 << ide->get_max(!ide_bm[ide->board], TYPE_PIO)); + ide->error = 1; + ide->cfg_spt = ide->cfg_hpc = 0; +} + + +void +ide_set_callback(uint8_t board, double callback) { ide_board_t *dev = ide_boards[board]; @@ -1091,18 +853,257 @@ ide_set_callback(uint8_t board, int64_t callback) return; } - if (callback) - dev->callback = callback; + if (callback == 0.0) + timer_stop(&dev->timer); else - dev->callback = 0LL; + timer_on_auto(&dev->timer, callback); +} + + +static void +ide_atapi_command_bus(ide_t *ide) +{ + ide->sc->status = BUSY_STAT; + ide->sc->phase = 1; + ide->sc->pos = 0; + ide->sc->callback = 1.0 * IDE_TIME; + ide_set_callback(ide->board, ide->sc->callback); +} + + +static void +ide_atapi_callback(ide_t *ide) +{ + int out, ret = 0; + + switch(ide->sc->packet_status) { + case PHASE_IDLE: + ide->sc->pos = 0; + ide->sc->phase = 1; + ide->sc->status = READY_STAT | DRQ_STAT | (ide->sc->status & ERR_STAT); + return; + case PHASE_COMMAND: + ide->sc->status = BUSY_STAT | (ide->sc->status & ERR_STAT); + if (ide->packet_command) { + ide->packet_command(ide->sc, ide->sc->atapi_cdb); + if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); + } + return; + case PHASE_COMPLETE: + ide->sc->status = READY_STAT; + ide->sc->phase = 3; + ide->sc->packet_status = PHASE_NONE; + ide_irq_raise(ide); + return; + case PHASE_DATA_IN: + case PHASE_DATA_OUT: + ide->sc->status = READY_STAT | DRQ_STAT | (ide->sc->status & ERR_STAT); + ide->sc->phase = !(ide->sc->packet_status & 0x01) << 1; + ide_irq_raise(ide); + return; + case PHASE_DATA_IN_DMA: + case PHASE_DATA_OUT_DMA: + out = (ide->sc->packet_status & 0x01); + + if (ide_bm[ide->board] && ide_bm[ide->board]->dma) { + ret = ide_bm[ide->board]->dma(ide->board, + ide->sc->temp_buffer, ide->sc->packet_len, + out, ide_bm[ide->board]->priv); + } else { + /* DMA command without a bus master. */ + if (ide->bus_master_error) + ide->bus_master_error(ide->sc); + return; + } + + if (ret == 0) { + if (ide->bus_master_error) + ide->bus_master_error(ide->sc); + } else if (ret == 1) { + if (out && ide->phase_data_out) + ret = ide->phase_data_out(ide->sc); + else if (!out && ide->command_stop) + ide->command_stop(ide->sc); + + if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); + } else if (ret == 2) + ide_atapi_command_bus(ide); + + return; + case PHASE_ERROR: + ide->sc->status = READY_STAT | ERR_STAT; + ide->sc->phase = 3; + ide->sc->packet_status = PHASE_NONE; + ide_irq_raise(ide); + return; + } +} + + +/* This is the general ATAPI PIO request function. */ +static void +ide_atapi_pio_request(ide_t *ide, uint8_t out) +{ + scsi_common_t *dev = ide->sc; + + ide_irq_lower(ide_drives[ide->board]); + + dev->status = BSY_STAT; + + if (dev->pos >= dev->packet_len) { + ide_log("%i bytes %s, command done\n", dev->pos, out ? "written" : "read"); + + dev->pos = dev->request_pos = 0; + if (out && ide->phase_data_out) + ide->phase_data_out(dev); + else if (!out && ide->command_stop) + ide->command_stop(dev); + + if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); + } else { + ide_log("%i bytes %s, %i bytes are still left\n", dev->pos, + out ? "written" : "read", dev->packet_len - dev->pos); + + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) { + dev->max_transfer_len = dev->packet_len - dev->pos; + /* Also update the request length so the host knows how many bytes to transfer. */ + dev->request_length = dev->max_transfer_len; + } + ide_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, + dev->max_transfer_len); + + dev->packet_status = PHASE_DATA_IN | out; + + dev->status = BSY_STAT; + dev->phase = 1; + ide_atapi_callback(ide); + ide_set_callback(ide->board >> 1, 0.0); + + dev->request_pos = 0; + } +} + + +static uint32_t +ide_atapi_packet_read(ide_t *ide, int length) +{ + scsi_common_t *dev = ide->sc; + + uint16_t *bufferw; + uint32_t *bufferl; + + uint32_t temp = 0; + + if (!dev || !dev->temp_buffer || (dev->packet_status != PHASE_DATA_IN)) + return 0; + + bufferw = (uint16_t *) dev->temp_buffer; + bufferl = (uint32_t *) dev->temp_buffer; + + /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, + which can happen when issuing media access commands with an allocated length below minimum request length + (which is 1 sector = 2048 bytes). */ + switch(length) { + case 1: + temp = (dev->pos < dev->packet_len) ? dev->temp_buffer[dev->pos] : 0; + dev->pos++; + dev->request_pos++; + break; + case 2: + temp = (dev->pos < dev->packet_len) ? bufferw[dev->pos >> 1] : 0; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + temp = (dev->pos < dev->packet_len) ? bufferl[dev->pos >> 2] : 0; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return 0; + } + + if (dev->packet_status == PHASE_DATA_IN) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + ide_atapi_pio_request(ide, 0); + } + return temp; + } else + return 0; +} + + +static void +ide_atapi_packet_write(ide_t *ide, uint32_t val, int length) +{ + scsi_common_t *dev = ide->sc; + + uint8_t *bufferb; + uint16_t *bufferw; + uint32_t *bufferl; + + if (!dev) + return; + + if (dev->packet_status == PHASE_IDLE) + bufferb = dev->atapi_cdb; + else { + if (dev->temp_buffer) + bufferb = dev->temp_buffer; + else + return; + } + + bufferw = (uint16_t *) bufferb; + bufferl = (uint32_t *) bufferb; + + switch(length) { + case 1: + bufferb[dev->pos] = val & 0xff; + dev->pos++; + dev->request_pos++; + break; + case 2: + bufferw[dev->pos >> 1] = val & 0xffff; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + bufferl[dev->pos >> 2] = val; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return; + } + + if (dev->packet_status == PHASE_DATA_OUT) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + ide_atapi_pio_request(ide, 1); + } + return; + } else if (dev->packet_status == PHASE_IDLE) { + if (dev->pos >= 12) { + dev->pos = 0; + dev->status = BSY_STAT; + dev->packet_status = PHASE_COMMAND; + ide_atapi_callback(ide); + } + return; + } } void ide_write_data(ide_t *ide, uint32_t val, int length) { - int ch = ide->channel; - uint8_t *idebufferb = (uint8_t *) ide->buffer; uint16_t *idebufferw = ide->buffer; uint32_t *idebufferl = (uint32_t *) ide->buffer; @@ -1110,14 +1111,8 @@ ide_write_data(ide_t *ide, uint32_t val, int length) if (ide->command == WIN_PACKETCMD) { ide->pos = 0; - if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) - return; - - if (ide_drive_is_zip(ide)) - zip_write(ch, val, length); - else - cdrom_write(ch, val, length); - return; + if (ide->type == IDE_ATAPI) + ide_atapi_packet_write(ide, val, length); } else { switch(length) { case 1: @@ -1136,15 +1131,13 @@ ide_write_data(ide_t *ide, uint32_t val, int length) return; } - if (ide->pos>=512) { + if (ide->pos >= 512) { ide->pos=0; ide->atastat = BSY_STAT; - timer_process(); if (ide->command == WIN_WRITE_MULTIPLE) ide_callback(ide_boards[ide->board]); else ide_set_callback(ide->board, ide_get_period(ide, 512)); - timer_update_outstanding(); } } } @@ -1203,6 +1196,16 @@ ide_writel(uint16_t addr, uint32_t val, void *priv) } +static void +dev_reset(ide_t *ide) +{ + ide_set_signature(ide); + + if ((ide->type == IDE_ATAPI) && ide->stop) + ide->stop(ide->sc); +} + + void ide_write_devctl(uint16_t addr, uint8_t val, void *priv) { @@ -1210,6 +1213,7 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv) ide_t *ide, *ide_other; int ch; + uint8_t old; ch = dev->cur_dev; ide = ide_drives[ch]; @@ -1217,35 +1221,59 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv) ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); - if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) { - timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 0LL; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; - ide_set_callback(ide->board, 500LL * IDE_TIME); - timer_update_outstanding(); + if ((ide->type == IDE_NONE) && (ide_other->type == IDE_NONE)) + return; - if (ide->type != IDE_NONE) + dev->diag = 0; + + if ((val & 4) && !(ide->fdisk & 4)) { + /* Reset toggled from 0 to 1, initiate reset procedure. */ + if (ide->type == IDE_ATAPI) + ide->sc->callback = 0.0; + ide_set_callback(ide->board, 0.0); + } else if (!(val & 4) && (ide->fdisk & 4)) { + /* Reset toggled from 1 to 0. */ + if (!(ch & 1)) { + /* Currently active device is 0, use the device 0 reset protocol. */ + /* Device 0. */ + dev_reset(ide); + ide->atastat = BSY_STAT; + ide->error = 1; + if (ide->type == IDE_ATAPI) { + ide->sc->status = BSY_STAT; + ide->sc->error = 1; + } + + /* Device 1. */ + dev_reset(ide_other); + ide_other->atastat = BSY_STAT; + ide_other->error = 1; + if (ide_other->type == IDE_ATAPI) { + ide_other->sc->status = BSY_STAT; + ide_other->sc->error = 1; + } + + /* Fire the timer. */ + dev->diag = 0; ide->reset = 1; - if (ide_other->type != IDE_NONE) - ide->reset = 1; - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; - ide->atastat = ide_other->atastat = BSY_STAT; + ide_set_callback(ide->board, 500 * IDE_TIME); + } else { + /* Currently active device is 1, simply reset the status and the active device. */ + dev_reset(ide); + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error = 1; + if (ide->type == IDE_ATAPI) { + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->error = 1; + } + dev->cur_dev &= ~1; + } } - if (val & 4) { - /*Drive held in reset*/ - timer_process(); - ide_set_callback(ide->board, 0LL); - timer_update_outstanding(); - ide->atastat = ide_other->atastat = BSY_STAT; - } + old = ide->fdisk; ide->fdisk = ide_other->fdisk = val; - return; + if (!(val & 0x02) && (old & 0x02) && ide->irqstat) + ide_irq_update(ide); } @@ -1275,38 +1303,27 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ case 0x1: /* Features */ - if (ide_drive_is_zip(ide)) { + if (ide->type == IDE_ATAPI) { ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); - zip[atapi_zip_drives[ch]]->features = val; - } else if (ide_drive_is_cdrom(ide)) { - ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); - cdrom[atapi_cdrom_drives[ch]]->features = val; + ide->sc->features = val; } ide->cylprecomp = val; - if (ide_drive_is_zip(ide_other)) - zip[atapi_zip_drives[ch ^ 1]]->features = val; - else if (ide_drive_is_cdrom(ide_other)) - cdrom[atapi_cdrom_drives[ch ^ 1]]->features = val; + if (ide_other->type == IDE_ATAPI) + ide_other->sc->features = val; ide_other->cylprecomp = val; return; case 0x2: /* Sector count */ - if (ide_drive_is_zip(ide)) { + if (ide->type == IDE_ATAPI) { ide_log("Sector count write: %i\n", val); - zip[atapi_zip_drives[ch]]->phase = val; - } else if (ide_drive_is_cdrom(ide)) { - ide_log("Sector count write: %i\n", val); - cdrom[atapi_cdrom_drives[ch]]->phase = val; + ide->sc->phase = val; } ide->secount = val; - if (ide_drive_is_zip(ide_other)) { + if (ide_other->type == IDE_ATAPI) { ide_log("Other sector count write: %i\n", val); - zip[atapi_zip_drives[ch ^ 1]]->phase = val; - } else if (ide_drive_is_cdrom(ide_other)) { - ide_log("Other sector count write: %i\n", val); - cdrom[atapi_cdrom_drives[ch ^ 1]]->phase = val; + ide_other->sc->phase = val; } ide_other->secount = val; return; @@ -1319,44 +1336,32 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; case 0x4: /* Cylinder low */ - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ch]]->request_length &= 0xFF00; - zip[atapi_zip_drives[ch]]->request_length |= val; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF00; - cdrom[atapi_cdrom_drives[ch]]->request_length |= val; + if (ide->type == IDE_ATAPI) { + ide->sc->request_length &= 0xFF00; + ide->sc->request_length |= val; } ide->cylinder = (ide->cylinder & 0xFF00) | val; ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); - if (ide_drive_is_zip(ide_other)) { - zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF00; - zip[atapi_zip_drives[ch ^ 1]]->request_length |= val; - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF00; - cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= val; + if (ide_other->type == IDE_ATAPI) { + ide_other->sc->request_length &= 0xFF00; + ide_other->sc->request_length |= val; } ide_other->cylinder = (ide_other->cylinder & 0xFF00) | val; ide_other->lba_addr = (ide_other->lba_addr & 0xFFF00FF) | (val << 8); return; case 0x5: /* Cylinder high */ - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ch]]->request_length &= 0xFF; - zip[atapi_zip_drives[ch]]->request_length |= (val << 8); - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF; - cdrom[atapi_cdrom_drives[ch]]->request_length |= (val << 8); + if (ide->type == IDE_ATAPI) { + ide->sc->request_length &= 0xFF; + ide->sc->request_length |= (val << 8); } ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); - if (ide_drive_is_zip(ide_other)) { - zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF; - zip[atapi_zip_drives[ch ^ 1]]->request_length |= (val << 8); - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF; - cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= (val << 8); + if (ide_other->type == IDE_ATAPI) { + ide_other->sc->request_length &= 0xFF; + ide_other->sc->request_length |= (val << 8); } ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); @@ -1376,40 +1381,25 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->cylinder = ide_other->cylinder = 0; ide->reset = ide_other->reset = 0; - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; - zip[atapi_zip_drives[ide->channel]]->error = 1; - zip[atapi_zip_drives[ide->channel]]->phase = 1; - zip[atapi_zip_drives[ide->channel]]->request_length = 0xEB14; - zip[atapi_zip_drives[ide->channel]]->callback = 0LL; - ide->cylinder = 0xEB14; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ide->channel]]->error = 1; - cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; - cdrom[atapi_cdrom_drives[ide->channel]]->request_length = 0xEB14; - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + if (ide->type == IDE_ATAPI) { + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->error = 1; + ide->sc->phase = 1; + ide->sc->request_length = 0xEB14; + ide->sc->callback = 0.0; ide->cylinder = 0xEB14; } - if (ide_drive_is_zip(ide_other)) { - zip[atapi_zip_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; - zip[atapi_zip_drives[ide_other->channel]]->error = 1; - zip[atapi_zip_drives[ide_other->channel]]->phase = 1; - zip[atapi_zip_drives[ide_other->channel]]->request_length = 0xEB14; - zip[atapi_zip_drives[ide_other->channel]]->callback = 0LL; - ide->cylinder = 0xEB14; - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom[atapi_cdrom_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ide_other->channel]]->error = 1; - cdrom[atapi_cdrom_drives[ide_other->channel]]->phase = 1; - cdrom[atapi_cdrom_drives[ide_other->channel]]->request_length = 0xEB14; - cdrom[atapi_cdrom_drives[ide_other->channel]]->callback = 0LL; - ide->cylinder = 0xEB14; + if (ide_other->type == IDE_ATAPI) { + ide_other->sc->status = DRDY_STAT | DSC_STAT; + ide_other->sc->error = 1; + ide_other->sc->phase = 1; + ide_other->sc->request_length = 0xEB14; + ide_other->sc->callback = 0.0; + ide_other->cylinder = 0xEB14; } - ide_set_callback(ide->board, 0LL); - timer_update_outstanding(); + ide_set_callback(ide->board, 0.0); return; } @@ -1423,6 +1413,8 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24); + + ide_irq_update(ide); return; case 0x7: /* Command register */ @@ -1430,48 +1422,33 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; ide_irq_lower(ide); - ide->command=val; + ide->command = val; - ide->error=0; - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->error = 0; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->error = 0; + ide->error = 0; + if (ide->type == IDE_ATAPI) + ide->sc->error = 0; if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) { - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT; + if (ide->type == IDE_ATAPI) + ide->sc->status = DRDY_STAT; else ide->atastat = BSY_STAT; - timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; - ide_set_callback(ide->board, 100LL * IDE_TIME); - timer_update_outstanding(); + if (ide->type == IDE_ATAPI) + ide->sc->callback = 100.0 * IDE_TIME; + ide_set_callback(ide->board, 100.0 * IDE_TIME); return; } switch (val) { case WIN_SRST: /* ATAPI Device Reset */ - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; - else + if (ide->type == IDE_ATAPI) { + ide->sc->status = BSY_STAT; + ide->sc->callback = 100.0 * IDE_TIME; + } else ide->atastat = DRDY_STAT; - timer_process(); - - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; - ide_set_callback(ide->board, 100LL * IDE_TIME); - timer_update_outstanding(); + + ide_set_callback(ide->board, 100.0 * IDE_TIME); return; case WIN_READ_MULTIPLE: @@ -1483,54 +1460,46 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->blockcount = 0; /* Turn on the activity indicator *here* so that it gets turned on less times. */ - /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); case WIN_READ: case WIN_READ_NORETRY: case WIN_READ_DMA: case WIN_READ_DMA_ALT: - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; - else + if (ide->type == IDE_ATAPI) { + ide->sc->status = BSY_STAT; + ide->sc->callback = 200.0 * IDE_TIME; + } else ide->atastat = BSY_STAT; - timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; if (ide->type == IDE_HDD) { if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { if (ide->secount) ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); else ide_set_callback(ide->board, ide_get_period(ide, 131072)); - } else + } else if (val == WIN_READ_MULTIPLE) + ide_set_callback(ide->board, 200.0 * IDE_TIME); + else ide_set_callback(ide->board, ide_get_period(ide, 512)); } else - ide_set_callback(ide->board, 200LL * IDE_TIME); - timer_update_outstanding(); + ide_set_callback(ide->board, 200.0 * IDE_TIME); ide->do_initial_read = 1; return; case WIN_WRITE_MULTIPLE: - if (!ide->blocksize && !ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + if (!ide->blocksize && (ide->type != IDE_ATAPI)) fatal("Write_MULTIPLE - blocksize = 0\n"); ide->blockcount = 0; /* Turn on the activity indicator *here* so that it gets turned on less times. */ - /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); case WIN_WRITE: case WIN_WRITE_NORETRY: - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; - zip[atapi_zip_drives[ide->channel]]->pos = 0; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; - cdrom[atapi_cdrom_drives[ide->channel]]->pos = 0; + if (ide->type == IDE_ATAPI) { + ide->sc->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + ide->sc->pos = 0; } else { ide->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT; ide->pos=0; @@ -1544,18 +1513,12 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_IDENTIFY: /* Identify Device */ case WIN_SET_FEATURES: /* Set Features */ case WIN_READ_NATIVE_MAX: - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; - else + if (ide->type == IDE_ATAPI) { + ide->sc->status = BSY_STAT; + ide->sc->callback = 200.0 * IDE_TIME; + } else ide->atastat = BSY_STAT; - timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; if ((ide->type == IDE_HDD) && ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { if (ide->secount) @@ -1566,12 +1529,11 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) ide_set_callback(ide->board, ide_get_period(ide, 512)); else - ide_set_callback(ide->board, 200LL * IDE_TIME); - timer_update_outstanding(); + ide_set_callback(ide->board, 200.0 * IDE_TIME); return; case WIN_FORMAT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide->type == IDE_ATAPI) goto ide_bad_command; else { ide->atastat = DRQ_STAT; @@ -1580,44 +1542,42 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; case WIN_SPECIFY: /* Initialize Drive Parameters */ - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; - else + if (ide->type == IDE_ATAPI) { + ide->sc->status = BSY_STAT; + ide->sc->callback = 30.0 * IDE_TIME; + } else ide->atastat = BSY_STAT; - timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 30LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 30LL*IDE_TIME; - ide_set_callback(ide->board, 30LL * IDE_TIME); - timer_update_outstanding(); + ide_set_callback(ide->board, 30.0 * IDE_TIME); return; case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; - else - ide->atastat = BSY_STAT; + dev->cur_dev &= ~1; + ide = ide_drives[ch & ~1]; + ide_other = ide_drives[ch | 1]; - if (ide_drive_is_zip(ide_other)) - zip[atapi_zip_drives[ide_other->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide_other)) - cdrom[atapi_cdrom_drives[ide_other->channel]]->status = BSY_STAT; - else - ide_other->atastat = BSY_STAT; + /* Device 0. */ + dev_reset(ide); + ide->atastat = BSY_STAT; + ide->error = 1; + if (ide->type == IDE_ATAPI) { + ide->sc->status = BSY_STAT; + ide->sc->error = 1; + } - timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 200LL * IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL * IDE_TIME; - ide_set_callback(ide->board, 200LL * IDE_TIME); - timer_update_outstanding(); + /* Device 1. */ + dev_reset(ide_other); + ide_other->atastat = BSY_STAT; + ide_other->error = 1; + if (ide_other->type == IDE_ATAPI) { + ide_other->sc->status = BSY_STAT; + ide_other->sc->error = 1; + } + + /* Fire the timer. */ + dev->diag = 1; + ide->reset = 1; + ide_set_callback(ide->board, 200 * IDE_TIME); return; case WIN_PIDENTIFY: /* Identify Packet Device */ @@ -1628,35 +1588,25 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_SETIDLE1: /* Idle */ case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + if (ide->type == IDE_ATAPI) + ide->sc->status = BSY_STAT; else ide->atastat = BSY_STAT; - timer_process(); ide_callback(dev); - timer_update_outstanding(); return; case WIN_PACKETCMD: /* ATAPI Packet */ /* Skip the command callback wait, and process immediately. */ - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ide->channel]]->packet_status = ZIP_PHASE_IDLE; - zip[atapi_zip_drives[ide->channel]]->pos=0; - zip[atapi_zip_drives[ide->channel]]->phase = 1; - zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; - ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ide->channel]]->packet_status = CDROM_PHASE_IDLE; - cdrom[atapi_cdrom_drives[ide->channel]]->pos=0; - cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + if (ide->type == IDE_ATAPI) { + ide->sc->packet_status = PHASE_IDLE; + ide->sc->pos = 0; + ide->sc->phase = 1; + ide->sc->status = DRDY_STAT | DRQ_STAT; + if (ide->interrupt_drq) + ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ } else { ide->atastat = BSY_STAT; - timer_process(); - ide_set_callback(ide->board, 200LL * IDE_TIME); - timer_update_outstanding(); + ide_set_callback(ide->board, 200.0 * IDE_TIME); ide->pos=0; } return; @@ -1664,12 +1614,9 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case 0xF0: default: ide_bad_command: - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; - zip[atapi_zip_drives[ide->channel]]->error = ABRT_ERR; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ide->channel]]->error = ABRT_ERR; + if (ide->type == IDE_ATAPI) { + ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->sc->error = ABRT_ERR; } else { ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; ide->error = ABRT_ERR; @@ -1685,8 +1632,7 @@ ide_bad_command: static uint32_t ide_read_data(ide_t *ide, int length) { - int ch = ide->channel; - uint32_t temp; + uint32_t temp = 0; if (!ide->buffer) { switch (length) { @@ -1707,14 +1653,12 @@ ide_read_data(ide_t *ide, int length) if (ide->command == WIN_PACKETCMD) { ide->pos = 0; - if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) { - ide_log("Drive not ZIP or CD-ROM (position: %i)\n", ide->pos); + if (ide->type == IDE_ATAPI) + temp = ide_atapi_packet_read(ide, length); + else { + ide_log("Drive not ATAPI (position: %i)\n", ide->pos); return 0; } - if (ide_drive_is_zip(ide)) - temp = zip_read(ch, length); - else - temp = cdrom_read(ch, length); } else { switch (length) { case 1: @@ -1733,31 +1677,24 @@ ide_read_data(ide_t *ide, int length) return 0; } } - if (ide->pos>=512 && ide->command != WIN_PACKETCMD) { - ide->pos=0; + if ((ide->pos >= 512) && (ide->command != WIN_PACKETCMD)) { + ide->pos = 0; ide->atastat = DRDY_STAT | DSC_STAT; - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ch]]->status = DRDY_STAT | DSC_STAT; - zip[atapi_zip_drives[ch]]->packet_status = ZIP_PHASE_IDLE; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ch]]->status = DRDY_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ch]]->packet_status = CDROM_PHASE_IDLE; + if (ide->type == IDE_ATAPI) { + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->packet_status = PHASE_IDLE; } - if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) { + 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 = BSY_STAT; - timer_process(); if (ide->command == WIN_READ_MULTIPLE) ide_callback(ide_boards[ide->board]); else ide_set_callback(ide->board, ide_get_period(ide, 512)); - timer_update_outstanding(); - } else { - if (ide->command != WIN_READ_MULTIPLE) - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } + } else if (ide->command != WIN_READ_MULTIPLE) + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); } } @@ -1766,18 +1703,16 @@ ide_read_data(ide_t *ide, int length) static uint8_t -ide_status(ide_t *ide, int ch) +ide_status(ide_t *ide, ide_t *ide_other, int ch) { - if (ide->type == IDE_NONE) - return 0; - else { - if (ide_drive_is_zip(ide)) - return (zip[atapi_zip_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - else if (ide_drive_is_cdrom(ide)) - return (cdrom[atapi_cdrom_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - else - return ide->atastat; - } + if ((ide->type == IDE_NONE) && ((ide_other->type == IDE_NONE) || !(ch & 1))) + return 0x7F; /* Bit 7 pulled down, all other bits pulled up, per the spec. */ + else if ((ide->type == IDE_NONE) && (ch & 1)) + return 0x00; /* On real hardware, a slave with a present master always returns a status of 0x00. */ + else if (ide->type == IDE_ATAPI) + return (ide->sc->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else + return ide->atastat; } @@ -1810,14 +1745,10 @@ ide_readb(uint16_t addr, void *priv) case 0x1: /* Error */ if (ide->type == IDE_NONE) temp = 0; - else { - if (ide_drive_is_zip(ide)) - temp = zip[atapi_zip_drives[ch]]->error; - else if (ide_drive_is_cdrom(ide)) - temp = cdrom[atapi_cdrom_drives[ch]]->error; - else - temp = ide->error; - } + else if (ide->type == IDE_ATAPI) + temp = ide->sc->error; + else + temp = ide->error; break; /* For ATAPI: @@ -1834,42 +1765,32 @@ ide_readb(uint16_t addr, void *priv) 0 1 0 Data from host 1 0 1 Status. */ case 0x2: /* Sector count */ - if (ide_drive_is_zip(ide)) - temp = zip[atapi_zip_drives[ch]]->phase; - else if (ide_drive_is_cdrom(ide)) - temp = cdrom[atapi_cdrom_drives[ch]]->phase; + if (ide->type == IDE_ATAPI) + temp = ide->sc->phase; else temp = ide->secount; break; case 0x3: /* Sector */ - temp = (uint8_t)ide->sector; + temp = (uint8_t) ide->sector; break; case 0x4: /* Cylinder low */ if (ide->type == IDE_NONE) temp = 0xFF; - else { - if (ide_drive_is_zip(ide)) - temp = zip[atapi_zip_drives[ch]]->request_length & 0xff; - else if (ide_drive_is_cdrom(ide)) - temp = cdrom[atapi_cdrom_drives[ch]]->request_length & 0xff; - else - temp = ide->cylinder & 0xff; - } + else if (ide->type == IDE_ATAPI) + temp = ide->sc->request_length & 0xff; + else + temp = ide->cylinder & 0xff; break; case 0x5: /* Cylinder high */ if (ide->type == IDE_NONE) temp = 0xFF; - else { - if (ide_drive_is_zip(ide)) - temp = zip[atapi_zip_drives[ch]]->request_length >> 8; - else if (ide_drive_is_cdrom(ide)) - temp = cdrom[atapi_cdrom_drives[ch]]->request_length >> 8; - else - temp = ide->cylinder >> 8; - } + else if (ide->type == IDE_ATAPI) + temp = ide->sc->request_length >> 8; + else + temp = ide->cylinder >> 8; break; case 0x6: /* Drive/Head */ @@ -1880,7 +1801,7 @@ ide_readb(uint16_t addr, void *priv) DF (drive fault). */ case 0x7: /* Status */ ide_irq_lower(ide); - temp = ide_status(ide, ch); + temp = ide_status(ide, ide_drives[ch ^ 1], ch); break; } @@ -1904,7 +1825,7 @@ ide_read_alt_status(uint16_t addr, void *priv) /* Per the Seagate ATA-3 specification: Reading the alternate status does *NOT* clear the IRQ. */ - temp = ide_status(ide, ch); + temp = ide_status(ide, ide_drives[ch ^ 1], ch); ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", addr, priv, temp); return temp; @@ -1965,9 +1886,7 @@ static void ide_callback(void *priv) { ide_t *ide, *ide_other; - int snum, ret, ch; - int cdrom_id, cdrom_id_other; - int zip_id, zip_id_other; + int snum, ret = 0, ch; ide_board_t *dev = (ide_board_t *) priv; ch = dev->cur_dev; @@ -1975,60 +1894,30 @@ ide_callback(void *priv) ide = ide_drives[ch]; ide_other = ide_drives[ch ^ 1]; - ide_set_callback(ide->board, 0LL); - if (ide->reset) { ide_log("CALLBACK RESET %i %i\n", ide->reset,ch); - ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; - ide->error = ide_other->error = 1; - ide->secount = ide_other->secount = 1; - ide->sector = ide_other->sector = 1; - ide->head = ide_other->head = 0; - ide->cylinder = ide_other->cylinder = 0; + ide->atastat = DRDY_STAT | DSC_STAT; + if (ide->type == IDE_ATAPI) + ide->sc->status = DRDY_STAT | DSC_STAT; - // ide->cfg_spt = ide->cfg_hpc = 0; /* need new parameters (drive 0) */ - // ide_other->cfg_spt = ide_other->cfg_hpc = 0; /* need new parameters (drive 1) */ + ide_other->atastat = DRDY_STAT | DSC_STAT; + if (ide_other->type == IDE_ATAPI) + ide_other->sc->status = DRDY_STAT | DSC_STAT; - ide->reset = ide_other->reset = 0; + dev->cur_dev &= ~1; - ide_set_signature(ide); - if (ide_drive_is_zip(ide)) { - zip_id = atapi_zip_drives[ch]; - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - zip[zip_id]->error = 1; - } else if (ide_drive_is_cdrom(ide)) { - cdrom_id = atapi_cdrom_drives[ch]; - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; - cdrom[cdrom_id]->error = 1; - if (cdrom[cdrom_id]->handler->stop) - cdrom[cdrom_id]->handler->stop(cdrom_id); + if (dev->diag) { + dev->diag = 0; + ide_irq_raise(ide); } - - ide_set_signature(ide_other); - if (ide_drive_is_zip(ide_other)) { - zip_id_other = atapi_zip_drives[ch ^ 1]; - zip[zip_id_other]->status = DRDY_STAT | DSC_STAT; - zip[zip_id_other]->error = 1; - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; - cdrom[cdrom_id_other]->status = DRDY_STAT | DSC_STAT; - cdrom[cdrom_id_other]->error = 1; - if (cdrom[cdrom_id_other]->handler->stop) - cdrom[cdrom_id_other]->handler->stop(cdrom_id_other); - } - + ide->reset = 0; + ide_set_callback(ide->board, 0.0); return; } ide_log("CALLBACK %02X %i %i\n", ide->command, ide->reset,ch); - cdrom_id = atapi_cdrom_drives[ch]; - cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; - - zip_id = atapi_zip_drives[ch]; - zip_id_other = atapi_zip_drives[ch ^ 1]; - if (((ide->command >= WIN_RECAL) && (ide->command <= 0x1F)) || ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F))) { if (ide->type != IDE_HDD) @@ -2055,17 +1944,14 @@ ide_callback(void *priv) ide_set_signature(ide); - if (ide_drive_is_zip(ide)) { - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - zip[zip_id]->error = 1; - zip_reset(zip[zip_id]); - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; - cdrom[cdrom_id]->error = 1; - cdrom_reset(cdrom[cdrom_id]); + if (ide->type == IDE_ATAPI) { + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->error = 1; + if (ide->device_reset) + ide->device_reset(ide->sc); } ide_irq_raise(ide); - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide->type == IDE_ATAPI) ide->service = 0; return; @@ -2073,10 +1959,8 @@ ide_callback(void *priv) case WIN_STANDBYNOW1: case WIN_IDLENOW1: case WIN_SETIDLE1: - if (ide_drive_is_zip(ide)) - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + if (ide->type == IDE_ATAPI) + ide->sc->status = DRDY_STAT | DSC_STAT; else ide->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); @@ -2084,12 +1968,9 @@ ide_callback(void *priv) case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: - if (ide_drive_is_zip(ide)) { - zip[zip_id]->phase = 0xFF; - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->phase = 0xFF; - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + if (ide->type == IDE_ATAPI) { + ide->sc->phase = 0xFF; + ide->sc->status = DRDY_STAT | DSC_STAT; } ide->secount = 0xFF; ide->atastat = DRDY_STAT | DSC_STAT; @@ -2098,7 +1979,7 @@ ide_callback(void *priv) case WIN_READ: case WIN_READ_NORETRY: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) { + if (ide->type == IDE_ATAPI) { ide_set_signature(ide); goto abort_cmd; } @@ -2128,7 +2009,7 @@ ide_callback(void *priv) case WIN_READ_DMA: case WIN_READ_DMA_ALT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + if ((ide->type == IDE_ATAPI) || !ide_bm[ide->board]) { ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel); goto abort_cmd; } @@ -2146,21 +2027,17 @@ ide_callback(void *priv) ide->pos=0; - if (ide_bus_master_read) { + if (ide_bm[ide->board] && ide_bm[ide->board]->dma) { /* We should not abort - we should simply wait for the host to start DMA. */ - ret = ide_bus_master_read(ide->board, - ide->sector_buffer, ide->sector_pos * 512, - ide_bus_master_priv[ide->board]); + ret = ide_bm[ide->board]->dma(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + 0, ide_bm[ide->board]->priv); if (ret == 2) { /* Bus master DMA disabled, simply wait for the host to enable DMA. */ ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide_set_callback(ide->board, 6LL * IDE_TIME); + ide_set_callback(ide->board, 6.0 * IDE_TIME); return; } else if (ret == 1) { - /* Bus master DMAS error, abort the command. */ - ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); - goto abort_cmd; - } else { /*DMA successful*/ ide_log("IDE %i: DMA read successful\n", ide->channel); @@ -2168,6 +2045,10 @@ ide_callback(void *priv) ide_irq_raise(ide); ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } else { + /* Bus master DMAS error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; } } else { ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel); @@ -2182,7 +2063,7 @@ ide_callback(void *priv) command has been executed or when Read Multiple commands are disabled, the Read Multiple operation is rejected with an Aborted Com- mand error. */ - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || !ide->blocksize) + if ((ide->type == IDE_ATAPI) || !ide->blocksize) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2211,7 +2092,7 @@ ide_callback(void *priv) case WIN_WRITE: case WIN_WRITE_NORETRY: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2231,7 +2112,7 @@ ide_callback(void *priv) case WIN_WRITE_DMA: case WIN_WRITE_DMA_ALT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + if ((ide->type == IDE_ATAPI) || !ide_bm[ide->board]) { ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel); goto abort_cmd; } @@ -2240,26 +2121,22 @@ ide_callback(void *priv) goto id_not_found; } - if (ide_bus_master_read) { + if (ide_bm[ide->board] && ide_bm[ide->board]->dma) { if (ide->secount) ide->sector_pos = ide->secount; else ide->sector_pos = 256; - ret = ide_bus_master_write(ide->board, - ide->sector_buffer, ide->sector_pos * 512, - ide_bus_master_priv[ide->board]); + ret = ide_bm[ide->board]->dma(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + 1, ide_bm[ide->board]->priv); if (ret == 2) { /* Bus master DMA disabled, simply wait for the host to enable DMA. */ ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide_set_callback(ide->board, 6LL * IDE_TIME); + ide_set_callback(ide->board, 6.0 * IDE_TIME); return; } else if (ret == 1) { - /* Bus master DMA error, abort the command. */ - ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); - goto abort_cmd; - } else { /*DMA successful*/ ide_log("IDE %i: DMA write successful\n", ide->channel); @@ -2269,6 +2146,10 @@ ide_callback(void *priv) ide_irq_raise(ide); ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } else { + /* Bus master DMA error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; } } else { ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel); @@ -2278,7 +2159,7 @@ ide_callback(void *priv) return; case WIN_WRITE_MULTIPLE: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2301,7 +2182,7 @@ ide_callback(void *priv) case WIN_VERIFY: case WIN_VERIFY_ONCE: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2312,7 +2193,7 @@ ide_callback(void *priv) return; case WIN_FORMAT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2321,47 +2202,11 @@ ide_callback(void *priv) ide->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); - /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ - return; - - case WIN_DRIVE_DIAGNOSTICS: - ide_set_signature(ide); - ide->error=1; /*No error detected*/ - - if (ide_drive_is_zip(ide)) { - zip[zip_id]->status = 0; - zip[zip_id]->error = 1; - ide_irq_raise(ide); - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->status = 0; - cdrom[cdrom_id]->error = 1; - ide_irq_raise(ide); - } else { - ide->atastat = DRDY_STAT | DSC_STAT; - ide->error = 1; - ide_irq_raise(ide); - } - - ide_set_signature(ide_other); - ide_other->error=1; /*No error detected*/ - - if (ide_drive_is_zip(ide_other)) { - zip[zip_id_other]->status = 0; - zip[zip_id_other]->error = 1; - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom[cdrom_id_other]->status = 0; - cdrom[cdrom_id_other]->error = 1; - } else { - ide_other->atastat = DRDY_STAT | DSC_STAT; - ide_other->error = 1; - } - - ide_boards[ide->board]->cur_dev &= ~1; - ch = ide_boards[ide->board]->cur_dev; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); return; case WIN_SPECIFY: /* Initialize Drive Parameters */ - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) { /* Only accept after RESET or DIAG. */ @@ -2375,29 +2220,20 @@ ide_callback(void *priv) return; case WIN_PIDENTIFY: /* Identify Packet Device */ - if (ide_drive_is_zip(ide)) { + if (ide->type == IDE_ATAPI) { ide_identify(ide); ide->pos = 0; - zip[zip_id]->phase = 2; - zip[zip_id]->pos = 0; - zip[zip_id]->error = 0; - zip[zip_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - } else if (ide_drive_is_cdrom(ide)) { - ide_identify(ide); - ide->pos = 0; - cdrom[cdrom_id]->phase = 2; - cdrom[cdrom_id]->pos = 0; - cdrom[cdrom_id]->error = 0; - cdrom[cdrom_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->sc->phase = 2; + ide->sc->pos = 0; + ide->sc->error = 0; + ide->sc->status = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_irq_raise(ide); return; } goto abort_cmd; case WIN_SET_MULTIPLE_MODE: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; ide->blocksize = ide->secount; ide->atastat = DRDY_STAT | DSC_STAT; @@ -2405,22 +2241,16 @@ ide_callback(void *priv) return; case WIN_SET_FEATURES: - if (ide->type == IDE_NONE) + if ((ide->type == IDE_NONE) || !ide_set_features(ide)) goto abort_cmd; - if (!ide_set_features(ide)) - goto abort_cmd; - else { - if (ide_drive_is_zip(ide)) { - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - zip[zip_id]->pos = 0; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; - cdrom[cdrom_id]->pos = 0; - } - ide->atastat = DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); + if (ide->type == IDE_ATAPI) { + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->pos = 0; } + + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); return; case WIN_READ_NATIVE_MAX: @@ -2440,20 +2270,17 @@ ide_callback(void *priv) goto abort_cmd; } else { ide_identify(ide); - ide->pos=0; + ide->pos = 0; ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_irq_raise(ide); } return; case WIN_PACKETCMD: /* ATAPI Packet */ - if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + if (ide->type != IDE_ATAPI) goto abort_cmd; - if (ide_drive_is_zip(ide)) - zip_phase_callback(zip[atapi_zip_drives[ch]]); - else - cdrom_phase_callback(cdrom[atapi_cdrom_drives[ch]]); + ide_atapi_callback(ide); return; case 0xFF: @@ -2462,14 +2289,10 @@ ide_callback(void *priv) abort_cmd: ide->command = 0; - if (ide_drive_is_zip(ide)) { - zip[zip_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; - zip[zip_id]->error = ABRT_ERR; - zip[zip_id]->pos = 0; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; - cdrom[cdrom_id]->error = ABRT_ERR; - cdrom[cdrom_id]->pos = 0; + if (ide->type == IDE_ATAPI) { + ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->sc->error = ABRT_ERR; + ide->sc->pos = 0; } else { ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; ide->error = ABRT_ERR; @@ -2489,25 +2312,28 @@ id_not_found: static void ide_set_handlers(uint8_t board) { - if (ide_base_main[board] & 0x300) { + if (ide_boards[board] == NULL) + return; + + if (ide_boards[board]->base_main & 0x300) { if (ide_boards[board]->bit32) { - io_sethandler(ide_base_main[board], 1, + io_sethandler(ide_boards[board]->base_main, 1, ide_readb, ide_readw, ide_readl, ide_writeb, ide_writew, ide_writel, ide_boards[board]); } else { - io_sethandler(ide_base_main[board], 1, + io_sethandler(ide_boards[board]->base_main, 1, ide_readb, ide_readw, NULL, ide_writeb, ide_writew, NULL, ide_boards[board]); } - io_sethandler(ide_base_main[board] + 1, 7, + io_sethandler(ide_boards[board]->base_main + 1, 7, ide_readb, NULL, NULL, ide_writeb, NULL, NULL, ide_boards[board]); } - if (ide_side_main[board] & 0x300) { - io_sethandler(ide_side_main[board], 1, + if (ide_boards[board]->side_main & 0x300) { + io_sethandler(ide_boards[board]->side_main, 1, ide_read_alt_status, NULL, NULL, ide_write_devctl, NULL, NULL, ide_boards[board]); @@ -2518,22 +2344,25 @@ ide_set_handlers(uint8_t board) static void ide_remove_handlers(uint8_t board) { + if (ide_boards[board] == NULL) + return; + if (ide_boards[board]->bit32) { - io_removehandler(ide_base_main[board], 1, + io_removehandler(ide_boards[board]->base_main, 1, ide_readb, ide_readw, ide_readl, ide_writeb, ide_writew, ide_writel, ide_boards[board]); } else { - io_removehandler(ide_base_main[board], 1, + io_removehandler(ide_boards[board]->base_main, 1, ide_readb, ide_readw, NULL, ide_writeb, ide_writew, NULL, ide_boards[board]); } - io_removehandler(ide_base_main[board] + 1, 7, + io_removehandler(ide_boards[board]->base_main + 1, 7, ide_readb, NULL, NULL, ide_writeb, NULL, NULL, ide_boards[board]); - io_removehandler(ide_side_main[board], 1, + io_removehandler(ide_boards[board]->side_main, 1, ide_read_alt_status, NULL, NULL, ide_write_devctl, NULL, NULL, ide_boards[board]); @@ -2569,35 +2398,184 @@ ide_sec_disable(void) void -ide_set_base(int controller, uint16_t port) +ide_set_base(int board, uint16_t port) { - ide_base_main[controller] = port; + ide_log("ide_set_base(%i, %04X)\n", board, port); + + if (ide_boards[board] == NULL) + return; + + ide_boards[board]->base_main = port; } void -ide_set_side(int controller, uint16_t port) +ide_set_side(int board, uint16_t port) { - ide_side_main[controller] = port; + ide_log("ide_set_side(%i, %04X)\n", board, port); + + if (ide_boards[board] == NULL) + return; + + ide_boards[board]->side_main = port; +} + + +static void +ide_clear_bus_master(int board) +{ + if (ide_bm[board]) { + free(ide_bm[board]); + ide_bm[board] = NULL; + } +} + + +static void +ide_board_close(int board) +{ + ide_t *dev; + int c, d; + + ide_log("ide_board_close(%i)\n", board); + + if ((ide_boards[board] == NULL)|| !ide_boards[board]->inited) + return; + + ide_log("IDE: Closing board %i...\n", board); + + timer_stop(&ide_boards[board]->timer); + + ide_clear_bus_master(board); + + /* Close hard disk image files (if previously open) */ + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if (dev == NULL) + continue; + + if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) + hdd_image_close(dev->hdd_num); + + if (dev->type == IDE_ATAPI) + dev->sc->status = DRDY_STAT | DSC_STAT; + + if (dev->buffer) { + free(dev->buffer); + dev->buffer = NULL; + } + + if (dev->sector_buffer) { + free(dev->sector_buffer); + dev->buffer = NULL; + } + + if (dev) { + free(dev); + ide_drives[c] = NULL; + } + } + + free(ide_boards[board]); + ide_boards[board] = NULL; +} + + +static void +ide_board_setup(int board) +{ + ide_t *dev; + int c, d; + int ch, is_ide, valid_ch; + int min_ch, max_ch; + + min_ch = (board << 1); + max_ch = min_ch + 1; + + ide_log("IDE: board %i: loading disks...\n", board); + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + ide_zero(c); + } + + c = 0; + for (d = 0; d < HDD_NUM; d++) { + is_ide = (hdd[d].bus == HDD_BUS_IDE); + ch = hdd[d].ide_channel; + + if (board == 4) { + valid_ch = ((ch >= 0) && (ch <= 1)); + ch |= 8; + } else + valid_ch = ((ch >= min_ch) && (ch <= max_ch)); + + if (is_ide && valid_ch) { + ide_log("Found IDE hard disk on channel %i\n", ch); + loadhd(ide_drives[ch], d, hdd[d].fn); + if (ide_drives[ch]->sector_buffer == NULL) + ide_drives[ch]->sector_buffer = (uint8_t *) malloc(256*512); + memset(ide_drives[ch]->sector_buffer, 0, 256*512); + if (++c >= 2) break; + } + } + ide_log("IDE: board %i: done, loaded %d disks.\n", board, c); + + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if (dev->type == IDE_NONE) + continue; + + ide_allocate_buffer(dev); + + ide_set_signature(dev); + + dev->mdma_mode = (1 << ide_get_max(dev, TYPE_PIO)); + dev->error = 1; + dev->cfg_spt = dev->cfg_hpc = 0; + } +} + + +static void +ide_board_init(int board, int irq, int base_main, int side_main, int type) +{ + ide_log("ide_board_init(%i, %i, %04X, %04X, %i)\n", board, irq, base_main, side_main, type); + + if ((ide_boards[board] != NULL) && ide_boards[board]->inited) + return; + + ide_log("IDE: Initializing board %i...\n", board); + + ide_boards[board] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[board], 0, sizeof(ide_board_t)); + ide_boards[board]->irq = irq; + ide_boards[board]->cur_dev = board << 1; + if (type & 6) + ide_boards[board]->bit32 = 1; + if (base_main != -1) + ide_boards[board]->base_main = base_main; + if (side_main != -1) + ide_boards[board]->side_main = side_main; + ide_set_handlers(board); + + timer_add(&ide_boards[board]->timer, ide_callback, ide_boards[board], 0); + + ide_board_setup(board); + + ide_boards[board]->inited = 1; } static void * ide_ter_init(const device_t *info) { - ide_boards[2] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[2], 0, sizeof(ide_board_t)); + ide_board_init(2, device_get_config_int("irq"), 0x168, 0x36e, info->local); - ide_boards[2]->irq = device_get_config_int("irq"); - ide_boards[2]->cur_dev = 4; - - ide_set_handlers(2); - - timer_add(ide_callback, &ide_boards[2]->callback, &ide_boards[2]->callback, ide_boards[2]); - - ide_board_init(2); - - return(ide_drives); + return(ide_boards[2]); } @@ -2605,31 +2583,16 @@ ide_ter_init(const device_t *info) static void ide_ter_close(void *priv) { - if (ide_boards[2]) { - free(ide_boards[2]); - ide_boards[2] = NULL; - - ide_board_close(2); - } + ide_board_close(2); } static void * ide_qua_init(const device_t *info) { - ide_boards[3] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[3], 0, sizeof(ide_board_t)); + ide_board_init(3, device_get_config_int("irq"), 0x1e8, 0x3ee, info->local); - ide_boards[3]->irq = device_get_config_int("irq"); - ide_boards[3]->cur_dev = 6; - - ide_set_handlers(3); - - timer_add(ide_callback, &ide_boards[3]->callback, &ide_boards[3]->callback, ide_boards[3]); - - ide_board_init(3); - - return(ide_drives); + return(ide_boards[3]); } @@ -2637,40 +2600,14 @@ ide_qua_init(const device_t *info) static void ide_qua_close(void *priv) { - if (ide_boards[3]) { - free(ide_boards[3]); - ide_boards[3] = NULL; - - ide_board_close(3); - } -} - - -static void -ide_clear_bus_master(void) -{ - ide_bus_master_read = ide_bus_master_write = NULL; - ide_bus_master_set_irq = NULL; - ide_bus_master_priv[0] = ide_bus_master_priv[1] = NULL; + ide_board_close(3); } void * ide_xtide_init(void) { - ide_clear_bus_master(); - - if (!ide_boards[0]) { - ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[0], 0, sizeof(ide_board_t)); - ide_boards[0]->cur_dev = 0; - - timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, - ide_boards[0]); - - ide_board_init(0); - } - ide_boards[0]->irq = -1; + ide_board_init(0, -1, -1, -1, 0); return ide_boards[0]; } @@ -2679,117 +2616,40 @@ ide_xtide_init(void) void ide_xtide_close(void) { - if (ide_boards[0]) { - free(ide_boards[0]); - ide_boards[0] = NULL; - - ide_board_close(0); - } + ide_board_close(0); } void -ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv), - int (*write)(int channel, uint8_t *data, int transfer_length, void *priv), - void (*set_irq)(int channel, void *priv), - void *priv0, void *priv1) +ide_set_bus_master(int board, + int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv), + void (*set_irq)(int channel, void *priv), void *priv) { - ide_bus_master_read = read; - ide_bus_master_write = write; - ide_bus_master_set_irq = set_irq; - ide_bus_master_priv[0] = priv0; - ide_bus_master_priv[1] = priv1; + if (ide_bm[board] == NULL) + ide_bm[board] = (ide_bm_t *) malloc(sizeof(ide_bm_t)); + + ide_bm[board]->dma = dma; + ide_bm[board]->set_irq = set_irq; + ide_bm[board]->priv = priv; } -void -secondary_ide_check(void) -{ - int i = 0; - int secondary_cdroms = 0; - int secondary_zips = 0; - - for (i=0; i= 2) && (zip_drives[i].ide_channel <= 3) && - (zip_drives[i].bus_type == ZIP_BUS_ATAPI)) - secondary_zips++; - } - for (i=0; i= 2) && (cdrom_drives[i].ide_channel <= 3) && - (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI)) - secondary_cdroms++; - } - if (!secondary_zips && !secondary_cdroms) - ide_remove_handlers(1); -} - - -/* - * Initialization of standalone IDE controller instance. - * - * Eventually, we should clean up the whole mess by only - * using const device_t units, with configuration parameters to - * indicate primary/secondary and all that, rather than - * keeping a zillion of duplicate functions around. - */ static void * -ide_sainit(const device_t *info) +ide_init(const device_t *info) { ide_log("Initializing IDE...\n"); switch(info->local) { case 0: /* ISA, single-channel */ - case 2: /* ISA, dual-channel */ - case 3: /* ISA, dual-channel, optional 2nd channel */ - case 4: /* VLB, single-channel */ - case 6: /* VLB, dual-channel */ - case 8: /* PCI, single-channel */ - case 10: /* PCI, dual-channel */ - if (!ide_inited) { - if (!(info->local & 8)) - ide_clear_bus_master(); - } + case 1: /* ISA, dual-channel */ + case 2: /* VLB, single-channel */ + case 3: /* VLB, dual-channel */ + case 4: /* PCI, single-channel */ + case 5: /* PCI, dual-channel */ + ide_board_init(0, 14, 0x1f0, 0x3f6, info->local); - if (!(ide_inited & 1)) { - ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[0], 0, sizeof(ide_board_t)); - ide_boards[0]->irq = 14; - ide_boards[0]->cur_dev = 0; - if (info->local & 8) - ide_boards[0]->bit32 = 1; - ide_base_main[0] = 0x1f0; - ide_side_main[0] = 0x3f6; - ide_set_handlers(0); - timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, - ide_boards[0]); - ide_log("Callback 0 pointer: %08X\n", &ide_boards[0]->callback); - - ide_board_init(0); - - ide_inited |= 1; - } - - if ((info->local & 3) && !(ide_inited & 2)) { - ide_boards[1] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[1], 0, sizeof(ide_board_t)); - ide_boards[1]->irq = 15; - ide_boards[1]->cur_dev = 2; - if (info->local & 8) - ide_boards[1]->bit32 = 1; - ide_base_main[1] = 0x170; - ide_side_main[1] = 0x376; - ide_set_handlers(1); - timer_add(ide_callback, &ide_boards[1]->callback, &ide_boards[1]->callback, - ide_boards[1]); - ide_log("Callback 1 pointer: %08X\n", &ide_boards[1]->callback); - - ide_board_init(1); - - if (info->local & 1) - secondary_ide_check(); - - ide_inited |= 2; - } + if (info->local & 1) + ide_board_init(1, 15, 0x170, 0x376, info->local); break; } @@ -2800,6 +2660,8 @@ ide_sainit(const device_t *info) static void ide_drive_reset(int d) { + ide_log("Resetting IDE drive %i...\n", d); + ide_drives[d]->channel = d; ide_drives[d]->atastat = DRDY_STAT | DSC_STAT; ide_drives[d]->service = 0; @@ -2807,7 +2669,7 @@ ide_drive_reset(int d) if (ide_boards[d >> 1]) { ide_boards[d >> 1]->cur_dev = d & ~1; - ide_boards[d >> 1]->callback = 0LL; + timer_stop(&ide_boards[d >> 1]->timer); } ide_set_signature(ide_drives[d]); @@ -2820,47 +2682,42 @@ ide_drive_reset(int d) } +static void +ide_board_reset(int board) +{ + int d, min, max; + + ide_log("Resetting IDE board %i...\n", board); + + timer_stop(&ide_boards[board]->timer); + + min = (board << 1); + max = min + 2; + + for (d = min; d < max; d++) + ide_drive_reset(d); +} + + /* Reset a standalone IDE unit. */ static void -ide_sareset(void *p) +ide_reset(void *p) { - int d; - ide_log("Resetting IDE...\n"); - if (ide_inited & 1) { - for (d = 0; d < 2; d++) - ide_drive_reset(d); - } - - if (ide_inited & 2) { - for (d = 2; d < 4; d++) - ide_drive_reset(d); - } + ide_board_reset(0); + ide_board_reset(1); } /* Close a standalone IDE unit. */ static void -ide_saclose(void *priv) +ide_close(void *priv) { ide_log("Closing IDE...\n"); - if ((ide_inited & 1) && (ide_boards[0])) { - free(ide_boards[0]); - ide_boards[0] = NULL; - - ide_board_close(0); - } - - if ((ide_inited & 2) && (ide_boards[1])) { - free(ide_boards[1]); - ide_boards[1] = NULL; - - ide_board_close(1); - } - - ide_inited = 0; + ide_board_close(0); + ide_board_close(1); } @@ -2868,55 +2725,47 @@ const device_t ide_isa_device = { "ISA PC/AT IDE Controller", DEVICE_ISA | DEVICE_AT, 0, - ide_sainit, ide_saclose, ide_sareset, + ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; const device_t ide_isa_2ch_device = { "ISA PC/AT IDE Controller (Dual-Channel)", DEVICE_ISA | DEVICE_AT, - 2, - ide_sainit, ide_saclose, ide_sareset, - NULL, NULL, NULL, NULL -}; - -const device_t ide_isa_2ch_opt_device = { - "ISA PC/AT IDE Controller (Single/Dual)", - DEVICE_ISA | DEVICE_AT, - 3, - ide_sainit, ide_saclose, ide_sareset, + 1, + ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; const device_t ide_vlb_device = { "VLB IDE Controller", DEVICE_VLB | DEVICE_AT, - 4, - ide_sainit, ide_saclose, ide_sareset, + 2, + ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; const device_t ide_vlb_2ch_device = { "VLB IDE Controller (Dual-Channel)", DEVICE_VLB | DEVICE_AT, - 6, - ide_sainit, ide_saclose, ide_sareset, + 3, + ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; const device_t ide_pci_device = { "PCI IDE Controller", DEVICE_PCI | DEVICE_AT, - 8, - ide_sainit, ide_saclose, ide_sareset, + 4, + ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; const device_t ide_pci_2ch_device = { "PCI IDE Controller (Dual-Channel)", DEVICE_PCI | DEVICE_AT, - 10, - ide_sainit, ide_saclose, ide_sareset, + 5, + ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; diff --git a/src/disk/hdc_ide.h b/src/disk/hdc_ide.h index 69a81276d..b1e172748 100644 --- a/src/disk/hdc_ide.h +++ b/src/disk/hdc_ide.h @@ -9,49 +9,101 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdd_ide.h 1.0.10 2018/05/02 + * Version: @(#)hdd_ide.h 1.0.16 2019/11/19 * * Authors: Sarah Walker, * Miran Grca, - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #ifndef EMU_IDE_H # define EMU_IDE_H -typedef struct { - uint8_t atastat, error, - command, fdisk; - int type, board, - irqstat, service, - blocksize, blockcount, - hdd_num, channel, - pos, sector_pos, - lba, skip512, - reset, tracks, - spt, hpc, - mdma_mode, do_initial_read; - uint32_t secount, sector, - cylinder, head, - drive, cylprecomp, - cfg_spt, cfg_hpc, - lba_addr; +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_ATAPI +}; - uint16_t *buffer; - uint8_t *sector_buffer; +#ifdef SCSI_DEVICE_H +typedef struct ide_s { + uint8_t atastat, error, + command, fdisk; + int type, board, + irqstat, service, + blocksize, blockcount, + hdd_num, channel, + pos, sector_pos, + lba, skip512, + reset, mdma_mode, + do_initial_read; + uint32_t secount, sector, + cylinder, head, + drive, cylprecomp, + cfg_spt, cfg_hpc, + lba_addr, tracks, + spt, hpc; + + uint16_t *buffer; + uint8_t *sector_buffer; + + /* Stuff mostly used by ATAPI */ + scsi_common_t *sc; + int interrupt_drq; + + int (*get_max)(int ide_has_dma, int type); + int (*get_timings)(int ide_has_dma, int type); + void (*identify)(struct ide_s *ide, int ide_has_dma); + void (*stop)(scsi_common_t *sc); + void (*packet_command)(scsi_common_t *sc, uint8_t *cdb); + void (*device_reset)(scsi_common_t *sc); + uint8_t (*phase_data_out)(scsi_common_t *sc); + void (*command_stop)(scsi_common_t *sc); + void (*bus_master_error)(scsi_common_t *sc); } ide_t; +#endif + +/* Type: + 0 = PIO, + 1 = SDMA, + 2 = MDMA, + 3 = UDMA + Return: + -1 = Not supported, + Anything else = maximum mode + + This will eventually be hookable. */ +enum { + TYPE_PIO = 0, + TYPE_SDMA, + TYPE_MDMA, + TYPE_UDMA +}; + +/* Return: + 0 = Not supported, + Anything else = timings + + This will eventually be hookable. */ +enum { + TIMINGS_DMA = 0, + TIMINGS_PIO, + TIMINGS_PIO_FC +}; -extern int ideboard; extern int ide_ter_enabled, ide_qua_enabled; -extern ide_t *ide_drives[IDE_NUM]; -extern int64_t idecallback[5]; - +#ifdef SCSI_DEVICE_H +extern ide_t * ide_get_drive(int ch); extern void ide_irq_raise(ide_t *ide); extern void ide_irq_lower(ide_t *ide); +extern void ide_allocate_buffer(ide_t *dev); +extern void ide_atapi_attach(ide_t *dev); +#endif extern void * ide_xtide_init(void); extern void ide_xtide_close(void); @@ -63,29 +115,28 @@ extern uint8_t ide_readb(uint16_t addr, void *priv); extern uint8_t ide_read_alt_status(uint16_t addr, void *priv); extern uint16_t ide_readw(uint16_t addr, void *priv); -extern void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv), - int (*write)(int channel, uint8_t *data, int transfer_length, void *priv), - void (*set_irq)(int channel, void *priv), - void *priv0, void *priv1); +extern void ide_set_bus_master(int board, + int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv), + void (*set_irq)(int channel, void *priv), void *priv); extern void win_cdrom_eject(uint8_t id); extern void win_cdrom_reload(uint8_t id); -extern void ide_set_base(int controller, uint16_t port); -extern void ide_set_side(int controller, uint16_t port); +extern void ide_set_base(int board, uint16_t port); +extern void ide_set_side(int board, uint16_t port); extern void ide_pri_enable(void); extern void ide_pri_disable(void); extern void ide_sec_enable(void); extern void ide_sec_disable(void); -extern void ide_set_callback(uint8_t channel, int64_t callback); -extern void secondary_ide_check(void); +extern double ide_atapi_get_period(uint8_t channel); +extern void ide_set_callback(uint8_t channel, double callback); +extern void ide_padstr(char *str, const char *src, int len); extern void ide_padstr8(uint8_t *buf, int buf_size, const char *src); -extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); -extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +extern int (*ide_bus_master_dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv); extern void (*ide_bus_master_set_irq)(int channel, void *priv); extern void *ide_bus_master_priv[2]; diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c new file mode 100644 index 000000000..bf712bcc8 --- /dev/null +++ b/src/disk/hdc_ide_sff8038i.c @@ -0,0 +1,471 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the SFF-8038i IDE Bus Master. + * + * PRD format : + * word 0 - base address + * word 1 - bits 1-15 = byte count, bit 31 = end of transfer + * + * Version: @(#)hdc_ide_sff8038i.c 1.0.1 2019/10/30 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cdrom/cdrom.h" +#include "../scsi/scsi_device.h" +#include "../scsi/scsi_cdrom.h" +#include "../dma.h" +#include "../io.h" +#include "../device.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../pci.h" +#include "../pic.h" +#include "hdc.h" +#include "hdc_ide.h" +#include "hdc_ide_sff8038i.h" +#include "zip.h" + + +static int next_id = 0; + + +static uint8_t sff_bus_master_read(uint16_t port, void *priv); +static uint16_t sff_bus_master_readw(uint16_t port, void *priv); +static uint32_t sff_bus_master_readl(uint16_t port, void *priv); +static void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); +static void sff_bus_master_writew(uint16_t port, uint16_t val, void *priv); +static void sff_bus_master_writel(uint16_t port, uint32_t val, void *priv); + + +#ifdef ENABLE_SFF_LOG +int sff_do_log = ENABLE_SFF_LOG; + + +static void +sff_log(const char *fmt, ...) +{ + va_list ap; + + if (sff_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define sff_log(fmt, ...) +#endif + + +void +sff_bus_master_handlers(sff8038i_t *dev, uint16_t old_base, uint16_t new_base, int enabled) +{ + io_removehandler(old_base, 0x08, + sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl, + sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel, + dev); + + if (enabled && new_base) { + io_sethandler(new_base, 0x08, + sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl, + sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel, + dev); + } + + dev->enabled = enabled; +} + + +static void +sff_bus_master_next_addr(sff8038i_t *dev) +{ + DMAPageRead(dev->ptr_cur, (uint8_t *)&(dev->addr), 4); + DMAPageRead(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4); + sff_log("SFF-8038i Bus master DWORDs: %08X %08X\n", dev->addr, dev->count); + dev->eot = dev->count >> 31; + dev->count &= 0xfffe; + if (!dev->count) + dev->count = 65536; + dev->addr &= 0xfffffffe; + dev->ptr_cur += 8; +} + + +static void +sff_bus_master_write(uint16_t port, uint8_t val, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; +#ifdef ENABLE_SFF_LOG + int channel = (port & 8) ? 1 : 0; +#endif + + sff_log("SFF-8038i Bus master BYTE write: %04X %02X\n", port, val); + + switch (port & 7) { + case 0: + sff_log("sff Cmd : val = %02X, old = %02X\n", val, dev->command); + if ((val & 1) && !(dev->command & 1)) { /*Start*/ + sff_log("sff Bus Master start on channel %i\n", channel); + dev->ptr_cur = dev->ptr; + sff_bus_master_next_addr(dev); + dev->status |= 1; + } + if (!(val & 1) && (dev->command & 1)) { /*Stop*/ + sff_log("sff Bus Master stop on channel %i\n", channel); + dev->status &= ~1; + } + + dev->command = val; + break; + case 2: + sff_log("sff Status: val = %02X, old = %02X\n", val, dev->status); + dev->status &= 0x07; + dev->status |= (val & 0x60); + if (val & 0x04) + dev->status &= ~0x04; + if (val & 0x02) + dev->status &= ~0x02; + break; + case 4: + dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val; + break; + case 5: + dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8); + dev->ptr %= (mem_size * 1024); + break; + case 6: + dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + case 7: + dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +sff_bus_master_writew(uint16_t port, uint16_t val, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + sff_log("SFF-8038i Bus master WORD write: %04X %04X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + sff_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + case 6: + dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +sff_bus_master_writel(uint16_t port, uint32_t val, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + sff_log("SFF-8038i Bus master DWORD write: %04X %08X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + sff_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (val & 0xfffffffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + } +} + + +static uint8_t +sff_bus_master_read(uint16_t port, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: + ret = dev->command; + break; + case 2: + ret = dev->status & 0x67; + break; + case 4: + ret = dev->ptr0; + break; + case 5: + ret = dev->ptr >> 8; + break; + case 6: + ret = dev->ptr >> 16; + break; + case 7: + ret = dev->ptr >> 24; + break; + } + + sff_log("SFF-8038i Bus master BYTE read : %04X %02X\n", port, ret); + + return ret; +} + + +static uint16_t +sff_bus_master_readw(uint16_t port, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + uint16_t ret = 0xffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint16_t) sff_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xff00); + break; + case 6: + ret = dev->ptr >> 16; + break; + } + + sff_log("SFF-8038i Bus master WORD read : %04X %04X\n", port, ret); + + return ret; +} + + +static uint32_t +sff_bus_master_readl(uint16_t port, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + uint32_t ret = 0xffffffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint32_t) sff_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xffffff00); + break; + } + + sff_log("sff Bus master DWORD read : %04X %08X\n", port, ret); + + return ret; +} + + +static int +sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; +#ifdef ENABLE_SFF_LOG + char *sop; +#endif + + int force_end = 0, buffer_pos = 0; + +#ifdef ENABLE_SFF_LOG + sop = out ? "Read" : "Writ"; +#endif + + if (!(dev->status & 1)) + return 2; /*DMA disabled*/ + + sff_log("SFF-8038i Bus master %s: %i bytes\n", out ? "write" : "read", transfer_length); + + while (1) { + if (dev->count <= transfer_length) { + sff_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr); + if (out) + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + else + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + transfer_length -= dev->count; + buffer_pos += dev->count; + } else { + sff_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr); + if (out) + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + else + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + /* Increase addr and decrease count so that resumed transfers do not mess up. */ + dev->addr += transfer_length; + dev->count -= transfer_length; + transfer_length = 0; + force_end = 1; + } + + if (force_end) { + sff_log("Total transfer length smaller than sum of all blocks, partial block\n"); + dev->status &= ~2; + return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ + } else { + if (!transfer_length && !dev->eot) { + sff_log("Total transfer length smaller than sum of all blocks, full block\n"); + dev->status &= ~2; + return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } else if (transfer_length && dev->eot) { + sff_log("Total transfer length greater than sum of all blocks\n"); + dev->status |= 2; + return 0; /* There is data left to transfer but we have reached EOT - return with error. */ + } else if (dev->eot) { + sff_log("Regular EOT\n"); + dev->status &= ~3; + return 1; /* We have regularly reached EOT - clear status and break. */ + } else { + /* We have more to transfer and there are blocks left, get next block. */ + sff_bus_master_next_addr(dev); + } + } + } + + return 1; +} + + +void +sff_bus_master_set_irq(int channel, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + dev->status &= ~4; + dev->status |= (channel >> 4); + + channel &= 0x01; + if (dev->status & 0x04) { + if (channel && pci_use_mirq(0)) + pci_set_mirq(0, 0); + else + picint(1 << (14 + channel)); + } else { + if ((channel & 1) && pci_use_mirq(0)) + pci_clear_mirq(0, 0); + else + picintc(1 << (14 + channel)); + } +} + + +void +sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base) +{ + if (dev->enabled) { + io_removehandler(old_base, 0x08, + sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl, + sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel, + dev); + + dev->enabled = 0; + } + + dev->command = 0x00; + dev->status = 0x00; + dev->ptr = dev->ptr_cur = 0x00000000; + dev->addr = 0x00000000; + dev->ptr0 = 0x00; + dev->count = dev->eot = 0x00000000; + + ide_pri_disable(); + ide_sec_disable(); +} + + +static void +sff_reset(void *p) +{ + int i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && + (cdrom[i].ide_channel < 4) && cdrom[i].priv) + scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv); + } + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && + (zip_drives[i].ide_channel < 4) && zip_drives[i].priv) + zip_reset((scsi_common_t *) zip_drives[i].priv); + } +} + + +static void +sff_close(void *p) +{ + sff8038i_t *dev = (sff8038i_t *)p; + + free(dev); + + next_id--; + if (next_id < 0) + next_id = 0; +} + + +static void +*sff_init(const device_t *info) +{ + sff8038i_t *dev = (sff8038i_t *) malloc(sizeof(sff8038i_t)); + memset(dev, 0, sizeof(sff8038i_t)); + + /* Make sure to only add IDE once. */ + if (next_id == 0) + device_add(&ide_pci_2ch_device); + + ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); + + next_id++; + + return dev; +} + + +const device_t sff8038i_device = +{ + "SFF-8038i IDE Bus Master", + DEVICE_PCI, + 0, + sff_init, + sff_close, + sff_reset, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/disk/hdc_ide_sff8038i.h b/src/disk/hdc_ide_sff8038i.h new file mode 100644 index 000000000..0be341eff --- /dev/null +++ b/src/disk/hdc_ide_sff8038i.h @@ -0,0 +1,38 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the SFF-8038i IDE Bus Master. + * + * Emulation core dispatcher. + * + * Version: @(#)hdc_ide_sff8038i.h 1.0.0 2019/05/12 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +typedef struct +{ + uint8_t command, status, + ptr0, enabled; + uint32_t ptr, ptr_cur, + addr; + int count, eot; +} sff8038i_t; + + +extern const device_t sff8038i_device; + +extern void sff_bus_master_handlers(sff8038i_t *dev, uint16_t old_base, uint16_t new_base, int enabled); + +extern int sff_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv); +extern int sff_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv); + +extern void sff_bus_master_set_irq(int channel, void *priv); + +extern void sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base); diff --git a/src/disk/hdc_mfm_xt.c b/src/disk/hdc_mfm_xt.c deleted file mode 100644 index 6d86fe070..000000000 --- a/src/disk/hdc_mfm_xt.c +++ /dev/null @@ -1,949 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Driver for the IBM PC-XT Fixed Disk controller. - * - * The original controller shipped by IBM was made by Xebec, and - * several variations had been made: - * - * #1 Original, single drive (ST412), 10MB, 2 heads. - * #2 Update, single drive (ST412) but with option for a - * switch block that can be used to 'set' the actual - * drive type. Four switches are define, where switches - * 1 and 2 define drive0, and switches 3 and 4 drive1. - * - * 0 ON ON 306 2 0 - * 1 ON OFF 375 8 0 - * 2 OFF ON 306 6 256 - * 3 OFF OFF 306 4 0 - * - * The latter option is the default, in use on boards - * without the switch block option. - * - * #3 Another updated board, mostly to accomodate the new - * 20MB disk now being shipped. The controller can have - * up to 2 drives, the type of which is set using the - * switch block: - * - * SW1 SW2 CYLS HD SPT WPC - * 0 ON ON 306 4 17 0 - * 1 ON OFF 612 4 17 0 (type 16) - * 2 OFF ON 615 4 17 300 (Seagate ST-225, 2) - * 3 OFF OFF 306 8 17 128 (IBM WD25, 13) - * - * Examples of #3 are IBM/Xebec, WD10004A-WX1 and ST11R. - * - * Since all controllers (including the ones made by DTC) use - * (mostly) the same API, we keep them all in this module. - * - * Version: @(#)hdc_mfm_xt.c 1.0.17 2018/04/29 - * - * Authors: Sarah Walker, - * Fred N. van Kempen, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2017,2018 Fred N. van Kempen. - */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "../86box.h" -#include "../device.h" -#include "../dma.h" -#include "../io.h" -#include "../mem.h" -#include "../pic.h" -#include "../rom.h" -#include "../timer.h" -#include "../plat.h" -#include "../ui.h" -#include "hdc.h" -#include "hdd.h" - - -// #define MFM_TIME (2000LL*TIMER_USEC) -#define MFM_TIME (50LL*TIMER_USEC) -#define XEBEC_BIOS_FILE L"roms/hdd/mfm_xebec/ibm_xebec_62x0822_1985.bin" -#define DTC_BIOS_FILE L"roms/hdd/mfm_xebec/dtc_cxd21a.bin" - - -enum { - STATE_IDLE, - STATE_RECEIVE_COMMAND, - STATE_START_COMMAND, - STATE_RECEIVE_DATA, - STATE_RECEIVED_DATA, - STATE_SEND_DATA, - STATE_SENT_DATA, - STATE_COMPLETION_BYTE, - STATE_DUNNO -}; - - -typedef struct { - int spt, hpc; - int tracks; - int cfg_spt; - int cfg_hpc; - int cfg_cyl; - int current_cylinder; - int present; - int hdd_num; -} drive_t; - -typedef struct { - rom_t bios_rom; - int64_t callback; - int state; - uint8_t status; - uint8_t command[6]; - int command_pos; - uint8_t data[512]; - int data_pos, data_len; - uint8_t sector_buf[512]; - uint8_t irq_dma_mask; - uint8_t completion_byte; - uint8_t error; - int drive_sel; - drive_t drives[2]; - int sector, head, cylinder; - int sector_count; - uint8_t switches; -} mfm_t; - -#define STAT_IRQ 0x20 -#define STAT_DRQ 0x10 -#define STAT_BSY 0x08 -#define STAT_CD 0x04 -#define STAT_IO 0x02 -#define STAT_REQ 0x01 - -#define IRQ_ENA 0x02 -#define DMA_ENA 0x01 - -#define CMD_TEST_DRIVE_READY 0x00 -#define CMD_RECALIBRATE 0x01 -#define CMD_READ_STATUS 0x03 -#define CMD_VERIFY_SECTORS 0x05 -#define CMD_FORMAT_TRACK 0x06 -#define CMD_READ_SECTORS 0x08 -#define CMD_WRITE_SECTORS 0x0a -#define CMD_SEEK 0x0b -#define CMD_INIT_DRIVE_PARAMS 0x0c -#define CMD_WRITE_SECTOR_BUFFER 0x0f -#define CMD_BUFFER_DIAGNOSTIC 0xe0 -#define CMD_CONTROLLER_DIAGNOSTIC 0xe4 -#define CMD_DTC_GET_DRIVE_PARAMS 0xfb -#define CMD_DTC_SET_STEP_RATE 0xfc -#define CMD_DTC_SET_GEOMETRY 0xfe -#define CMD_DTC_GET_GEOMETRY 0xff - -#define ERR_NOT_READY 0x04 -#define ERR_SEEK_ERROR 0x15 -#define ERR_ILLEGAL_SECTOR_ADDRESS 0x21 - - -#ifdef ENABLE_MFM_XT_LOG -int mfm_xt_do_log = ENABLE_MFM_XT_LOG; -#endif - - -static void -mfm_xt_log(const char *fmt, ...) -{ -#ifdef ENABLE_MFM_XT_LOG - va_list ap; - - if (mfm_xt_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - -static uint8_t -mfm_read(uint16_t port, void *priv) -{ - mfm_t *mfm = (mfm_t *)priv; - uint8_t temp = 0xff; - - switch (port) { - case 0x320: /*Read data*/ - mfm->status &= ~STAT_IRQ; - switch (mfm->state) { - case STATE_COMPLETION_BYTE: - if ((mfm->status & 0xf) != (STAT_CD | STAT_IO | STAT_REQ | STAT_BSY)) - fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status); - - temp = mfm->completion_byte; - mfm->status = 0; - mfm->state = STATE_IDLE; - break; - - case STATE_SEND_DATA: - if ((mfm->status & 0xf) != (STAT_IO | STAT_REQ | STAT_BSY)) - fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status); - if (mfm->data_pos >= mfm->data_len) - fatal("Data write with full data!\n"); - temp = mfm->data[mfm->data_pos++]; - if (mfm->data_pos == mfm->data_len) { - mfm->status = STAT_BSY; - mfm->state = STATE_SENT_DATA; - mfm->callback = MFM_TIME; - } - break; - - default: - fatal("Read data register - %i, %02x\n", mfm->state, mfm->status); - } - break; - - case 0x321: /*Read status*/ - temp = mfm->status; - break; - - case 0x322: /*Read option jumpers*/ - temp = mfm->switches; - break; - } - - return(temp); -} - - -static void -mfm_write(uint16_t port, uint8_t val, void *priv) -{ - mfm_t *mfm = (mfm_t *)priv; - - switch (port) { - case 0x320: /*Write data*/ - switch (mfm->state) { - case STATE_RECEIVE_COMMAND: - if ((mfm->status & 0xf) != (STAT_BSY | STAT_CD | STAT_REQ)) - fatal("Bad write data state - STATE_START_COMMAND, status=%02x\n", mfm->status); - if (mfm->command_pos >= 6) - fatal("Command write with full command!\n"); - /*Command data*/ - mfm->command[mfm->command_pos++] = val; - if (mfm->command_pos == 6) { - mfm->status = STAT_BSY; - mfm->state = STATE_START_COMMAND; - mfm->callback = MFM_TIME; - } - break; - - case STATE_RECEIVE_DATA: - if ((mfm->status & 0xf) != (STAT_BSY | STAT_REQ)) - fatal("Bad write data state - STATE_RECEIVE_DATA, status=%02x\n", mfm->status); - if (mfm->data_pos >= mfm->data_len) - fatal("Data write with full data!\n"); - /*Command data*/ - mfm->data[mfm->data_pos++] = val; - if (mfm->data_pos == mfm->data_len) { - mfm->status = STAT_BSY; - mfm->state = STATE_RECEIVED_DATA; - mfm->callback = MFM_TIME; - } - break; - - default: - fatal("Write data unknown state - %i %02x\n", mfm->state, mfm->status); - } - break; - - case 0x321: /*Controller reset*/ - mfm->status = 0; - break; - - case 0x322: /*Generate controller-select-pulse*/ - mfm->status = STAT_BSY | STAT_CD | STAT_REQ; - mfm->command_pos = 0; - mfm->state = STATE_RECEIVE_COMMAND; - break; - - case 0x323: /*DMA/IRQ mask register*/ - mfm->irq_dma_mask = val; - break; - } -} - - -static void mfm_complete(mfm_t *mfm) -{ - mfm->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; - mfm->state = STATE_COMPLETION_BYTE; - - if (mfm->irq_dma_mask & IRQ_ENA) { - mfm->status |= STAT_IRQ; - picint(1 << 5); - } -} - - -static void -mfm_error(mfm_t *mfm, uint8_t error) -{ - mfm->completion_byte |= 0x02; - mfm->error = error; - - mfm_xt_log("mfm_error - %02x\n", mfm->error); -} - - -static int -get_sector(mfm_t *mfm, off64_t *addr) -{ - drive_t *drive = &mfm->drives[mfm->drive_sel]; - int heads = drive->cfg_hpc; - - if (drive->current_cylinder != mfm->cylinder) { - mfm_xt_log("mfm_get_sector: wrong cylinder\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; - return(1); - } - if (mfm->head > heads) { - mfm_xt_log("mfm_get_sector: past end of configured heads\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; - return(1); - } - if (mfm->head > drive->hpc) { - mfm_xt_log("mfm_get_sector: past end of heads\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; - return(1); - } - if (mfm->sector >= 17) { - mfm_xt_log("mfm_get_sector: past end of sectors\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; - return(1); - } - - *addr = ((((off64_t) mfm->cylinder * heads) + mfm->head) * - 17) + mfm->sector; - - return(0); -} - - -static void -next_sector(mfm_t *mfm) -{ - drive_t *drive = &mfm->drives[mfm->drive_sel]; - - mfm->sector++; - if (mfm->sector >= 17) { - mfm->sector = 0; - mfm->head++; - if (mfm->head >= drive->cfg_hpc) { - mfm->head = 0; - mfm->cylinder++; - drive->current_cylinder++; - if (drive->current_cylinder >= drive->cfg_cyl) - drive->current_cylinder = drive->cfg_cyl-1; - } - } -} - - -static void -mfm_callback(void *priv) -{ - mfm_t *mfm = (mfm_t *)priv; - drive_t *drive; - off64_t addr; - - mfm->callback = 0LL; - - mfm->drive_sel = (mfm->command[1] & 0x20) ? 1 : 0; - mfm->completion_byte = mfm->drive_sel & 0x20; - drive = &mfm->drives[mfm->drive_sel]; - - switch (mfm->command[0]) { - case CMD_TEST_DRIVE_READY: - if (!drive->present) - mfm_error(mfm, ERR_NOT_READY); - mfm_complete(mfm); - break; - - case CMD_RECALIBRATE: - if (!drive->present) - mfm_error(mfm, ERR_NOT_READY); - else { - mfm->cylinder = 0; - drive->current_cylinder = 0; - } - mfm_complete(mfm); - break; - - case CMD_READ_STATUS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 4; - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - mfm->data[0] = mfm->error; - mfm->data[1] = mfm->drive_sel ? 0x20 : 0; - mfm->data[2] = mfm->data[3] = 0; - mfm->error = 0; - break; - - case STATE_SENT_DATA: - mfm_complete(mfm); - break; - } - break; - - case CMD_VERIFY_SECTORS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - mfm->sector = mfm->command[2] & 0x1f; - mfm->sector_count = mfm->command[4]; - do { - if (get_sector(mfm, &addr)) { - mfm_xt_log("get_sector failed\n"); - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - next_sector(mfm); - - mfm->sector_count = (mfm->sector_count-1) & 0xff; - } while (mfm->sector_count); - - mfm_complete(mfm); - - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); - break; - - default: - fatal("CMD_VERIFY_SECTORS: bad state %i\n", mfm->state); - } - break; - - case CMD_FORMAT_TRACK: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - - if (get_sector(mfm, &addr)) { - mfm_xt_log("get_sector failed\n"); - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - hdd_image_zero(drive->hdd_num, addr, 17); - - mfm_complete(mfm); - break; - - case CMD_READ_SECTORS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - mfm->sector = mfm->command[2] & 0x1f; - mfm->sector_count = mfm->command[4]; - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 512; - - if (get_sector(mfm, &addr)) { - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *) mfm->sector_buf); - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else { - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memcpy(mfm->data, mfm->sector_buf, 512); - } - break; - - case STATE_SEND_DATA: - mfm->status = STAT_BSY; - if (mfm->irq_dma_mask & DMA_ENA) { - for (; mfm->data_pos < 512; mfm->data_pos++) { - int val = dma_channel_write(3, mfm->sector_buf[mfm->data_pos]); - - if (val == DMA_NODATA) { - mfm_xt_log("CMD_READ_SECTORS out of data!\n"); - mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - mfm->callback = MFM_TIME; - return; - } - } - mfm->state = STATE_SENT_DATA; - mfm->callback = MFM_TIME; - } else - fatal("Read sectors no DMA! - shouldn't get here\n"); - break; - - case STATE_SENT_DATA: - next_sector(mfm); - - mfm->data_pos = 0; - - mfm->sector_count = (mfm->sector_count-1) & 0xff; - - if (mfm->sector_count) { - if (get_sector(mfm, &addr)) { - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *) mfm->sector_buf); - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - mfm->state = STATE_SEND_DATA; - - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else { - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memcpy(mfm->data, mfm->sector_buf, 512); - } - } else { - mfm_complete(mfm); - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); - } - break; - - default: - fatal("CMD_READ_SECTORS: bad state %i\n", mfm->state); - } - break; - - case CMD_WRITE_SECTORS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - mfm->sector = mfm->command[2] & 0x1f; - mfm->sector_count = mfm->command[4]; - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 512; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else - mfm->status = STAT_BSY | STAT_REQ; - break; - - case STATE_RECEIVE_DATA: - mfm->status = STAT_BSY; - if (mfm->irq_dma_mask & DMA_ENA) { - for (; mfm->data_pos < 512; mfm->data_pos++) { - int val = dma_channel_read(3); - - if (val == DMA_NODATA) { - mfm_xt_log("CMD_WRITE_SECTORS out of data!\n"); - mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - mfm->callback = MFM_TIME; - return; - } - - mfm->sector_buf[mfm->data_pos] = val & 0xff; - } - - mfm->state = STATE_RECEIVED_DATA; - mfm->callback = MFM_TIME; - } else - fatal("Write sectors no DMA! - should never get here\n"); - break; - - case STATE_RECEIVED_DATA: - if (! (mfm->irq_dma_mask & DMA_ENA)) - memcpy(mfm->sector_buf, mfm->data, 512); - - if (get_sector(mfm, &addr)) - { - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - hdd_image_write(drive->hdd_num, addr, 1, - (uint8_t *) mfm->sector_buf); - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - next_sector(mfm); - mfm->data_pos = 0; - mfm->sector_count = (mfm->sector_count-1) & 0xff; - - if (mfm->sector_count) { - mfm->state = STATE_RECEIVE_DATA; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else - mfm->status = STAT_BSY | STAT_REQ; - } else - mfm_complete(mfm); - break; - - default: - fatal("CMD_WRITE_SECTORS: bad state %i\n", mfm->state); - } - break; - - case CMD_SEEK: - if (! drive->present) - mfm_error(mfm, ERR_NOT_READY); - else { - int cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - - drive->current_cylinder = (cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : cylinder; - - if (cylinder != drive->current_cylinder) - mfm_error(mfm, ERR_SEEK_ERROR); - } - mfm_complete(mfm); - break; - - case CMD_INIT_DRIVE_PARAMS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 8; - mfm->status = STAT_BSY | STAT_REQ; - break; - - case STATE_RECEIVED_DATA: - drive->cfg_cyl = mfm->data[1] | (mfm->data[0] << 8); - drive->cfg_hpc = mfm->data[2]; - mfm_xt_log("Drive %i: cylinders=%i, heads=%i\n", mfm->drive_sel, drive->cfg_cyl, drive->cfg_hpc); - mfm_complete(mfm); - break; - - default: - fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state); - } - break; - - case CMD_WRITE_SECTOR_BUFFER: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 512; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else - mfm->status = STAT_BSY | STAT_REQ; - break; - - case STATE_RECEIVE_DATA: - if (mfm->irq_dma_mask & DMA_ENA) { - mfm->status = STAT_BSY; - - for (; mfm->data_pos < 512; mfm->data_pos++) { - int val = dma_channel_read(3); - - if (val == DMA_NODATA) { - mfm_xt_log("CMD_WRITE_SECTOR_BUFFER out of data!\n"); - mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - mfm->callback = MFM_TIME; - return; - } - - mfm->data[mfm->data_pos] = val & 0xff; - } - - mfm->state = STATE_RECEIVED_DATA; - mfm->callback = MFM_TIME; - } else - fatal("CMD_WRITE_SECTOR_BUFFER - should never get here!\n"); - break; - - case STATE_RECEIVED_DATA: - memcpy(mfm->sector_buf, mfm->data, 512); - mfm_complete(mfm); - break; - - default: - fatal("CMD_WRITE_SECTOR_BUFFER bad state %i\n", mfm->state); - } - break; - - case CMD_BUFFER_DIAGNOSTIC: - case CMD_CONTROLLER_DIAGNOSTIC: - mfm_complete(mfm); - break; - - case 0xfa: - mfm_complete(mfm); - break; - - case CMD_DTC_SET_STEP_RATE: - mfm_complete(mfm); - break; - - case CMD_DTC_GET_DRIVE_PARAMS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 4; - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memset(mfm->data, 0, 4); - mfm->data[0] = drive->tracks & 0xff; - mfm->data[1] = 17 | ((drive->tracks >> 2) & 0xc0); - mfm->data[2] = drive->hpc-1; - mfm_xt_log("Get drive params %02x %02x %02x %i\n", mfm->data[0], mfm->data[1], mfm->data[2], drive->tracks); - break; - - case STATE_SENT_DATA: - mfm_complete(mfm); - break; - - default: - fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state); - } - break; - - case CMD_DTC_GET_GEOMETRY: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 16; - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memset(mfm->data, 0, 16); - mfm->data[0x4] = drive->tracks & 0xff; - mfm->data[0x5] = (drive->tracks >> 8) & 0xff; - mfm->data[0xa] = drive->hpc; - break; - - case STATE_SENT_DATA: - mfm_complete(mfm); - break; - } - break; - - case CMD_DTC_SET_GEOMETRY: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 16; - mfm->status = STAT_BSY | STAT_REQ; - break; - - case STATE_RECEIVED_DATA: - /*Bit of a cheat here - we always report the actual geometry of the drive in use*/ - mfm_complete(mfm); - break; - } - break; - - default: - fatal("Unknown Xebec command - %02x %02x %02x %02x %02x %02x\n", - mfm->command[0], mfm->command[1], - mfm->command[2], mfm->command[3], - mfm->command[4], mfm->command[5]); - } -} - - -static void -loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn) -{ - drive_t *drive = &mfm->drives[d]; - - if (! hdd_image_load(c)) { - drive->present = 0; - return; - } - - drive->spt = hdd[c].spt; - drive->hpc = hdd[c].hpc; - drive->tracks = hdd[c].tracks; - drive->hdd_num = c; - drive->present = 1; -} - - -static struct { - int tracks, hpc; -} hd_types[4] = { - { 306, 4 }, /* Type 0 */ - { 612, 4 }, /* Type 16 */ - { 615, 4 }, /* Type 2 */ - { 306, 8 } /* Type 13 */ -}; - - -static void -mfm_set_switches(mfm_t *mfm) -{ - int c, d; - - mfm->switches = 0; - - for (d=0; d<2; d++) { - drive_t *drive = &mfm->drives[d]; - - if (! drive->present) continue; - - for (c=0; c<4; c++) { - if (drive->spt == 17 && - drive->hpc == hd_types[c].hpc && - drive->tracks == hd_types[c].tracks) { - mfm->switches |= (c << (d ? 0 : 2)); - break; - } - } - - if (c == 4) - mfm_xt_log("WARNING: Drive %c: has format not supported by Fixed Disk Adapter", d ? 'D' : 'C'); - } -} - - -static void * -xebec_init(const device_t *info) -{ - int i, c = 0; - - mfm_t *xebec = malloc(sizeof(mfm_t)); - memset(xebec, 0x00, sizeof(mfm_t)); - - mfm_xt_log("MFM: looking for disks..\n"); - for (i=0; i MFM_NUM) break; - } - } - mfm_xt_log("MFM: %d disks loaded.\n", c); - - mfm_set_switches(xebec); - - rom_init(&xebec->bios_rom, XEBEC_BIOS_FILE, - 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - io_sethandler(0x0320, 4, - mfm_read, NULL, NULL, mfm_write, NULL, NULL, xebec); - - timer_add(mfm_callback, &xebec->callback, &xebec->callback, xebec); - - return(xebec); -} - - -static void -mfm_close(void *priv) -{ - mfm_t *mfm = (mfm_t *)priv; - int d; - - for (d=0; d<2; d++) { - drive_t *drive = &mfm->drives[d]; - - hdd_image_close(drive->hdd_num); - } - - free(mfm); -} - - -static int -xebec_available(void) -{ - return(rom_present(XEBEC_BIOS_FILE)); -} - - -const device_t mfm_xt_xebec_device = { - "IBM PC Fixed Disk Adapter", - DEVICE_ISA, - 0, - xebec_init, mfm_close, NULL, - xebec_available, NULL, NULL, NULL -}; - - -static void * -dtc5150x_init(const device_t *info) -{ - int i, c = 0; - - mfm_t *dtc = malloc(sizeof(mfm_t)); - memset(dtc, 0x00, sizeof(mfm_t)); - - mfm_xt_log("MFM: looking for disks..\n"); - for (i=0; i MFM_NUM) break; - } - } - mfm_xt_log("MFM: %d disks loaded.\n", c); - - dtc->switches = 0xff; - - dtc->drives[0].cfg_cyl = dtc->drives[0].tracks; - dtc->drives[0].cfg_hpc = dtc->drives[0].hpc; - dtc->drives[1].cfg_cyl = dtc->drives[1].tracks; - dtc->drives[1].cfg_hpc = dtc->drives[1].hpc; - - rom_init(&dtc->bios_rom, DTC_BIOS_FILE, - 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - io_sethandler(0x0320, 4, - mfm_read, NULL, NULL, mfm_write, NULL, NULL, dtc); - - timer_add(mfm_callback, &dtc->callback, &dtc->callback, dtc); - - return(dtc); -} - - -static int -dtc5150x_available(void) -{ - return(rom_present(DTC_BIOS_FILE)); -} - - -const device_t mfm_xt_dtc5150x_device = { - "DTC 5150X", - DEVICE_ISA, - 0, - dtc5150x_init, mfm_close, NULL, - dtc5150x_available, NULL, NULL, NULL -}; diff --git a/src/disk/hdc_mfm_at.c b/src/disk/hdc_st506_at.c similarity index 76% rename from src/disk/hdc_mfm_at.c rename to src/disk/hdc_st506_at.c index de2bf728e..683ade1fc 100644 --- a/src/disk/hdc_mfm_at.c +++ b/src/disk/hdc_st506_at.c @@ -12,13 +12,13 @@ * based design. Most cards were WD1003-WA2 or -WAH, where the * -WA2 cards had a floppy controller as well (to save space.) * - * Version: @(#)hdc_mfm_at.c 1.0.17 2018/05/02 + * Version: @(#)hdc_st506_at.c 1.0.21 2019/11/01 * * Authors: Sarah Walker, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. */ #define __USE_LARGEFILE64 #define _LARGEFILE_SOURCE @@ -43,7 +43,15 @@ #include "hdd.h" -#define MFM_TIME (TIMER_USEC*10LL) +#define MFM_TIME (TIMER_USEC*10) + +/*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 @@ -104,7 +112,7 @@ typedef struct { pad; int pos; /* offset within data buffer */ - int64_t callback; /* callback delay timer */ + pc_timer_t callback_timer; /* callback delay timer */ uint16_t buffer[256]; /* data buffer (16b wide) */ @@ -112,24 +120,24 @@ typedef struct { } mfm_t; -#ifdef ENABLE_MFM_AT_LOG -int mfm_at_do_log = ENABLE_MFM_AT_LOG; -#endif +#ifdef ENABLE_ST506_AT_LOG +int mfm_at_do_log = ENABLE_ST506_AT_LOG; static void -mfm_at_log(const char *fmt, ...) +st506_at_log(const char *fmt, ...) { -#ifdef ENABLE_MFM_AT_LOG va_list ap; - if (mfm_at_do_log) { + if (st506_at_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define st506_at_log(fmt, ...) +#endif static inline void @@ -145,12 +153,16 @@ irq_raise(mfm_t *mfm) static inline void irq_lower(mfm_t *mfm) { - if (mfm->irqstat) { - if (!(mfm->fdisk & 2)) - picintc(1 << 14); + picintc(1 << 14); +} - mfm->irqstat = 0; - } + + +static void +irq_update(mfm_t *mfm) +{ + if (mfm->irqstat && !((pic2.pend | pic2.ins) & 0x40) && !(mfm->fdisk & 2)) + picint(1 << 14); } @@ -171,35 +183,35 @@ get_sector(mfm_t *mfm, off64_t *addr) { drive_t *drive = &mfm->drives[mfm->drvsel]; +/* FIXME: See if this is even needed - if the code is present, IBM AT + diagnostics v2.07 will error with: ERROR 152 - SYSTEM BOARD. */ if (drive->curcyl != mfm->cylinder) { - mfm_at_log("WD1003(%d) sector: wrong cylinder\n"); + st506_at_log("WD1003(%d) sector: wrong cylinder\n"); return(1); } if (mfm->head > drive->cfg_hpc) { - mfm_at_log("WD1003(%d) get_sector: past end of configured heads\n", - mfm->drvsel); + st506_at_log("WD1003(%d) get_sector: past end of configured heads\n", + mfm->drvsel); return(1); } if (mfm->sector >= drive->cfg_spt+1) { - mfm_at_log("WD1003(%d) get_sector: past end of configured sectors\n", - mfm->drvsel); + st506_at_log("WD1003(%d) get_sector: past end of configured sectors\n", + mfm->drvsel); return(1); } -#if 1 /* We should check this in the SET_DRIVE_PARAMETERS command! --FvK */ if (mfm->head > drive->hpc) { - mfm_at_log("WD1003(%d) get_sector: past end of heads\n", mfm->drvsel); + st506_at_log("WD1003(%d) get_sector: past end of heads\n", mfm->drvsel); return(1); } if (mfm->sector >= drive->spt+1) { - mfm_at_log("WD1003(%d) get_sector: past end of sectors\n", mfm->drvsel); + st506_at_log("WD1003(%d) get_sector: past end of sectors\n", mfm->drvsel); return(1); } -#endif *addr = ((((off64_t) mfm->cylinder * drive->cfg_hpc) + mfm->head) * drive->cfg_spt) + (mfm->sector - 1); @@ -233,14 +245,11 @@ mfm_cmd(mfm_t *mfm, uint8_t val) if (! drive->present) { /* This happens if sofware polls all drives. */ - mfm_at_log("WD1003(%d) command %02x on non-present drive\n", - mfm->drvsel, val); + st506_at_log("WD1003(%d) command %02x on non-present drive\n", + mfm->drvsel, val); mfm->command = 0xff; mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); - + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); return; } @@ -251,9 +260,10 @@ mfm_cmd(mfm_t *mfm, uint8_t val) switch (val & 0xf0) { case CMD_RESTORE: drive->steprate = (val & 0x0f); - mfm_at_log("WD1003(%d) restore, step=%d\n", - mfm->drvsel, drive->steprate); + st506_at_log("WD1003(%d) restore, step=%d\n", + mfm->drvsel, drive->steprate); drive->curcyl = 0; + mfm->cylinder = 0; mfm->status = STAT_READY|STAT_DSC; mfm->command &= 0xf0; irq_raise(mfm); @@ -263,9 +273,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) drive->steprate = (val & 0x0f); mfm->command &= 0xf0; mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; default: @@ -275,23 +283,21 @@ mfm_cmd(mfm_t *mfm, uint8_t val) case CMD_READ+1: case CMD_READ+2: case CMD_READ+3: - mfm_at_log("WD1003(%d) read, opt=%d\n", - mfm->drvsel, val&0x03); + st506_at_log("WD1003(%d) read, opt=%d\n", + mfm->drvsel, val&0x03); mfm->command &= 0xfc; if (val & 2) fatal("WD1003: READ with ECC\n"); mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; case CMD_WRITE: case CMD_WRITE+1: case CMD_WRITE+2: case CMD_WRITE+3: - mfm_at_log("WD1003(%d) write, opt=%d\n", - mfm->drvsel, val & 0x03); + st506_at_log("WD1003(%d) write, opt=%d\n", + mfm->drvsel, val & 0x03); mfm->command &= 0xfc; if (val & 2) fatal("WD1003: WRITE with ECC\n"); @@ -303,9 +309,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) case CMD_VERIFY+1: mfm->command &= 0xfe; mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; case CMD_FORMAT: @@ -315,9 +319,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) case CMD_DIAGNOSE: mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; case CMD_SET_PARAMETERS: @@ -341,13 +343,13 @@ mfm_cmd(mfm_t *mfm, uint8_t val) /* Only accept after RESET or DIAG. */ drive->cfg_spt = mfm->secount; drive->cfg_hpc = mfm->head+1; - mfm_at_log("WD1003(%d) parameters: tracks=%d, spt=%i, hpc=%i\n", - mfm->drvsel, drive->tracks, - drive->cfg_spt, drive->cfg_hpc); + st506_at_log("WD1003(%d) parameters: tracks=%d, spt=%i, hpc=%i\n", + mfm->drvsel, drive->tracks, + drive->cfg_spt, drive->cfg_hpc); } else { - mfm_at_log("WD1003(%d) parameters: tracks=%d,spt=%i,hpc=%i (IGNORED)\n", - mfm->drvsel, drive->tracks, - drive->cfg_spt, drive->cfg_hpc); + st506_at_log("WD1003(%d) parameters: tracks=%d,spt=%i,hpc=%i (IGNORED)\n", + mfm->drvsel, drive->tracks, + drive->cfg_spt, drive->cfg_hpc); } mfm->command = 0x00; mfm->status = STAT_READY|STAT_DSC; @@ -356,11 +358,9 @@ mfm_cmd(mfm_t *mfm, uint8_t val) break; default: - mfm_at_log("WD1003: bad command %02X\n", val); + st506_at_log("WD1003: bad command %02X\n", val); mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200 * MFM_TIME); break; } } @@ -378,11 +378,7 @@ mfm_writew(uint16_t port, uint16_t val, void *priv) if (mfm->pos >= 512) { mfm->pos = 0; mfm->status = STAT_BUSY; - timer_clock(); - /* 781.25 us per sector at 5 Mbit/s = 640 kB/s. */ - mfm->callback = ((3125LL * TIMER_USEC) / 4LL); - /* mfm->callback = 10LL * MFM_TIME; */ - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, SECTOR_TIME); } } @@ -392,7 +388,7 @@ mfm_write(uint16_t port, uint8_t val, void *priv) { mfm_t *mfm = (mfm_t *)priv; - mfm_at_log("WD1003 write(%04x, %02x)\n", port, val); + st506_at_log("WD1003 write(%04x, %02x)\n", port, val); switch (port) { case 0x01f0: /* data */ @@ -435,24 +431,18 @@ mfm_write(uint16_t port, uint8_t val, void *priv) case 0x03f6: /* device control */ val &= 0x0f; if ((mfm->fdisk & 0x04) && !(val & 0x04)) { - timer_clock(); - mfm->callback = 500LL*MFM_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 500 * MFM_TIME); mfm->reset = 1; mfm->status = STAT_BUSY; } if (val & 0x04) { /* Drive held in reset. */ - timer_clock(); - mfm->callback = 0LL; - timer_update_outstanding(); + timer_disable(&mfm->callback_timer); mfm->status = STAT_BUSY; } mfm->fdisk = val; - /* Lower IRQ on IRQ disable. */ - if ((val & 2) && !(mfm->fdisk & 0x02)) - picintc(1 << 14); + irq_update(mfm); break; } } @@ -474,14 +464,9 @@ mfm_readw(uint16_t port, void *priv) if (mfm->secount) { next_sector(mfm); mfm->status = STAT_BUSY; - timer_clock(); - /* 781.25 us per sector at 5 Mbit/s = 640 kB/s. */ - mfm->callback = ((3125LL * TIMER_USEC) / 4LL); - /* mfm->callback = 10LL * MFM_TIME; */ - timer_update_outstanding(); - } else { + timer_set_delay_u64(&mfm->callback_timer, SECTOR_TIME); + } else ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); - } } } @@ -533,7 +518,7 @@ mfm_read(uint16_t port, void *priv) break; } - mfm_at_log("WD1003 read(%04x) = %02x\n", port, ret); + st506_at_log("WD1003 read(%04x) = %02x\n", port, ret); return(ret); } @@ -544,8 +529,8 @@ do_seek(mfm_t *mfm) { drive_t *drive = &mfm->drives[mfm->drvsel]; - mfm_at_log("WD1003(%d) seek(%d) max=%d\n", - mfm->drvsel,mfm->cylinder,drive->tracks); + st506_at_log("WD1003(%d) seek(%d) max=%d\n", + mfm->drvsel,mfm->cylinder,drive->tracks); if (mfm->cylinder < drive->tracks) drive->curcyl = mfm->cylinder; @@ -561,9 +546,8 @@ do_callback(void *priv) drive_t *drive = &mfm->drives[mfm->drvsel]; off64_t addr; - mfm->callback = 0LL; if (mfm->reset) { - mfm_at_log("WD1003(%d) reset\n", mfm->drvsel); + st506_at_log("WD1003(%d) reset\n", mfm->drvsel); mfm->status = STAT_READY|STAT_DSC; mfm->error = 1; @@ -584,16 +568,16 @@ do_callback(void *priv) switch (mfm->command) { case CMD_SEEK: - mfm_at_log("WD1003(%d) seek, step=%d\n", - mfm->drvsel, drive->steprate); + st506_at_log("WD1003(%d) seek, step=%d\n", + mfm->drvsel, drive->steprate); do_seek(mfm); mfm->status = STAT_READY|STAT_DSC; irq_raise(mfm); break; case CMD_READ: - mfm_at_log("WD1003(%d) read(%d,%d,%d)\n", - mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); + st506_at_log("WD1003(%d) read(%d,%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); do_seek(mfm); if (get_sector(mfm, &addr)) { mfm->error = ERR_ID_NOT_FOUND; @@ -611,8 +595,8 @@ do_callback(void *priv) break; case CMD_WRITE: - mfm_at_log("WD1003(%d) write(%d,%d,%d)\n", - mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); + st506_at_log("WD1003(%d) write(%d,%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); do_seek(mfm); if (get_sector(mfm, &addr)) { mfm->error = ERR_ID_NOT_FOUND; @@ -637,8 +621,8 @@ do_callback(void *priv) break; case CMD_VERIFY: - mfm_at_log("WD1003(%d) verify(%d,%d,%d)\n", - mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); + st506_at_log("WD1003(%d) verify(%d,%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); do_seek(mfm); mfm->pos = 0; mfm->status = STAT_READY|STAT_DSC; @@ -647,8 +631,8 @@ do_callback(void *priv) break; case CMD_FORMAT: - mfm_at_log("WD1003(%d) format(%d,%d)\n", - mfm->drvsel, mfm->cylinder, mfm->head); + st506_at_log("WD1003(%d) format(%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head); do_seek(mfm); if (get_sector(mfm, &addr)) { mfm->error = ERR_ID_NOT_FOUND; @@ -665,7 +649,13 @@ do_callback(void *priv) break; case CMD_DIAGNOSE: - mfm_at_log("WD1003(%d) diag\n", mfm->drvsel); + st506_at_log("WD1003(%d) diag\n", mfm->drvsel); + + /* This is basically controller diagnostics - it resets drive select to 0, + and resets error and status to ready, DSC, and no error detected. */ + mfm->drvsel = 0; + drive = &mfm->drives[mfm->drvsel]; + drive->steprate = 0x0f; mfm->error = 1; mfm->status = STAT_READY|STAT_DSC; @@ -673,8 +663,8 @@ do_callback(void *priv) break; default: - mfm_at_log("WD1003(%d) callback on unknown command %02x\n", - mfm->drvsel, mfm->command); + st506_at_log("WD1003(%d) callback on unknown command %02x\n", + mfm->drvsel, mfm->command); mfm->status = STAT_READY|STAT_ERR|STAT_DSC; mfm->error = ERR_ABRT; irq_raise(mfm); @@ -708,7 +698,7 @@ mfm_init(const device_t *info) mfm_t *mfm; int c, d; - mfm_at_log("WD1003: ISA MFM/RLL Fixed Disk Adapter initializing ...\n"); + st506_at_log("WD1003: ISA MFM/RLL Fixed Disk Adapter initializing ...\n"); mfm = malloc(sizeof(mfm_t)); memset(mfm, 0x00, sizeof(mfm_t)); @@ -717,8 +707,8 @@ mfm_init(const device_t *info) if ((hdd[d].bus == HDD_BUS_MFM) && (hdd[d].mfm_channel < MFM_NUM)) { loadhd(mfm, hdd[d].mfm_channel, d, hdd[d].fn); - mfm_at_log("WD1003(%d): (%ls) geometry %d/%d/%d\n", c, hdd[d].fn, - (int)hdd[d].tracks, (int)hdd[d].hpc, (int)hdd[d].spt); + st506_at_log("WD1003(%d): (%ls) geometry %d/%d/%d\n", c, hdd[d].fn, + (int)hdd[d].tracks, (int)hdd[d].hpc, (int)hdd[d].spt); if (++c >= MFM_NUM) break; } @@ -734,7 +724,7 @@ mfm_init(const device_t *info) io_sethandler(0x03f6, 1, NULL, NULL, NULL, mfm_write, NULL, NULL, mfm); - timer_add(do_callback, &mfm->callback, &mfm->callback, mfm); + timer_add(&mfm->callback_timer, do_callback, mfm, 0); ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); @@ -760,7 +750,7 @@ mfm_close(void *priv) } -const device_t mfm_at_wd1003_device = { +const device_t st506_at_wd1003_device = { "WD1003 AT MFM/RLL Controller", DEVICE_ISA | DEVICE_AT, 0, diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c new file mode 100644 index 000000000..a49e866fe --- /dev/null +++ b/src/disk/hdc_st506_xt.c @@ -0,0 +1,1885 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Driver for the IBM PC-XT Fixed Disk controller. + * + * The original controller shipped by IBM was made by Xebec, and + * several variations had been made: + * + * #1 Original, single drive (ST412), 10MB, 2 heads. + * #2 Update, single drive (ST412) but with option for a + * switch block that can be used to 'set' the actual + * drive type. Four switches are defined, where switches + * 1 and 2 define drive0, and switches 3 and 4 drive1. + * + * 0 ON ON 306 2 0 + * 1 ON OFF 375 8 0 + * 2 OFF ON 306 6 256 + * 3 OFF OFF 306 4 0 + * + * The latter option is the default, in use on boards + * without the switch block option. + * + * #3 Another updated board, mostly to accomodate the new + * 20MB disk now being shipped. The controller can have + * up to 2 drives, the type of which is set using the + * switch block: + * + * SW1 SW2 CYLS HD SPT WPC + * 0 ON ON 306 4 17 0 + * 1 ON OFF 612 4 17 0 (type 16) + * 2 OFF ON 615 4 17 300 (Seagate ST-225, 2) + * 3 OFF OFF 306 8 17 128 (IBM WD25, 13) + * + * Examples of #3 are IBM/Xebec, WD10004A-WX1 and ST11R. + * + * Since all controllers (including the ones made by DTC) use + * (mostly) the same API, we keep them all in this module. + * + * Version: @(#)hdc_st506_xt.c 1.0.17 2019/10/20 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../ui.h" +#include "../plat.h" +#include "../dma.h" +#include "../pic.h" +#include "hdc.h" +#include "hdd.h" + + +#define XEBEC_BIOS_FILE L"roms/hdd/st506/ibm_xebec_62x0822_1985.bin" +#define DTC_BIOS_FILE L"roms/hdd/st506/dtc_cxd21a.bin" +#define ST11_BIOS_FILE_OLD L"roms/hdd/st506/st11_bios_vers_1.7.bin" +#define ST11_BIOS_FILE_NEW L"roms/hdd/st506/st11_bios_vers_2.0.bin" +#define WD1002A_WX1_BIOS_FILE L"roms/hdd/st506/wd1002a_wx1-62-000094-032.bin" +/* SuperBIOS was for both the WX1 and 27X, users jumpers readout to determine + if to use 26 sectors per track, 26 -> 17 sectors per track translation, or + 17 sectors per track. */ +#define WD1002A_27X_BIOS_FILE L"roms/hdd/st506/wd1002a_27x-62-000094-032.bin" + + +#define ST506_TIME (250 * TIMER_USEC) +#define ST506_TIME_MS (1000 * TIMER_USEC) + +/* MFM and RLL use different sectors/track. */ +#define SECTOR_SIZE 512 +#define MFM_SECTORS 17 +#define RLL_SECTORS 26 + + +/* Status register. */ +#define STAT_REQ 0x01 /* controller ready */ +#define STAT_IO 0x02 /* input, data to host */ +#define STAT_CD 0x04 /* command mode (else data) */ +#define STAT_BSY 0x08 /* controller is busy */ +#define STAT_DRQ 0x10 /* controller needs DMA */ +#define STAT_IRQ 0x20 /* interrupt, we have info */ + +/* DMA/IRQ enable register. */ +#define DMA_ENA 0x01 /* DMA operation enabled */ +#define IRQ_ENA 0x02 /* IRQ operation enabled */ + +/* Error codes in sense report. */ +#define ERR_BV 0x80 +#define ERR_TYPE_MASK 0x30 +#define ERR_TYPE_SHIFT 4 +# define ERR_TYPE_DRIVE 0x00 +# define ERR_TYPE_CONTROLLER 0x01 +# define ERR_TYPE_COMMAND 0x02 +# define ERR_TYPE_MISC 0x03 + +/* No, um, errors.. */ +#define ERR_NONE 0x00 + +/* Group 0: drive errors. */ +#define ERR_NO_SEEK 0x02 /* no seek_complete */ +#define ERR_WR_FAULT 0x03 /* write fault */ +#define ERR_NOT_READY 0x04 /* drive not ready */ +#define ERR_NO_TRACK0 0x06 /* track 0 not found */ +#define ERR_STILL_SEEKING 0x08 /* drive is still seeking */ +#define ERR_NOT_AVAILABLE 0x09 /* drive not available */ + +/* Group 1: controller errors. */ +#define ERR_ID_FAULT 0x10 /* could not read ID field */ +#define ERR_UNC_ERR 0x11 /* uncorrectable data */ +#define ERR_SECTOR_ADDR 0x12 /* sector address */ +#define ERR_DATA_ADDR 0x13 /* data mark not found */ +#define ERR_TARGET_SECTOR 0x14 /* target sector not found */ +#define ERR_SEEK_ERROR 0x15 /* seek error- cyl not found */ +#define ERR_CORR_ERR 0x18 /* correctable data */ +#define ERR_BAD_TRACK 0x19 /* track is flagged as bad */ +#define ERR_ALT_TRACK_FLAGGED 0x1c /* alt trk not flagged as alt */ +#define ERR_ALT_TRACK_ACCESS 0x1e /* illegal access to alt trk */ +#define ERR_NO_RECOVERY 0x1f /* recovery mode not avail */ + +/* Group 2: command errors. */ +#define ERR_BAD_COMMAND 0x20 /* invalid command */ +#define ERR_ILLEGAL_ADDR 0x21 /* address beyond disk size */ +#define ERR_BAD_PARAMETER 0x22 /* invalid command parameter */ + +/* Group 3: misc errors. */ +#define ERR_BAD_RAM 0x30 /* controller has bad RAM */ +#define ERR_BAD_ROM 0x31 /* ROM failed checksum test */ +#define ERR_CRC_FAIL 0x32 /* CRC circuit failed test */ + +/* Controller commands. */ +#define CMD_TEST_DRIVE_READY 0x00 +#define CMD_RECALIBRATE 0x01 +/* reserved 0x02 */ +#define CMD_STATUS 0x03 +#define CMD_FORMAT_DRIVE 0x04 +#define CMD_VERIFY 0x05 +#define CMD_FORMAT_TRACK 0x06 +#define CMD_FORMAT_BAD_TRACK 0x07 +#define CMD_READ 0x08 +#define CMD_REASSIGN 0x09 +#define CMD_WRITE 0x0a +#define CMD_SEEK 0x0b +#define CMD_SPECIFY 0x0c +#define CMD_READ_ECC_BURST_LEN 0x0d +#define CMD_READ_BUFFER 0x0e +#define CMD_WRITE_BUFFER 0x0f +#define CMD_ALT_TRACK 0x11 +#define CMD_INQUIRY_ST11 0x12 /* ST-11 BIOS */ +#define CMD_RAM_DIAGNOSTIC 0xe0 +/* reserved 0xe1 */ +/* reserved 0xe2 */ +#define CMD_DRIVE_DIAGNOSTIC 0xe3 +#define CMD_CTRLR_DIAGNOSTIC 0xe4 +#define CMD_READ_LONG 0xe5 +#define CMD_WRITE_LONG 0xe6 + +#define CMD_FORMAT_ST11 0xf6 /* ST-11 BIOS */ +#define CMD_GET_GEOMETRY_ST11 0xf8 /* ST-11 BIOS */ +#define CMD_SET_GEOMETRY_ST11 0xfa /* ST-11 BIOS */ +#define CMD_WRITE_GEOMETRY_ST11 0xfc /* ST-11 BIOS 2.0 */ + +#define CMD_GET_DRIVE_PARAMS_DTC 0xfb /* DTC */ +#define CMD_SET_STEP_RATE_DTC 0xfc /* DTC */ +#define CMD_SET_GEOMETRY_DTC 0xfe /* DTC */ +#define CMD_GET_GEOMETRY_DTC 0xff /* DTC */ + +enum { + STATE_IDLE, + STATE_RECEIVE_COMMAND, + STATE_START_COMMAND, + STATE_RECEIVE_DATA, + STATE_RECEIVED_DATA, + STATE_SEND_DATA, + STATE_SENT_DATA, + STATE_COMPLETION_BYTE, + STATE_DONE +}; + + +typedef struct { + int8_t present; + uint8_t hdd_num; + + uint8_t interleave; /* default interleave */ + char pad; + + uint16_t cylinder; /* current cylinder */ + + uint8_t spt, /* physical parameters */ + hpc; + uint16_t tracks; + + uint8_t cfg_spt, /* configured parameters */ + cfg_hpc; + uint16_t cfg_cyl; +} drive_t; + + +typedef struct { + uint8_t type; /* controller type */ + + uint8_t spt; /* sectors-per-track for controller */ + + uint16_t base; /* controller configuration */ + int8_t irq, + dma; + uint8_t switches; + uint8_t misc; + uint8_t nr_err, err_bv, cur_sec, pad; + uint32_t bios_addr, + bios_size, + bios_ram; + rom_t bios_rom; + + int state; /* operational data */ + uint8_t irq_dma; + uint8_t error; + uint8_t status; + int8_t cyl_off; /* for ST-11, cylinder0 offset */ + pc_timer_t timer; + + uint8_t command[6]; /* current command request */ + int drive_sel; + int sector, + head, + cylinder, + count; + uint8_t compl; /* current request completion code */ + + int buff_pos, /* pointers to the RAM buffer */ + buff_cnt; + + drive_t drives[MFM_NUM]; /* the attached drives */ + uint8_t scratch[64]; /* ST-11 scratchpad RAM */ + uint8_t buff[SECTOR_SIZE + 4]; /* sector buffer RAM (+ ECC bytes) */ +} hdc_t; + + +/* Supported drives table for the Xebec controller. */ +typedef struct { + uint16_t tracks; + uint8_t hpc; + uint8_t spt; +} hd_type_t; + +hd_type_t hd_types[4] = { + { 306, 4, MFM_SECTORS }, /* type 0 */ + { 612, 4, MFM_SECTORS }, /* type 16 */ + { 615, 4, MFM_SECTORS }, /* type 2 */ + { 306, 8, MFM_SECTORS } /* type 13 */ +}; + + +#ifdef ENABLE_ST506_XT_LOG +int st506_xt_do_log = ENABLE_ST506_XT_LOG; + + +static void +st506_xt_log(const char *fmt, ...) +{ + va_list ap; + + if (st506_xt_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define st506_xt_log(fmt, ...) +#endif + + +static void +st506_complete(hdc_t *dev) +{ + dev->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; + dev->state = STATE_COMPLETION_BYTE; + + if (dev->irq_dma & DMA_ENA) + dma_set_drq(dev->dma, 0); + + if (dev->irq_dma & IRQ_ENA) { + dev->status |= STAT_IRQ; + picint(1 << dev->irq); + } +} + + +static void +st506_error(hdc_t *dev, uint8_t err) +{ + dev->compl |= 0x02; + dev->error = err; +} + + +static int +get_sector(hdc_t *dev, drive_t *drive, off64_t *addr) +{ + if (! drive->present) { + /* No need to log this. */ + dev->error = dev->nr_err; + return(0); + } + +#if 0 + if (drive->cylinder != dev->cylinder) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: get_sector: wrong cylinder\n"); +#endif + dev->error = ERR_ILLEGAL_ADDR; + return(0); + } +#endif + + if (dev->head >= drive->cfg_hpc) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: get_sector: past end of configured heads\n"); +#endif + dev->error = ERR_ILLEGAL_ADDR; + return(0); + } + if (dev->sector >= drive->cfg_spt) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: get_sector: past end of configured sectors\n"); +#endif + dev->error = ERR_ILLEGAL_ADDR; + return(0); + } + + *addr = ((((off64_t)dev->cylinder * drive->cfg_hpc) + dev->head) * drive->cfg_spt) + dev->sector; + + return(1); +} + + +static void +next_sector(hdc_t *dev, drive_t *drive) +{ + if (++dev->sector >= drive->cfg_spt) { + dev->sector = 0; + if (++dev->head >= drive->cfg_hpc) { + dev->head = 0; + if (++drive->cylinder >= drive->cfg_cyl) { + /* + * This really is an error, we cannot move + * past the end of the drive, which should + * result in an ERR_ILLEGAL_ADDR. --FvK + */ + drive->cylinder = drive->cfg_cyl - 1; + } else + dev->cylinder++; + } + } +} + + +/* Extract the CHS info from a command block. */ +static int +get_chs(hdc_t *dev, drive_t *drive) +{ + dev->err_bv = 0x80; + + dev->head = dev->command[1] & 0x1f; + /* 6 bits are used for the sector number even on the IBM PC controller. */ + dev->sector = dev->command[2] & 0x3f; + dev->count = dev->command[4]; + if (((dev->type == 11) || (dev->type == 12)) && (dev->command[0] >= 0xf0)) + dev->cylinder = 0; + else { + dev->cylinder = dev->command[3] | ((dev->command[2] & 0xc0) << 2); + dev->cylinder += dev->cyl_off; /* for ST-11 */ + } + + if (dev->cylinder >= drive->cfg_cyl) { + /* + * This really is an error, we cannot move + * past the end of the drive, which should + * result in an ERR_ILLEGAL_ADDR. --FvK + */ + drive->cylinder = drive->cfg_cyl - 1; + return(0); + } + + drive->cylinder = dev->cylinder; + + return(1); +} + + +static void +st506_callback(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + drive_t *drive; + off64_t addr; + uint32_t capac; + int val; + + /* Get the drive info. Note that the API supports up to 8 drives! */ + dev->drive_sel = (dev->command[1] >> 5) & 0x07; + drive = &dev->drives[dev->drive_sel]; + + /* Preset the completion byte to "No error" and the selected drive. */ + dev->compl = (dev->drive_sel << 5) | ERR_NONE; + + if (dev->command[0] != 3) + dev->err_bv = 0x00; + + switch (dev->command[0]) { + case CMD_TEST_DRIVE_READY: + st506_xt_log("ST506: TEST_READY(%i) = %i\n", + dev->drive_sel, drive->present); + if (! drive->present) + st506_error(dev, dev->nr_err); + st506_complete(dev); + break; + + case CMD_RECALIBRATE: + switch (dev->state) { + case STATE_START_COMMAND: + st506_xt_log("ST506: RECALIBRATE(%i) [%i]\n", + dev->drive_sel, drive->present); + if (! drive->present) { + st506_error(dev, dev->nr_err); + st506_complete(dev); + break; + } + + /* Wait 20msec. */ + timer_advance_u64(&dev->timer, ST506_TIME_MS * 20); + + dev->cylinder = dev->cyl_off; + drive->cylinder = dev->cylinder; + dev->state = STATE_DONE; + + break; + + case STATE_DONE: + st506_complete(dev); + break; + } + break; + + case CMD_STATUS: + switch (dev->state) { + case STATE_START_COMMAND: +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: STATUS\n"); +#endif + dev->buff_pos = 0; + dev->buff_cnt = 4; + dev->buff[0] = dev->err_bv | dev->error; + dev->error = 0; + + /* Give address of last operation. */ + dev->buff[1] = (dev->drive_sel ? 0x20 : 0) | + dev->head; + dev->buff[2] = ((dev->cylinder & 0x0300) >> 2) | + dev->sector; + dev->buff[3] = (dev->cylinder & 0xff); + + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_FORMAT_DRIVE: + switch (dev->state) { + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: FORMAT_DRIVE(%i) interleave=%i\n", + dev->drive_sel, dev->command[4]); + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + timer_advance_u64(&dev->timer, ST506_TIME); + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: /* wrong, but works */ + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + /* FIXME: should be drive->capac, not ->spt */ + capac = (drive->tracks - 1) * drive->hpc * drive->spt; + hdd_image_zero(drive->hdd_num, addr, capac); + + /* Wait 20msec per cylinder. */ + timer_advance_u64(&dev->timer, ST506_TIME_MS * 20); + + dev->state = STATE_SENT_DATA; + break; + + case STATE_SENT_DATA: + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + break; + } + break; + + case CMD_VERIFY: + switch (dev->state) { + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: VERIFY(%i, %i/%i/%i, %i)\n", + dev->drive_sel, dev->cylinder, + dev->head, dev->sector, dev->count); + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + timer_advance_u64(&dev->timer, ST506_TIME); + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: + if (dev->count-- == 0) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + } + + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + next_sector(dev, drive); + + timer_advance_u64(&dev->timer, ST506_TIME); + break; + } + break; + + case CMD_FORMAT_ST11: /* This is really "Format cylinder 0" */ + if ((dev->type < 11) || (dev->type > 12)) { + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + break; + } + case CMD_FORMAT_TRACK: + case CMD_FORMAT_BAD_TRACK: + switch (dev->state) { + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: FORMAT_%sTRACK(%i, %i/%i)\n", + (dev->command[0] == CMD_FORMAT_BAD_TRACK) ? "BAD_" : "", + dev->drive_sel, dev->cylinder, dev->head); + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + timer_advance_u64(&dev->timer, ST506_TIME); + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: /* wrong, but works */ + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + hdd_image_zero(drive->hdd_num, + addr, drive->cfg_spt); + + /* Wait 20 msec per cylinder. */ + timer_advance_u64(&dev->timer, ST506_TIME_MS * 20); + + dev->state = STATE_SENT_DATA; + break; + + case STATE_SENT_DATA: + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + break; + } + break; + + case CMD_GET_GEOMETRY_ST11: /* "Get geometry" is really "Read cylinder 0" */ + if ((dev->type < 11) || (dev->type > 12)) { + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + break; + } + case CMD_READ: +#if 0 + case CMD_READ_LONG: +#endif + switch (dev->state) { + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: READ%s(%i, %i/%i/%i, %i)\n", + (dev->command[0] == CMD_READ_LONG) ? "_LONG" : "", + dev->drive_sel, dev->cylinder, + dev->head, dev->sector, dev->count); + + if (! get_sector(dev, drive, &addr)) { + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + + /* Read data from the image. */ + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)dev->buff); + + /* Set up the data transfer. */ + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + if (dev->command[0] == CMD_READ_LONG) + dev->buff_cnt += 4; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + timer_advance_u64(&dev->timer, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: + for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { + val = dma_channel_write(dev->dma, dev->buff[dev->buff_pos]); + if (val == DMA_NODATA) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CMD_READ out of data!\n"); +#endif + st506_error(dev, ERR_NO_RECOVERY); + st506_complete(dev); + return; + } + } + dma_set_drq(dev->dma, 0); + timer_advance_u64(&dev->timer, ST506_TIME); + dev->state = STATE_SENT_DATA; + break; + + case STATE_SENT_DATA: + if (--dev->count == 0) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + break; + } + + next_sector(dev, drive); + + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + /* Read data from the image. */ + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)dev->buff); + + /* Set up the data transfer. */ + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + timer_advance_u64(&dev->timer, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_SEND_DATA; + break; + } + break; + + case CMD_SET_GEOMETRY_ST11: /* "Set geometry" is really "Write cylinder 0" */ + if (dev->type == 1) { + /* DTC sends this... */ + st506_complete(dev); + break; + } else if ((dev->type < 11) || (dev->type > 12)) { + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + break; + } + case CMD_WRITE: +#if 0 + case CMD_WRITE_LONG: +#endif + switch (dev->state) { + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: WRITE%s(%i, %i/%i/%i, %i)\n", + (dev->command[0] == CMD_WRITE_LONG) ? "_LONG" : "", + dev->drive_sel, dev->cylinder, + dev->head, dev->sector, dev->count); + + if (! get_sector(dev, drive, &addr)) { + st506_error(dev, ERR_BAD_PARAMETER); + st506_complete(dev); + return; + } + + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + + /* Set up the data transfer. */ + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + if (dev->command[0] == CMD_WRITE_LONG) + dev->buff_cnt += 4; + dev->status = STAT_BSY | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + timer_advance_u64(&dev->timer, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_RECEIVE_DATA; + break; + + case STATE_RECEIVE_DATA: + for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CMD_WRITE out of data!\n"); +#endif + st506_error(dev, ERR_NO_RECOVERY); + st506_complete(dev); + return; + } + dev->buff[dev->buff_pos] = val & 0xff; + } + + dma_set_drq(dev->dma, 0); + timer_advance_u64(&dev->timer, ST506_TIME); + dev->state = STATE_RECEIVED_DATA; + break; + + case STATE_RECEIVED_DATA: + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + /* Write data to image. */ + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)dev->buff); + + if (--dev->count == 0) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + break; + } + + next_sector(dev, drive); + + /* Set up the data transfer. */ + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + dev->status = STAT_BSY | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + timer_advance_u64(&dev->timer, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_RECEIVE_DATA; + break; + } + break; + + case CMD_SEEK: + if (drive->present) { + val = get_chs(dev, drive); + st506_xt_log("ST506: SEEK(%i, %i) [%i]\n", + dev->drive_sel, drive->cylinder, val); + if (! val) + st506_error(dev, ERR_SEEK_ERROR); + } else + st506_error(dev, dev->nr_err); + st506_complete(dev); + break; + + case CMD_SPECIFY: + switch (dev->state) { + case STATE_START_COMMAND: + dev->buff_pos = 0; + dev->buff_cnt = 8; + dev->status = STAT_BSY | STAT_REQ; + dev->state = STATE_RECEIVE_DATA; + break; + + case STATE_RECEIVED_DATA: + drive->cfg_cyl = dev->buff[1] | (dev->buff[0] << 8); + drive->cfg_hpc = dev->buff[2]; + /* For a 615/4/26 we get 666/2/31 geometry. */ + st506_xt_log("ST506: drive%i: cyls=%i, heads=%i\n", + dev->drive_sel, drive->cfg_cyl, drive->cfg_hpc); + st506_complete(dev); + break; + } + break; + + case CMD_READ_ECC_BURST_LEN: + switch (dev->state) { + case STATE_START_COMMAND: +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: READ_ECC_BURST_LEN\n"); +#endif + dev->buff_pos = 0; + dev->buff_cnt = 1; + dev->buff[0] = 0; /* 0 bits */ + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_READ_BUFFER: + switch (dev->state) { + case STATE_START_COMMAND: + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + st506_xt_log("ST506: READ_BUFFER (%i)\n", + dev->buff_cnt); + + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + timer_advance_u64(&dev->timer, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: + for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { + val = dma_channel_write(dev->dma, dev->buff[dev->buff_pos]); + if (val == DMA_NODATA) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CMD_READ_BUFFER out of data!\n"); +#endif + st506_error(dev, ERR_NO_RECOVERY); + st506_complete(dev); + return; + } + } + + dma_set_drq(dev->dma, 0); + timer_advance_u64(&dev->timer, ST506_TIME); + dev->state = STATE_SENT_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_WRITE_BUFFER: + switch (dev->state) { + case STATE_START_COMMAND: + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + st506_xt_log("ST506: WRITE_BUFFER (%i)\n", + dev->buff_cnt); + + dev->status = STAT_BSY | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + timer_advance_u64(&dev->timer, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_RECEIVE_DATA; + break; + + case STATE_RECEIVE_DATA: + for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CMD_WRITE_BUFFER out of data!\n"); +#endif + st506_error(dev, ERR_NO_RECOVERY); + st506_complete(dev); + return; + } + dev->buff[dev->buff_pos] = val & 0xff; + } + + dma_set_drq(dev->dma, 0); + timer_advance_u64(&dev->timer, ST506_TIME); + dev->state = STATE_RECEIVED_DATA; + break; + + case STATE_RECEIVED_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_INQUIRY_ST11: + if (dev->type == 11 || dev->type == 12) switch (dev->state) { + case STATE_START_COMMAND: + st506_xt_log("ST506: INQUIRY (type=%i)\n", dev->type); + dev->buff_pos = 0; + dev->buff_cnt = 2; + dev->buff[0] = 0x80; /* "ST-11" */ + if (dev->spt == 17) + dev->buff[0] |= 0x40; /* MFM */ + dev->buff[1] = dev->misc; /* revision */ + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } else { + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + } + break; + + case CMD_RAM_DIAGNOSTIC: +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: RAM_DIAG\n"); +#endif + st506_complete(dev); + break; + + case CMD_CTRLR_DIAGNOSTIC: +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CTRLR_DIAG\n"); +#endif + st506_complete(dev); + break; + + case CMD_SET_STEP_RATE_DTC: + if (dev->type == 1) { + /* For DTC, we are done. */ + st506_complete(dev); + } else if (dev->type == 11 || dev->type == 12) { + /* + * For Seagate ST-11, this is WriteGeometry. + * + * This writes the contents of the buffer to track 0. + * + * By the time this command is sent, it will have + * formatted the first track, so it should be good, + * and our sector buffer contains the magic data + * (see above) we need to write to it. + */ + (void)get_chs(dev, drive); + st506_xt_log("ST506: WRITE BUFFER (%i, %i/%i/%i, %i)\n", + dev->drive_sel, dev->cylinder, + dev->head, dev->sector, dev->count); + + if (! get_sector(dev, drive, &addr)) { + st506_error(dev, ERR_BAD_PARAMETER); + st506_complete(dev); + return; + } + + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + + /* Write data to image. */ + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)dev->buff); + + if (--dev->count == 0) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + break; + } + + next_sector(dev, drive); + timer_advance_u64(&dev->timer, ST506_TIME); + break; + } else { + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + } + break; + + case CMD_GET_DRIVE_PARAMS_DTC: + switch (dev->state) { + case STATE_START_COMMAND: + dev->buff_pos = 0; + dev->buff_cnt = 4; + memset(dev->buff, 0x00, dev->buff_cnt); + dev->buff[0] = drive->tracks & 0xff; + dev->buff[1] = ((drive->tracks >> 2) & 0xc0) | dev->spt; + dev->buff[2] = drive->hpc - 1; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_SET_GEOMETRY_DTC: + switch (dev->state) { + case STATE_START_COMMAND: + val = dev->command[1] & 0x01; + st506_xt_log("ST506: DTC_GET_GEOMETRY(%i) %i\n", + dev->drive_sel, val); + dev->buff_pos = 0; + dev->buff_cnt = 16; + dev->status = STAT_BSY | STAT_REQ; + dev->state = STATE_RECEIVE_DATA; + break; + + case STATE_RECEIVED_DATA: + /* FIXME: ignore the results. */ + st506_complete(dev); + break; + } + break; + + case CMD_GET_GEOMETRY_DTC: + switch (dev->state) { + case STATE_START_COMMAND: + val = dev->command[1] & 0x01; + st506_xt_log("ST506: DTC_GET_GEOMETRY(%i) %i\n", + dev->drive_sel, val); + dev->buff_pos = 0; + dev->buff_cnt = 16; + memset(dev->buff, 0x00, dev->buff_cnt); + dev->buff[4] = drive->tracks & 0xff; + dev->buff[5] = (drive->tracks >> 8) & 0xff; + dev->buff[10] = drive->hpc; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + default: + if (dev->command[0] == CMD_WRITE_GEOMETRY_ST11) + fatal("CMD_WRITE_GEOMETRY_ST11\n"); +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: unknown command:\n"); +#endif + st506_xt_log("ST506: %02x %02x %02x %02x %02x %02x\n", + dev->command[0], dev->command[1], dev->command[2], + dev->command[3], dev->command[4], dev->command[5]); + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + } +} + + +/* Read from one of the registers. */ +static uint8_t +st506_read(uint16_t port, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint8_t ret = 0xff; + + switch (port & 3) { + case 0: /* read data */ + dev->status &= ~STAT_IRQ; + switch (dev->state) { + case STATE_COMPLETION_BYTE: + ret = dev->compl; + dev->status = 0x00; + dev->state = STATE_IDLE; + break; + + case STATE_SEND_DATA: + ret = dev->buff[dev->buff_pos++]; + if (dev->buff_pos == dev->buff_cnt) { + dev->buff_pos = 0; + dev->buff_cnt = 0; + dev->status = STAT_BSY; + dev->state = STATE_SENT_DATA; + timer_set_delay_u64(&dev->timer, ST506_TIME); + } + break; + } + break; + + case 1: /* read status */ + ret = dev->status; + if ((dev->irq_dma & DMA_ENA) && dma_get_drq(dev->dma)) + ret |= STAT_DRQ; + break; + + case 2: /* read option jumpers */ + ret = dev->switches; + break; + } + st506_xt_log("ST506: read(%04x) = %02x\n", port, ret); + + return(ret); +} + + +/* Write to one of the registers. */ +static void +st506_write(uint16_t port, uint8_t val, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + + st506_xt_log("ST506: write(%04x, %02x)\n", port, val); + switch (port & 3) { + case 0: /* write data */ + switch (dev->state) { + case STATE_RECEIVE_COMMAND: /* command data */ + /* Write directly to the command buffer to avoid overwriting + the data buffer. */ + dev->command[dev->buff_pos++] = val; + if (dev->buff_pos == dev->buff_cnt) { + /* We have a new command. */ + dev->buff_pos = 0; + dev->buff_cnt = 0; + dev->status = STAT_BSY; + dev->state = STATE_START_COMMAND; + timer_set_delay_u64(&dev->timer, ST506_TIME); + } + break; + + case STATE_RECEIVE_DATA: /* data */ + dev->buff[dev->buff_pos++] = val; + if (dev->buff_pos == dev->buff_cnt) { + dev->buff_pos = 0; + dev->buff_cnt = 0; + dev->status = STAT_BSY; + dev->state = STATE_RECEIVED_DATA; + timer_set_delay_u64(&dev->timer, ST506_TIME); + } + break; + } + break; + + case 1: /* controller reset */ + dev->status = 0x00; + break; + + case 2: /* generate controller-select-pulse */ + dev->status = STAT_BSY | STAT_CD | STAT_REQ; + dev->buff_pos = 0; + dev->buff_cnt = sizeof(dev->command); + dev->state = STATE_RECEIVE_COMMAND; + break; + + case 3: /* DMA/IRQ enable register */ + dev->irq_dma = val; + + if (!(dev->irq_dma & DMA_ENA)) + dma_set_drq(dev->dma, 0); + + if (!(dev->irq_dma & IRQ_ENA)) { + dev->status &= ~STAT_IRQ; + picintc(1 << dev->irq); + } + break; + } +} + + +/* Write to ROM (or scratchpad RAM.) */ +static void +mem_write(uint32_t addr, uint8_t val, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint32_t ptr, mask = 0; + + /* Ignore accesses to anything below the configured address, + needed because of the emulator's 4k mapping granularity. */ + if (addr < dev->bios_addr) + return; + + addr -= dev->bios_addr; + + switch(dev->type) { + case 11: /* ST-11M */ + case 12: /* ST-11R */ + mask = 0x1fff; /* ST-11 decodes RAM on each 8K block */ + break; + + default: + break; + } + + addr &= dev->bios_rom.mask; + + ptr = (dev->bios_rom.mask & mask) - dev->bios_ram; + if (mask && ((addr & mask) > ptr) && + ((addr & mask) <= (ptr + dev->bios_ram))) + dev->scratch[addr & (dev->bios_ram - 1)] = val; +} + + +static uint8_t +mem_read(uint32_t addr, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint32_t ptr, mask = 0; + uint8_t ret = 0xff; + + /* Ignore accesses to anything below the configured address, + needed because of the emulator's 4k mapping granularity. */ + if (addr < dev->bios_addr) + return 0xff; + + addr -= dev->bios_addr; + + switch(dev->type) { + case 0: /* Xebec */ + if (addr >= 0x001000) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: Xebec ROM access(0x%06lx)\n", addr); +#endif + return 0xff; + } + break; + + case 1: /* DTC */ + default: + if (addr >= 0x002000) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: DTC-5150X ROM access(0x%06lx)\n", addr); +#endif + return 0xff; + } + break; + + case 11: /* ST-11M */ + case 12: /* ST-11R */ + mask = 0x1fff; /* ST-11 decodes RAM on each 8K block */ + break; + + /* default: + break; */ + } + + addr = addr & dev->bios_rom.mask; + + ptr = (dev->bios_rom.mask & mask) - dev->bios_ram; + if (mask && ((addr & mask) > ptr) && + ((addr & mask) <= (ptr + dev->bios_ram))) + ret = dev->scratch[addr & (dev->bios_ram - 1)]; + else + ret = dev->bios_rom.rom[addr]; + + return(ret); +} + + +/* + * Set up and load the ROM BIOS for this controller. + * + * This is straightforward for most, but some (like the ST-11x) + * map part of the area as scratchpad RAM, so we cannot use the + * standard 'rom_init' function here. + */ +static void +loadrom(hdc_t *dev, const wchar_t *fn) +{ + uint32_t size; + FILE *fp; + + if ((fp = rom_fopen((wchar_t *) fn, L"rb")) == NULL) { + st506_xt_log("ST506: BIOS ROM '%ls' not found!\n", fn); + return; + } + + /* Initialize the ROM entry. */ + memset(&dev->bios_rom, 0x00, sizeof(rom_t)); + + /* Manually load and process the ROM image. */ + (void)fseek(fp, 0L, SEEK_END); + size = ftell(fp); + (void)fseek(fp, 0L, SEEK_SET); + + /* Load the ROM data. */ + dev->bios_rom.rom = (uint8_t *)malloc(size); + memset(dev->bios_rom.rom, 0xff, size); + (void)fread(dev->bios_rom.rom, size, 1, fp); + (void)fclose(fp); + + /* Set up an address mask for this memory. */ + dev->bios_size = size; + dev->bios_rom.mask = (size - 1); + + /* Map this system into the memory map. */ + mem_mapping_add(&dev->bios_rom.mapping, dev->bios_addr, size, + mem_read,NULL,NULL, mem_write,NULL,NULL, + dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +loadhd(hdc_t *dev, int c, int d, const wchar_t *fn) +{ + drive_t *drive = &dev->drives[c]; + + if (! hdd_image_load(d)) { + drive->present = 0; + return; + } + + /* Make sure we can do this. */ + /* Allow 31 sectors per track on RLL controllers, for the + ST225R, which is 667/2/31. */ + if ((hdd[d].spt != dev->spt) && (hdd[d].spt != 31) && (dev->spt != 26)) { + /* + * Uh-oh, MFM/RLL mismatch. + * + * Although this would be no issue in the code itself, + * most of the BIOSes were hardwired to whatever their + * native SPT setting was, so, do not allow this here. + */ + st506_xt_log("ST506: drive%i: MFM/RLL mismatch (%i/%i)\n", + c, hdd[d].spt, dev->spt); + hdd_image_close(d); + drive->present = 0; + return; + } + + drive->spt = (uint8_t)hdd[d].spt; + drive->hpc = (uint8_t)hdd[d].hpc; + drive->tracks = (uint16_t)hdd[d].tracks; + + drive->hdd_num = d; + drive->present = 1; +} + + +/* Set the "drive type" switches for the IBM Xebec controller. */ +static void +set_switches(hdc_t *dev) +{ + drive_t *drive; + int c, d; + + dev->switches = 0x00; + + for (d = 0; d < MFM_NUM; d++) { + drive = &dev->drives[d]; + + if (! drive->present) continue; + + for (c = 0; c < 4; c++) { + if ((drive->spt == hd_types[c].spt) && + (drive->hpc == hd_types[c].hpc) && + (drive->tracks == hd_types[c].tracks)) { + dev->switches |= (c << (d ? 0 : 2)); + break; + } + } + +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: "); + if (c == 4) + st506_xt_log("*WARNING* drive%i unsupported", d); + else + st506_xt_log("drive%i is type %i", d, c); + st506_xt_log(" (%i/%i/%i)\n", drive->tracks, drive->hpc, drive->spt); +#endif + } +} + + +static void * +st506_init(const device_t *info) +{ + wchar_t *fn = NULL; + hdc_t *dev; + int i, c; + + dev = (hdc_t *)malloc(sizeof(hdc_t)); + memset(dev, 0x00, sizeof(hdc_t)); + dev->type = info->local & 255; + + /* Set defaults for the controller. */ + dev->spt = MFM_SECTORS; + dev->base = 0x0320; + dev->irq = 5; + dev->dma = 3; + dev->bios_addr = 0xc8000; + dev->nr_err = ERR_NOT_READY; + + switch(dev->type) { + case 0: /* Xebec (MFM) */ + fn = XEBEC_BIOS_FILE; + break; + + case 1: /* DTC5150 (MFM) */ + fn = DTC_BIOS_FILE; + dev->switches = 0xff; + break; + + case 12: /* Seagate ST-11R (RLL) */ + dev->spt = RLL_SECTORS; + /*FALLTHROUGH*/ + + case 11: /* Seagate ST-11M (MFM) */ + dev->nr_err = ERR_NOT_AVAILABLE; + dev->switches = 0x01; /* fixed */ + dev->misc = device_get_config_int("revision"); + switch (dev->misc) { + case 5: /* v1.7 */ + fn = ST11_BIOS_FILE_OLD; + break; + + case 19: /* v2.0 */ + fn = ST11_BIOS_FILE_NEW; + break; + } + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bios_addr = device_get_config_hex20("bios_addr"); + dev->bios_ram = 64; /* scratch RAM size */ + + /* + * Industrial Madness Alert. + * + * With the ST-11 controller, Seagate decided to act + * like they owned the industry, and reserved the + * first cylinder of a drive for the controller. So, + * when the host accessed cylinder 0, that would be + * the actual cylinder 1 on the drive, and so on. + */ + dev->cyl_off = 1; + break; + + case 21: /* Western Digital WD1002A-WX1 (MFM) */ + dev->nr_err = ERR_NOT_AVAILABLE; + fn = WD1002A_WX1_BIOS_FILE; + /* The switches are read in reverse: 0 = closed, 1 = open. + Both open means MFM, 17 sectors per track. */ + dev->switches = 0x30; /* autobios */ + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + if (dev->irq == 2) + dev->switches |= 0x40; + dev->bios_addr = device_get_config_hex20("bios_addr"); + break; + + case 22: /* Western Digital WD1002A-27X (RLL) */ + dev->nr_err = ERR_NOT_AVAILABLE; + fn = WD1002A_27X_BIOS_FILE; + /* The switches are read in reverse: 0 = closed, 1 = open. + Both closed means translate 26 sectors per track to 17, + SW6 closed, SW5 open means 26 sectors per track. */ + dev->switches = device_get_config_int("translate") ? 0x00 : 0x10; /* autobios */ + dev->spt = RLL_SECTORS; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + if (dev->irq == 2) + dev->switches |= 0x40; + dev->bios_addr = device_get_config_hex20("bios_addr"); + break; + } + + /* Load the ROM BIOS. */ + loadrom(dev, fn); + + /* Set up the I/O region. */ + io_sethandler(dev->base, 4, + st506_read,NULL,NULL, st506_write,NULL,NULL, dev); + + /* Add the timer. */ + timer_add(&dev->timer, st506_callback, dev, 0); + + st506_xt_log("ST506: %s (I/O=%03X, IRQ=%i, DMA=%i, BIOS @0x%06lX, size %lu)\n", + info->name,dev->base,dev->irq,dev->dma, dev->bios_addr,dev->bios_size); + + /* Load any drives configured for us. */ +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: looking for disks...\n"); +#endif + for (c = 0, i = 0; i < HDD_NUM; i++) { + if ((hdd[i].bus == HDD_BUS_MFM) && (hdd[i].mfm_channel < MFM_NUM)) { + st506_xt_log("ST506: disk '%ls' on channel %i\n", + hdd[i].fn, hdd[i].mfm_channel); + loadhd(dev, hdd[i].mfm_channel, i, hdd[i].fn); + + if (++c > MFM_NUM) break; + } + } + st506_xt_log("ST506: %i disks loaded.\n", c); + + /* For the Xebec, set the switches now. */ + if (dev->type == 0) + set_switches(dev); + + /* Initial "active" drive parameters. */ + for (c = 0; c < MFM_NUM; c++) { + dev->drives[c].cfg_cyl = dev->drives[c].tracks; + dev->drives[c].cfg_hpc = dev->drives[c].hpc; + dev->drives[c].cfg_spt = dev->drives[c].spt; + } + + return(dev); +} + + +static void +st506_close(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + drive_t *drive; + int d; + + for (d = 0; d < MFM_NUM; d++) { + drive = &dev->drives[d]; + + hdd_image_close(drive->hdd_num); + } + + if (dev->bios_rom.rom != NULL) { + free(dev->bios_rom.rom); + dev->bios_rom.rom = NULL; + } + + free(dev); +} + + +static int +xebec_available(void) +{ + return(rom_present(XEBEC_BIOS_FILE)); +} + + +static int +dtc5150x_available(void) +{ + return(rom_present(DTC_BIOS_FILE)); +} + +static int +st11_m_available(void) +{ + return(rom_present(ST11_BIOS_FILE_OLD) && rom_present(ST11_BIOS_FILE_NEW)); +} + +static int +st11_r_available(void) +{ + return(rom_present(ST11_BIOS_FILE_OLD) && rom_present(ST11_BIOS_FILE_NEW)); +} + +static int +wd1002a_wx1_available(void) +{ + return(rom_present(WD1002A_WX1_BIOS_FILE)); +} + +static int +wd1002a_27x_available(void) +{ + return(rom_present(WD1002A_27X_BIOS_FILE)); +} + + +static const device_config_t dtc_config[] = { + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, + { + { + "Disabled", 0x00000 + }, + { + "C800H", 0xc8000 + }, + { + "CA00H", 0xca000 + }, + { + "D800H", 0xd8000 + }, + { + "F400H", 0xf4000 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t st11_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x0320, + { + { + "320H", 0x0320 + }, + { + "324H", 0x0324 + }, + { + "328H", 0x0328 + }, + { + "32CH", 0x032c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 2", 2 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, + { + { + "Disabled", 0x00000 + }, + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "E000H", 0xe0000 + }, + { + "" + } + } + }, + { + "revision", "Board Revision", CONFIG_SELECTION, "", 19, + { + { + "Rev. 05 (v1.7)", 5 + }, + { + "Rev. 19 (v2.0)", 19 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t wd_config[] = { + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, + { + { + "Disabled", 0x00000 + }, + { + "C800H", 0xc8000 + }, + { + "" + } + } + }, + { + "base", "Address", CONFIG_HEX16, "", 0x0320, + { + { + "320H", 0x0320 + }, + { + "324H", 0x0324 + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 2", 2 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t wd_rll_config[] = { + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, + { + { + "Disabled", 0x00000 + }, + { + "C800H", 0xc8000 + }, + { + "" + } + } + }, + { + "base", "Address", CONFIG_HEX16, "", 0x0320, + { + { + "320H", 0x0320 + }, + { + "324H", 0x0324 + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 2", 2 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "translate", "Translate 26 -> 17", CONFIG_SELECTION, "", 0, + { + { + "Off", 0 + }, + { + "On", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t st506_xt_xebec_device = { + "IBM PC Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 0, + st506_init, st506_close, NULL, + xebec_available, + NULL, NULL, + NULL +}; + +const device_t st506_xt_dtc5150x_device = { + "DTC 5150X Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 1, + st506_init, st506_close, NULL, + dtc5150x_available, + NULL, NULL, + dtc_config +}; + +const device_t st506_xt_st11_m_device = { + "ST-11M Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 11, + st506_init, st506_close, NULL, + st11_m_available, + NULL, NULL, + st11_config +}; + +const device_t st506_xt_st11_r_device = { + "ST-11R RLL Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 12, + st506_init, st506_close, NULL, + st11_r_available, + NULL, NULL, + st11_config +}; + +const device_t st506_xt_wd1002a_wx1_device = { + "WD1002A-WX1 Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 21, + st506_init, st506_close, NULL, + wd1002a_wx1_available, + NULL, NULL, + wd_config +}; + +const device_t st506_xt_wd1002a_27x_device = { + "WD1002A-27X RLL Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 22, + st506_init, st506_close, NULL, + wd1002a_27x_available, + NULL, NULL, + wd_rll_config +}; diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index 00528b096..9aa8f8faf 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -46,7 +46,7 @@ * * NOTE: The XTA interface is 0-based for sector numbers !! * - * Version: @(#)hdc_ide_xta.c 1.0.8 2018/04/29 + * Version: @(#)hdc_ide_xta.c 1.0.9 2018/10/17 * * Author: Fred N. van Kempen, * @@ -257,7 +257,8 @@ typedef struct { uint8_t sense; /* current SENSE ERROR value */ uint8_t status; /* current operational status */ uint8_t intr; - int64_t callback; + uint64_t callback; + pc_timer_t timer; /* Data transfer. */ int16_t buf_idx, /* buffer index and pointer */ @@ -281,13 +282,11 @@ typedef struct { #ifdef ENABLE_XTA_LOG int xta_do_log = ENABLE_XTA_LOG; -#endif static void xta_log(const char *fmt, ...) { -#ifdef ENABLE_XTA_LOG va_list ap; if (xta_do_log) { @@ -295,8 +294,10 @@ xta_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define xta_log(fmt, ...) +#endif static void @@ -357,6 +358,22 @@ next_sector(hdc_t *dev, drive_t *drive) } } +static void +xta_set_callback(hdc_t *dev, uint64_t callback) +{ + if (!dev) { + return; + } + + if (callback) { + dev->callback = callback; + timer_set_delay_u64(&dev->timer, dev->callback); + } else { + dev->callback = 0; + timer_disable(&dev->timer); + } +} + /* Perform the seek operation. */ static void @@ -456,7 +473,7 @@ hdc_callback(void *priv) int val; /* Cancel timer. */ - dev->callback = 0; + xta_set_callback(dev, 0); drive = &dev->drives[dcb->drvsel]; dev->comp = (dcb->drvsel) ? COMP_DRIVE : 0x00; @@ -553,12 +570,12 @@ do_send: dev->buf_idx = 0; if (no_data) { /* Delay a bit, no actual transfer. */ - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { if (dev->intr & DMA_ENA) { /* DMA enabled. */ dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { /* Copy from sector to data. */ memcpy(dev->data, @@ -581,14 +598,14 @@ do_send: xta_log("%s: CMD_READ_SECTORS out of data (idx=%d, len=%d)!\n", dev->name, dev->buf_idx, dev->buf_len); dev->status |= (STAT_CD | STAT_IO| STAT_REQ); - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); return; } dev->buf_ptr++; dev->buf_idx++; } } - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); dev->state = STATE_SDONE; break; @@ -651,12 +668,12 @@ do_recv: dev->buf_idx = 0; if (no_data) { /* Delay a bit, no actual transfer. */ - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { if (dev->intr & DMA_ENA) { /* DMA enabled. */ dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { /* No DMA, do PIO. */ dev->buf_ptr = dev->data; @@ -676,7 +693,7 @@ do_recv: xta_log("%s: CMD_WRITE_SECTORS out of data!\n", dev->name); dev->status |= (STAT_CD | STAT_IO | STAT_REQ); - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); return; } @@ -684,7 +701,7 @@ do_recv: dev->buf_idx++; } dev->state = STATE_RDONE; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } break; @@ -783,7 +800,7 @@ do_recv: dev->state = STATE_RDATA; if (dev->intr & DMA_ENA) { dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { dev->buf_ptr = dev->data; dev->status |= STAT_REQ; @@ -798,7 +815,7 @@ do_recv: if (val == DMA_NODATA) { xta_log("%s: CMD_WRITE_BUFFER out of data!\n", dev->name); dev->status |= (STAT_CD | STAT_IO | STAT_REQ); - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); return; } @@ -806,7 +823,7 @@ do_recv: dev->buf_idx++; } dev->state = STATE_RDONE; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } break; @@ -823,7 +840,7 @@ do_recv: switch(dev->state) { case STATE_IDLE: dev->state = STATE_RDONE; - dev->callback = 5*HDC_TIME; + xta_set_callback(dev, 5 * HDC_TIME); break; case STATE_RDONE: @@ -837,7 +854,7 @@ do_recv: case STATE_IDLE: if (drive->present) { dev->state = STATE_RDONE; - dev->callback = 5*HDC_TIME; + xta_set_callback(dev, 5 * HDC_TIME); } else { dev->comp |= COMP_ERR; dev->sense = ERR_NOTRDY; @@ -855,7 +872,7 @@ do_recv: switch(dev->state) { case STATE_IDLE: dev->state = STATE_RDONE; - dev->callback = 10*HDC_TIME; + xta_set_callback(dev, 10 * HDC_TIME); break; case STATE_RDONE: @@ -898,7 +915,7 @@ hdc_read(uint16_t port, void *priv) /* All data sent. */ dev->status &= ~STAT_REQ; dev->state = STATE_SDONE; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } } else if (dev->state == STATE_COMPL) { xta_log("DCB=%02X status=%02X comp=%02X\n", dev->dcb.cmd, dev->status, dev->comp); @@ -954,7 +971,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv) else dev->state = STATE_IDLE; dev->status &= ~STAT_CD; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } } break; @@ -981,6 +998,13 @@ hdc_write(uint16_t port, uint8_t val, void *priv) } +static int +xta_available(void) +{ + return(rom_present(WD_BIOS_FILE)); +} + + static void * xta_init(const device_t *info) { @@ -1063,7 +1087,7 @@ xta_init(const device_t *info) dev->rom_addr, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); /* Create a timer for command delays. */ - timer_add(hdc_callback, &dev->callback, &dev->callback, dev); + timer_add(&dev->timer, hdc_callback, dev, 0); return(dev); } @@ -1146,7 +1170,7 @@ const device_t xta_wdxt150_device = { DEVICE_ISA, 0, xta_init, xta_close, NULL, - NULL, NULL, NULL, + xta_available, NULL, NULL, wdxt150_config }; diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index a558a3318..3a6cf6656 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -276,7 +276,7 @@ const device_t xtide_acculogic_device = { const device_t xtide_at_ps2_device = { "XTIDE (AT) (1.1.5)", - DEVICE_ISA | DEVICE_PS2, + DEVICE_AT, 0, xtide_at_ps2_init, xtide_at_close, NULL, xtide_at_ps2_available, NULL, NULL, diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 805618a75..97bbf3ddb 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -8,13 +8,13 @@ * * Common code to handle all sorts of hard disk images. * - * Version: @(#)hdd.c 1.0.9 2018/05/25 + * Version: @(#)hdd.c 1.0.10 2019/09/26 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -24,6 +24,7 @@ #include "../plat.h" #include "../ui.h" #include "hdd.h" +#include "../cdrom/cdrom.h" hard_disk_t hdd[HDD_NUM]; diff --git a/src/disk/hdd.h b/src/disk/hdd.h index b9b439a4b..0ff451f42 100644 --- a/src/disk/hdd.h +++ b/src/disk/hdd.h @@ -8,7 +8,7 @@ * * Definitions for the hard disk image handler. * - * Version: @(#)hdd.h 1.0.6 2018/06/09 + * Version: @(#)hdd.h 1.0.8 2018/10/28 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -74,28 +74,27 @@ enum { /* Define the virtual Hard Disk. */ typedef struct { - int8_t is_hdi; /* image type (should rename) */ - int8_t wp; /* disk has been mounted READ-ONLY */ - - uint8_t bus; - - uint8_t mfm_channel; /* should rename and/or unionize */ + uint8_t id; + uint8_t mfm_channel; /* Should rename and/or unionize */ uint8_t esdi_channel; uint8_t xta_channel; uint8_t ide_channel; uint8_t scsi_id; + uint8_t bus, + res; /* Reserved for bus mode */ + uint8_t wp; /* Disk has been mounted READ-ONLY */ + uint8_t pad, pad0; - uint32_t base, + void *priv; + + wchar_t fn[1024], /* Name of current image file */ + prev_fn[1024]; /* Name of previous image file */ + + uint32_t res0, pad1, + base, spt, - hpc, /* physical geometry parameters */ - tracks, - at_spt, /* [Translation] parameters */ - at_hpc; - - FILE *f; /* current file handle to image */ - - wchar_t fn[260]; /* name of current image file */ - wchar_t prev_fn[260]; /* name of previous image file */ + hpc, /* Physical geometry parameters */ + tracks; } hard_disk_t; @@ -145,7 +144,6 @@ extern int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count); extern uint32_t hdd_image_get_last_sector(uint8_t id); extern uint32_t hdd_image_get_pos(uint8_t id); extern uint8_t hdd_image_get_type(uint8_t id); -extern void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt); extern void hdd_image_unload(uint8_t id, int fn_preserve); extern void hdd_image_close(uint8_t id); extern void hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size); diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index b895158cb..a34f2b5cb 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -8,7 +8,7 @@ * * Handling of hard disk image files. * - * Version: @(#)hdd_image.c 1.0.16 2018/06/09 + * Version: @(#)hdd_image.c 1.0.20 2018/10/28 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -72,13 +72,11 @@ static char *empty_sector_1mb; #ifdef ENABLE_HDD_IMAGE_LOG int hdd_image_do_log = ENABLE_HDD_IMAGE_LOG; -#endif static void hdd_image_log(const char *fmt, ...) { -#ifdef ENABLE_HDD_IMAGE_LOG va_list ap; if (hdd_image_do_log) { @@ -86,8 +84,10 @@ hdd_image_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define hdd_image_log(fmt, ...) +#endif int @@ -182,14 +182,14 @@ image_is_vhd(const wchar_t *s, int check_signature) static uint64_t be_to_u64(uint8_t *bytes, int start) { - uint64_t n = ((uint64_t)bytes[start+7] << 0) | - ((uint64_t)bytes[start+6] << 8) | - ((uint64_t)bytes[start+5] << 16) | - ((uint64_t)bytes[start+4] << 24) | - ((uint64_t)bytes[start+3] << 32) | - ((uint64_t)bytes[start+2] << 40) | - ((uint64_t)bytes[start+1] << 48) | - ((uint64_t)bytes[start] << 56); + uint64_t n = ((uint64_t) bytes[start + 7] << 0) | + ((uint64_t) bytes[start + 6] << 8) | + ((uint64_t) bytes[start + 5] << 16) | + ((uint64_t) bytes[start + 4] << 24) | + ((uint64_t) bytes[start + 3] << 32) | + ((uint64_t) bytes[start + 2] << 40) | + ((uint64_t) bytes[start + 1] << 48) | + ((uint64_t) bytes[start ] << 56); return n; } @@ -197,10 +197,10 @@ be_to_u64(uint8_t *bytes, int start) static uint32_t be_to_u32(uint8_t *bytes, int start) { - uint32_t n = ((uint32_t)bytes[start+3] << 0) | - ((uint32_t)bytes[start+2] << 8) | - ((uint32_t)bytes[start+1] << 16) | - ((uint32_t)bytes[start] << 24); + uint32_t n = ((uint32_t) bytes[start + 3] << 0) | + ((uint32_t) bytes[start + 2] << 8) | + ((uint32_t) bytes[start + 1] << 16) | + ((uint32_t) bytes[start ] << 24); return n; } @@ -208,8 +208,8 @@ be_to_u32(uint8_t *bytes, int start) static uint16_t be_to_u16(uint8_t *bytes, int start) { - uint16_t n = ((uint16_t)bytes[start+1] << 0) | - ((uint16_t)bytes[start] <<8); + uint16_t n = ((uint16_t) bytes[start + 1] << 0) | + ((uint16_t) bytes[start ] << 8); return n; } @@ -222,11 +222,11 @@ u64_to_be(uint64_t value, int is_be) res = value; else { uint64_t mask = 0xff00000000000000; - res = ((value & (mask >> 0)) >> 56) | - ((value & (mask >> 8)) >> 40) | + res = ((value & (mask >> 0)) >> 56) | + ((value & (mask >> 8)) >> 40) | ((value & (mask >> 16)) >> 24) | - ((value & (mask >> 24)) >> 8) | - ((value & (mask >> 32)) << 8) | + ((value & (mask >> 24)) >> 8) | + ((value & (mask >> 32)) << 8) | ((value & (mask >> 40)) << 24) | ((value & (mask >> 48)) << 40) | ((value & (mask >> 56)) << 56); @@ -243,9 +243,9 @@ u32_to_be(uint32_t value, int is_be) res = value; else { uint32_t mask = 0xff000000; - res = ((value & (mask >> 0)) >> 24) | - ((value & (mask >> 8)) >> 8) | - ((value & (mask >> 16)) << 8) | + res = ((value & (mask >> 0)) >> 24) | + ((value & (mask >> 8)) >> 8) | + ((value & (mask >> 16)) << 8) | ((value & (mask >> 24)) << 24); } return res; @@ -286,7 +286,7 @@ calc_vhd_timestamp() time_t start_time; time_t curr_time; double vhd_time; - start_time = 946684800; /* 1 Jan 2000 00:00 */ + start_time = 946684800; /* 1 Jan 2000 00:00 */ curr_time = time(NULL); vhd_time = difftime(curr_time, start_time); @@ -415,22 +415,22 @@ hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size) if (ts >= 65535 * 16 * 63) { spt = 255; heads = 16; - cth = ts / spt; + cth = (uint32_t) (ts / spt); } else { spt = 17; - cth = ts / spt; + cth = (uint32_t) (ts / spt); heads = (cth +1023) / 1024; if (heads < 4) heads = 4; if ((cth >= (heads * 1024)) || (heads > 16)) { spt = 31; heads = 16; - cth = ts / spt; + cth = (uint32_t) (ts / spt); } if (cth >= (heads * 1024)) { spt = 63; heads = 16; - cth = ts / spt; + cth = (uint32_t) (ts / spt); } } cyl = cth / heads; @@ -462,14 +462,19 @@ prepare_new_hard_disk(uint8_t id, uint64_t full_size) /* First, write all the 1 MB blocks. */ if (t > 0) { for (i = 0; i < t; i++) { - fwrite(empty_sector_1mb, 1, 1045876, hdd_images[id].file); + fseek(hdd_images[id].file, 0, SEEK_END); + fwrite(empty_sector_1mb, 1, 1048576, hdd_images[id].file); pclog("#"); } } /* Then, write the remainder. */ - fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); - pclog("#]\n"); + if (size > 0) { + fseek(hdd_images[id].file, 0, SEEK_END); + fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); + pclog("#"); + } + pclog("]\n"); /* Switch the suppression of seen messages back on. */ pclog_toggle_suppr(); @@ -493,6 +498,25 @@ hdd_image_init(void) } +static void +hdd_image_gen_vft(int id, vhd_footer_t **vft, uint64_t full_size) +{ + /* Generate new footer. */ + new_vhd_footer(vft); + (*vft)->orig_size = (*vft)->curr_size = full_size; + (*vft)->geom.cyl = hdd[id].tracks; + (*vft)->geom.heads = hdd[id].hpc; + (*vft)->geom.spt = hdd[id].spt; + generate_vhd_checksum(*vft); + vhd_footer_to_bytes((uint8_t *) empty_sector, *vft); + fseeko64(hdd_images[id].file, 0, SEEK_END); + fwrite(empty_sector, 1, 512, hdd_images[id].file); + free(*vft); + *vft = NULL; + hdd_images[id].type = 3; +} + + int hdd_image_load(int id) { @@ -596,22 +620,7 @@ hdd_image_load(int id) if (is_vhd[0]) { /* VHD image. */ - /* Generate new footer. */ - empty_sector_1mb = (char *) malloc(512); - new_vhd_footer(&vft); - vft->orig_size = vft->curr_size = full_size; - vft->geom.cyl = tracks; - vft->geom.heads = hpc; - vft->geom.spt = spt; - generate_vhd_checksum(vft); - memset(empty_sector_1mb, 0, 512); - vhd_footer_to_bytes((uint8_t *) empty_sector_1mb, vft); - fwrite(empty_sector_1mb, 1, 512, hdd_images[id].file); - free(vft); - vft = NULL; - free(empty_sector_1mb); - empty_sector_1mb = NULL; - hdd_images[id].type = 3; + hdd_image_gen_vft(id, &vft, full_size); } return ret; @@ -665,23 +674,17 @@ hdd_image_load(int id) hdd[id].spt = spt; hdd[id].hpc = hpc; hdd[id].tracks = tracks; - fread(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); - fread(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); hdd_images[id].type = 2; } else if (is_vhd[1]) { - empty_sector_1mb = (char *) malloc(512); - memset(empty_sector_1mb, 0, 512); fseeko64(hdd_images[id].file, -512, SEEK_END); - fread(empty_sector_1mb, 1, 512, hdd_images[id].file); + fread(empty_sector, 1, 512, hdd_images[id].file); new_vhd_footer(&vft); - vhd_footer_from_bytes(vft, (uint8_t *) empty_sector_1mb); + vhd_footer_from_bytes(vft, (uint8_t *) empty_sector); if (vft->type != 2) { /* VHD is not fixed size */ hdd_image_log("VHD: Image is not fixed size\n"); free(vft); vft = NULL; - free(empty_sector_1mb); - empty_sector_1mb = NULL; fclose(hdd_images[id].file); hdd_images[id].file = NULL; memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); @@ -693,8 +696,6 @@ hdd_image_load(int id) hdd[id].spt = vft->geom.spt; free(vft); vft = NULL; - free(empty_sector_1mb); - empty_sector_1mb = NULL; hdd_images[id].type = 3; /* If we're here, this means there is a valid VHD footer in the image, which means that by definition, all valid sectors @@ -713,12 +714,23 @@ hdd_image_load(int id) fseeko64(hdd_images[id].file, 0, SEEK_END); s = ftello64(hdd_images[id].file); if (s < (full_size + hdd_images[id].base)) - return prepare_new_hard_disk(id, full_size); + ret = prepare_new_hard_disk(id, full_size); else { hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; hdd_images[id].loaded = 1; - return 1; + ret = 1; } + + if (is_vhd[0]) { + fseeko64(hdd_images[id].file, 0, SEEK_END); + s = ftello64(hdd_images[id].file); + if (s == (full_size + hdd_images[id].base)) { + /* VHD image. */ + hdd_image_gen_vft(id, &vft, full_size); + } + } + + return ret; } @@ -736,9 +748,17 @@ hdd_image_seek(uint8_t id, uint32_t sector) void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - fread(buffer, 1, count << 9, hdd_images[id].file); + int i; + + fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET); + + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; + + hdd_images[id].pos = sector + i; + fread(buffer + (i << 9), 1, 512, hdd_images[id].file); + } } @@ -759,9 +779,7 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) if ((sectors - sector) < transfer_sectors) transfer_sectors = sectors - sector; - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - fread(buffer, 1, transfer_sectors << 9, hdd_images[id].file); + hdd_image_read(id, sector, transfer_sectors, buffer); if (count != transfer_sectors) return 1; @@ -772,9 +790,17 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - fwrite(buffer, count << 9, 1, hdd_images[id].file); + int i; + + fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET); + + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; + + hdd_images[id].pos = sector + i; + fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file); + } } @@ -787,9 +813,7 @@ hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) if ((sectors - sector) < transfer_sectors) transfer_sectors = sectors - sector; - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - fwrite(buffer, transfer_sectors << 9, 1, hdd_images[id].file); + hdd_image_write(id, sector, transfer_sectors, buffer); if (count != transfer_sectors) return 1; @@ -802,28 +826,30 @@ hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) { uint32_t i = 0; - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - for (i = 0; i < count; i++) + memset(empty_sector, 0, 512); + + fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET); + + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; + + hdd_images[id].pos = sector + i; fwrite(empty_sector, 512, 1, hdd_images[id].file); + } } int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) { - uint32_t i = 0; - uint32_t transfer_sectors = count; uint32_t sectors = hdd_sectors(id); if ((sectors - sector) < transfer_sectors) transfer_sectors = sectors - sector; - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - for (i = 0; i < transfer_sectors; i++) - fwrite(empty_sector, 1, 512, hdd_images[id].file); + hdd_image_zero(id, sector, transfer_sectors); if (count != transfer_sectors) return 1; @@ -852,19 +878,6 @@ hdd_image_get_type(uint8_t id) } -void -hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt) -{ - if (hdd_images[id].type == 2) { - hdd[id].at_hpc = hpc; - hdd[id].at_spt = spt; - fseeko64(hdd_images[id].file, 0x20, SEEK_SET); - fwrite(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); - } -} - - void hdd_image_unload(uint8_t id, int fn_preserve) { diff --git a/src/disk/zip.c b/src/disk/zip.c index e2a4c28d3..60c775810 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -9,11 +9,11 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)zip.c 1.0.21 2018/05/28 + * Version: @(#)zip.c 1.0.38 2019/11/19 * * Author: Miran Grca, * - * Copyright 2018 Miran Grca. + * Copyright 2018,2019 Miran Grca. */ #include #include @@ -23,11 +23,12 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../config.h" #include "../timer.h" #include "../device.h" #include "../piix.h" -#include "../scsi/scsi.h" +#include "../scsi/scsi_device.h" #include "../nvr.h" #include "../plat.h" #include "../ui.h" @@ -36,26 +37,7 @@ #include "zip.h" -/* Bits of 'status' */ -#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 zipbufferb dev->buffer - - -zip_t *zip[ZIP_NUM]; zip_drive_t zip_drives[ZIP_NUM]; -uint8_t atapi_zip_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -uint8_t scsi_zip_drives[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ @@ -129,20 +111,22 @@ const uint8_t zip_command_flags[0x100] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static uint64_t zip_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | - (1LL << 0x02LL) | (1LL << 0x2FLL) | - (1LL << GPMODE_ALL_PAGES); -static uint64_t zip_250_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | - (1LL << 0x05LL) | (1LL << 0x08LL) | - (1LL << 0x2FLL) | - (1LL << GPMODE_ALL_PAGES); +static uint64_t zip_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | + GPMODEP_DISCONNECT_PAGE | + GPMODEP_IOMEGA_PAGE | + GPMODEP_ALL_PAGES); +static uint64_t zip_250_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | + GPMODEP_FLEXIBLE_DISK_PAGE | + GPMODEP_CACHING_PAGE | + GPMODEP_IOMEGA_PAGE | + GPMODEP_ALL_PAGES); static const mode_sense_pages_t zip_mode_sense_pages_default = { { { 0, 0 }, { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { GPMODE_DISCONNECT_PAGE, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -187,7 +171,7 @@ static const mode_sense_pages_t zip_mode_sense_pages_default = { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } + { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0xff, 0x0f } } }; static const mode_sense_pages_t zip_250_mode_sense_pages_default = @@ -197,10 +181,10 @@ static const mode_sense_pages_t zip_250_mode_sense_pages_default = { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + {GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { GPMODE_CACHING_PAGE, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -238,14 +222,14 @@ static const mode_sense_pages_t zip_250_mode_sense_pages_default = { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } + { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } } }; static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = { { { 0, 0 }, { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { GPMODE_DISCONNECT_PAGE, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -290,7 +274,7 @@ static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } + { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0xff, 0x0f } } }; static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = @@ -300,10 +284,10 @@ static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + {GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { GPMODE_CACHING_PAGE, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -342,14 +326,15 @@ static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } + { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } } }; static const mode_sense_pages_t zip_mode_sense_pages_changeable = { { { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xFF, 0xFF, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF }, + { GPMODE_DISCONNECT_PAGE, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -394,20 +379,20 @@ static const mode_sense_pages_t zip_mode_sense_pages_changeable = { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } + { GPMODE_IOMEGA_PAGE, 0x04, 0xff, 0xff, 0xff, 0xff } } }; static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = { { { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xFF, 0xFF, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + {GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { GPMODE_CACHING_PAGE, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -446,34 +431,32 @@ static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } + { GPMODE_IOMEGA_PAGE, 0x04, 0xff, 0xff, 0xff, 0xff } } }; static void zip_command_complete(zip_t *dev); static void zip_init(zip_t *dev); -void zip_phase_callback(zip_t *dev); - #ifdef ENABLE_ZIP_LOG int zip_do_log = ENABLE_ZIP_LOG; -#endif static void -zip_log(const char *format, ...) +zip_log(const char *fmt, ...) { -#ifdef ENABLE_ZIP_LOG va_list ap; if (zip_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define zip_log(fmt, ...) +#endif int @@ -489,62 +472,66 @@ find_zip_for_channel(uint8_t channel) } +static int +zip_load_abort(zip_t *dev) +{ + if (dev->drv->f) + fclose(dev->drv->f); + dev->drv->f = NULL; + dev->drv->medium_size = 0; + zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; +} + + int zip_load(zip_t *dev, wchar_t *fn) { - int read_only = dev->drv->ui_writeprot; int size = 0; - dev->drv->f = plat_fopen(fn, dev->drv->ui_writeprot ? L"rb" : L"rb+"); - if (!dev->drv->ui_writeprot && !dev->drv->f) { - dev->drv->f = plat_fopen(fn, L"rb"); - read_only = 1; - } - if (dev->drv->f) { - fseek(dev->drv->f, 0, SEEK_END); - size = ftell(dev->drv->f); - - if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { - /* This is a ZDI image. */ - size -= 0x1000; - dev->drv->base = 0x1000; + dev->drv->f = plat_fopen(fn, dev->drv->read_only ? L"rb" : L"rb+"); + if (!dev->drv->f) { + if (!dev->drv->read_only) { + dev->drv->f = plat_fopen(fn, L"rb"); + if (dev->drv->f) + dev->drv->read_only = 1; + else + return zip_load_abort(dev); } else - dev->drv->base = 0; - - if (dev->drv->is_250) { - if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", - ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); - fclose(dev->drv->f); - dev->drv->f = NULL; - dev->drv->medium_size = 0; - zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } else { - if (size != (ZIP_SECTORS << 9)) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", - ZIP_SECTORS << 9); - fclose(dev->drv->f); - dev->drv->f = NULL; - dev->drv->medium_size = 0; - zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } - - dev->drv->medium_size = size >> 9; - - fseek(dev->drv->f, dev->drv->base, SEEK_SET); - - memcpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path)); - - dev->drv->read_only = read_only; - - return 1; + return zip_load_abort(dev); } - return 0; + fseek(dev->drv->f, 0, SEEK_END); + size = ftell(dev->drv->f); + + if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { + /* This is a ZDI image. */ + size -= 0x1000; + dev->drv->base = 0x1000; + } else + dev->drv->base = 0; + + if (dev->drv->is_250) { + if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", + ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); + return zip_load_abort(dev); + } + } else { + if (size != (ZIP_SECTORS << 9)) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", + ZIP_SECTORS << 9); + return zip_load_abort(dev); + } + } + + dev->drv->medium_size = size >> 9; + + fseek(dev->drv->f, dev->drv->base, SEEK_SET); + + memcpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path)); + + return 1; } @@ -564,11 +551,20 @@ zip_disk_reload(zip_t *dev) void -zip_disk_close(zip_t *dev) +zip_disk_unload(zip_t *dev) { if (dev->drv->f) { fclose(dev->drv->f); dev->drv->f = NULL; + } +} + + +void +zip_disk_close(zip_t *dev) +{ + if (dev->drv->f) { + zip_disk_unload(dev); memcpy(dev->drv->prev_image_path, dev->drv->image_path, sizeof(dev->drv->prev_image_path)); memset(dev->drv->image_path, 0, sizeof(dev->drv->image_path)); @@ -578,43 +574,6 @@ zip_disk_close(zip_t *dev) } -void -build_atapi_zip_map() -{ - uint8_t i = 0; - - memset(atapi_zip_drives, 0xff, 8); - - for (i = 0; i < 8; i++) - atapi_zip_drives[i] = find_zip_for_channel(i); -} - - -int -find_zip_for_scsi_id(uint8_t scsi_id) -{ - uint8_t i = 0; - - for (i = 0; i < ZIP_NUM; i++) { - if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id)) - return i; - } - return 0xff; -} - - -void -build_scsi_zip_map() -{ - uint8_t i = 0; - - memset(scsi_zip_drives, 0xff, 16); - - for (i = 0; i < 16; i++) - scsi_zip_drives[i] = find_zip_for_scsi_id(i); -} - - static void zip_set_callback(zip_t *dev) { @@ -623,16 +582,6 @@ zip_set_callback(zip_t *dev) } -void -zip_set_signature(zip_t *dev) -{ - if (dev->id >= ZIP_NUM) - return; - dev->phase = 1; - dev->request_length = 0xEB14; -} - - static void zip_init(zip_t *dev) { @@ -648,11 +597,13 @@ zip_init(zip_t *dev) if (dev->drv->bus_type < ZIP_BUS_SCSI) dev->drv->bus_mode |= 1; zip_log("ZIP %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); - if (dev->drv->bus_type < ZIP_BUS_SCSI) - zip_set_signature(dev); + if (dev->drv->bus_type < ZIP_BUS_SCSI) { + dev->phase = 1; + dev->request_length = 0xEB14; + } dev->status = READY_STAT | DSC_STAT; dev->pos = 0; - dev->packet_status = 0xff; + dev->packet_status = PHASE_NONE; zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = 0; } @@ -692,17 +643,6 @@ zip_current_mode(zip_t *dev) } -/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int -zip_ZIP_PHASE_to_scsi(zip_t *dev) -{ - if (dev->status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; -} - - /* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ int zip_atapi_phase_to_scsi(zip_t *dev) @@ -734,44 +674,30 @@ zip_mode_sense_load(zip_t *dev) { FILE *f; wchar_t file_name[512]; - int i; memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (dev->drv->is_250) { - if (zip_250_mode_sense_pages_default.pages[i][1] != 0) { - if (zip_drives[dev->id].bus_type == ZIP_BUS_SCSI) { - memcpy(dev->ms_pages_saved.pages[i], - zip_250_mode_sense_pages_default_scsi.pages[i], - zip_250_mode_sense_pages_default_scsi.pages[i][1] + 2); - } else { - memcpy(dev->ms_pages_saved.pages[i], - zip_250_mode_sense_pages_default.pages[i], - zip_250_mode_sense_pages_default.pages[i][1] + 2); - } - } - } else { - if (zip_mode_sense_pages_default.pages[i][1] != 0) { - if (dev->drv->bus_type == ZIP_BUS_SCSI) { - memcpy(dev->ms_pages_saved.pages[i], - zip_mode_sense_pages_default_scsi.pages[i], - zip_mode_sense_pages_default_scsi.pages[i][1] + 2); - } else { - memcpy(dev->ms_pages_saved.pages[i], - zip_mode_sense_pages_default.pages[i], - zip_mode_sense_pages_default.pages[i][1] + 2); - } - } - } + if (dev->drv->is_250) { + if (zip_drives[dev->id].bus_type == ZIP_BUS_SCSI) + memcpy(&dev->ms_pages_saved, &zip_250_mode_sense_pages_default_scsi, sizeof(mode_sense_pages_t)); + else + memcpy(&dev->ms_pages_saved, &zip_250_mode_sense_pages_default, sizeof(mode_sense_pages_t)); + } else { + if (zip_drives[dev->id].bus_type == ZIP_BUS_SCSI) + memcpy(&dev->ms_pages_saved, &zip_mode_sense_pages_default_scsi, sizeof(mode_sense_pages_t)); + else + memcpy(&dev->ms_pages_saved, &zip_mode_sense_pages_default, sizeof(mode_sense_pages_t)); } + memset(file_name, 0, 512 * sizeof(wchar_t)); if (dev->drv->bus_type == ZIP_BUS_SCSI) swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", dev->id); else swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", dev->id); f = plat_fopen(nvr_path(file_name), L"rb"); - if (f) + if (f) { + /* Nothing to read, not used by ZIP. */ fclose(f); + } } @@ -787,29 +713,10 @@ zip_mode_sense_save(zip_t *dev) else swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", dev->id); f = plat_fopen(nvr_path(file_name), L"wb"); - if (f) + if (f) { + /* Nothing to write, not used by ZIP. */ fclose(f); -} - - -int -zip_read_capacity(zip_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - int size = 0; - - if (dev->drv->is_250) - size = dev->drv->medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ - else - size = ZIP_SECTORS - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 2; /* 512 = 0x0200 */ - *len = 8; - - return 1; + } } @@ -852,35 +759,28 @@ zip_mode_sense_read(zip_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) static uint32_t -zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) { - uint64_t page_flags; - uint8_t page_control = (type >> 6) & 3; + uint64_t pf; + uint8_t page_control = (page >> 6) & 3; if (dev->drv->is_250) - page_flags = zip_250_mode_sense_page_flags; + pf = zip_250_mode_sense_page_flags; else - page_flags = zip_mode_sense_page_flags; + pf = zip_mode_sense_page_flags; int i = 0; int j = 0; uint8_t msplen; - type &= 0x3f; + page &= 0x3f; if (block_descriptor_len) { - if (dev->drv->is_250) { - buf[pos++] = ((dev->drv->medium_size >> 24) & 0xff); - buf[pos++] = ((dev->drv->medium_size >> 16) & 0xff); - buf[pos++] = ((dev->drv->medium_size >> 8) & 0xff); - buf[pos++] = ( dev->drv->medium_size & 0xff); - } else { - buf[pos++] = ((ZIP_SECTORS >> 24) & 0xff); - buf[pos++] = ((ZIP_SECTORS >> 16) & 0xff); - buf[pos++] = ((ZIP_SECTORS >> 8) & 0xff); - buf[pos++] = ( ZIP_SECTORS & 0xff); - } + buf[pos++] = ((dev->drv->medium_size >> 24) & 0xff); + buf[pos++] = ((dev->drv->medium_size >> 16) & 0xff); + buf[pos++] = ((dev->drv->medium_size >> 8) & 0xff); + buf[pos++] = ( dev->drv->medium_size & 0xff); buf[pos++] = 0; /* Reserved. */ buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ buf[pos++] = 2; @@ -888,8 +788,8 @@ zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t blo } for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (page_flags & (1LL << dev->current_page_code)) { + if ((page == GPMODE_ALL_PAGES) || (page == i)) { + if (pf & (1LL << ((uint64_t) page))) { buf[pos++] = zip_mode_sense_read(dev, page_control, i, 0); msplen = zip_mode_sense_read(dev, page_control, i, 1); buf[pos++] = msplen; @@ -907,7 +807,7 @@ zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t blo static void zip_update_request_length(zip_t *dev, int len, int block_len) { - uint32_t bt, min_len = 0; + int bt, min_len = 0; dev->max_transfer_len = dev->request_length; @@ -933,6 +833,7 @@ zip_update_request_length(zip_t *dev, int len, int block_len) break; } } + /*FALLTHROUGH*/ default: dev->packet_len = len; break; @@ -953,14 +854,23 @@ zip_update_request_length(zip_t *dev, int len, int block_len) } -static void -zip_command_bus(zip_t *dev) +static double +zip_bus_speed(zip_t *dev) { - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 1LL * ZIP_TIME; - zip_set_callback(dev); + double ret = -1.0; + + if (dev->drv->bus_type == ZIP_BUS_SCSI) { + dev->callback = -1.0; /* Speed depends on SCSI controller */ + return 0.0; + } else { + if (dev && dev->drv) + ret = ide_atapi_get_period(dev->drv->ide_channel); + if (ret == -1.0) { + dev->callback = -1.0; + return 0.0; + } else + return ret * 1000000.0; + } } @@ -968,29 +878,21 @@ static void zip_command_common(zip_t *dev) { double bytes_per_second, period; - double dusec; dev->status = BUSY_STAT; dev->phase = 1; dev->pos = 0; - if (dev->packet_status == ZIP_PHASE_COMPLETE) { - zip_phase_callback(dev); - dev->callback = 0LL; - } else { + if (dev->packet_status == PHASE_COMPLETE) + dev->callback = 0.0; + else { if (dev->drv->bus_type == ZIP_BUS_SCSI) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ + dev->callback = -1.0; /* Speed depends on SCSI controller */ return; - } else { - if (zip_current_mode(dev) == 2) - bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ - else - bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ - } + } else + bytes_per_second = zip_bus_speed(dev); period = 1000000.0 / bytes_per_second; - dusec = (double) TIMER_USEC; - dusec = dusec * period * (double) (dev->packet_len); - dev->callback = ((int64_t) dusec); + dev->callback = period * (double) (dev->packet_len); } zip_set_callback(dev); @@ -1000,7 +902,8 @@ zip_command_common(zip_t *dev) static void zip_command_complete(zip_t *dev) { - dev->packet_status = ZIP_PHASE_COMPLETE; + ui_sb_update_icon(SB_ZIP | dev->id, 0); + dev->packet_status = PHASE_COMPLETE; zip_command_common(dev); } @@ -1008,25 +911,23 @@ zip_command_complete(zip_t *dev) static void zip_command_read(zip_t *dev) { - dev->packet_status = ZIP_PHASE_DATA_IN; + dev->packet_status = PHASE_DATA_IN; zip_command_common(dev); - dev->total_read = 0; } static void zip_command_read_dma(zip_t *dev) { - dev->packet_status = ZIP_PHASE_DATA_IN_DMA; + dev->packet_status = PHASE_DATA_IN_DMA; zip_command_common(dev); - dev->total_read = 0; } static void zip_command_write(zip_t *dev) { - dev->packet_status = ZIP_PHASE_DATA_OUT; + dev->packet_status = PHASE_DATA_OUT; zip_command_common(dev); } @@ -1034,7 +935,7 @@ zip_command_write(zip_t *dev) static void zip_command_write_dma(zip_t *dev) { - dev->packet_status = ZIP_PHASE_DATA_OUT_DMA; + dev->packet_status = PHASE_DATA_OUT_DMA; zip_command_common(dev); } @@ -1085,7 +986,6 @@ zip_data_command_finish(zip_t *dev, int len, int block_len, int alloc_len, int d static void zip_sense_clear(zip_t *dev, int command) { - dev->previous_command = command; zip_sense_key = zip_asc = zip_ascq = 0; } @@ -1098,7 +998,7 @@ zip_set_phase(zip_t *dev, uint8_t phase) if (dev->drv->bus_type != ZIP_BUS_SCSI) return; - SCSIDevices[scsi_id].Phase = phase; + scsi_devices[scsi_id].phase = phase; } @@ -1112,9 +1012,10 @@ zip_cmd_error(zip_t *dev) dev->status = READY_STAT | ERR_STAT; dev->phase = 3; dev->pos = 0; - dev->packet_status = 0x80; - dev->callback = 50LL * ZIP_TIME; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); + ui_sb_update_icon(SB_ZIP | dev->id, 0); zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", dev->id, dev->current_cdb[0], zip_sense_key, zip_asc, zip_ascq); } @@ -1129,16 +1030,40 @@ zip_unit_attention(zip_t *dev) dev->status = READY_STAT | ERR_STAT; dev->phase = 3; dev->pos = 0; - dev->packet_status = 0x80; - dev->callback = 50LL * ZIP_TIME; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); + ui_sb_update_icon(SB_ZIP | dev->id, 0); zip_log("ZIP %i: UNIT ATTENTION\n", dev->id); } static void -zip_bus_master_error(zip_t *dev) +zip_buf_alloc(zip_t *dev, uint32_t len) { + zip_log("ZIP %i: Allocated buffer length: %i\n", dev->id, len); + if (!dev->buffer) + dev->buffer = (uint8_t *) malloc(len); +} + + +static void +zip_buf_free(zip_t *dev) +{ + if (dev->buffer) { + zip_log("ZIP %i: Freeing buffer...\n", dev->id); + free(dev->buffer); + dev->buffer = NULL; + } +} + + +static void +zip_bus_master_error(scsi_common_t *sc) +{ + zip_t *dev = (zip_t *) sc; + + zip_buf_free(dev); zip_sense_key = zip_asc = zip_ascq = 0; zip_cmd_error(dev); } @@ -1227,11 +1152,10 @@ zip_data_phase_error(zip_t *dev) static int -zip_blocks(zip_t *dev, uint32_t *len, int first_batch, int out) +zip_blocks(zip_t *dev, int32_t *len, int first_batch, int out) { - dev->data_pos = 0; - *len = 0; + int i; if (!dev->sector_len) { zip_command_complete(dev); @@ -1248,11 +1172,17 @@ zip_blocks(zip_t *dev, uint32_t *len, int first_batch, int out) *len = dev->requested_blocks << 9; - fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9), SEEK_SET); - if (out) - fwrite(zipbufferb, 1, *len, dev->drv->f); - else - fread(zipbufferb, 1, *len, dev->drv->f); + for (i = 0; i < dev->requested_blocks; i++) { + fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9) + (i << 9), SEEK_SET); + + if (feof(dev->drv->f)) + break; + + if (out) + fwrite(dev->buffer + (i << 9), 1, 512, dev->drv->f); + else + fread(dev->buffer + (i << 9), 1, 512, dev->drv->f); + } zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); @@ -1345,11 +1275,6 @@ zip_pre_execution_check(zip_t *dev, uint8_t *cdb) zip_sense_clear(dev, cdb[0]); /* Next it's time for NOT READY. */ - if (!ready) - dev->media_status = MEC_MEDIA_REMOVAL; - else - dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { zip_log("ZIP %i: Not ready (%02X)\n", dev->id, cdb[0]); zip_not_ready(dev); @@ -1379,13 +1304,17 @@ zip_rezero(zip_t *dev) void -zip_reset(zip_t *dev) +zip_reset(scsi_common_t *sc) { + zip_t *dev = (zip_t *) sc; + zip_rezero(dev); dev->status = 0; - dev->callback = 0LL; + dev->callback = 0.0; zip_set_callback(dev); - dev->packet_status = 0xff; + dev->phase = 1; + dev->request_length = 0xEB14; + dev->packet_status = PHASE_NONE; dev->unit_attention = 0; } @@ -1426,9 +1355,10 @@ zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) } -void -zip_request_sense_for_scsi(zip_t *dev, uint8_t *buffer, uint8_t alloc_length) +static void +zip_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { + zip_t *dev = (zip_t *) sc; int ready = 0; ready = (dev->drv->f != NULL); @@ -1447,7 +1377,7 @@ zip_request_sense_for_scsi(zip_t *dev, uint8_t *buffer, uint8_t alloc_length) static void -zip_set_buf_len(zip_t *dev, int32_t *BufLen, uint32_t *src_len) +zip_set_buf_len(zip_t *dev, int32_t *BufLen, int32_t *src_len) { if (dev->drv->bus_type == ZIP_BUS_SCSI) { if (*BufLen == -1) @@ -1462,38 +1392,21 @@ zip_set_buf_len(zip_t *dev, int32_t *BufLen, uint32_t *src_len) static void -zip_buf_alloc(zip_t *dev, uint32_t len) -{ - zip_log("ZIP %i: Allocated buffer length: %i\n", dev->id, len); - zipbufferb = (uint8_t *) malloc(len); -} - - -static void -zip_buf_free(zip_t *dev) -{ - if (zipbufferb) { - zip_log("ZIP %i: Freeing buffer...\n", dev->id); - free(zipbufferb); - zipbufferb = NULL; - } -} - - -void -zip_command(zip_t *dev, uint8_t *cdb) +zip_command(scsi_common_t *sc, uint8_t *cdb) { + zip_t *dev = (zip_t *) sc; int pos = 0, block_desc = 0; int ret; - uint32_t len, max_len; - uint32_t alloc_length, i = 0; - unsigned size_idx, idx = 0; + int32_t len, max_len; + int32_t alloc_length; + uint32_t i = 0; + int size_idx, idx = 0; unsigned preamble_len; int32_t blen = 0; int32_t *BufLen; if (dev->drv->bus_type == ZIP_BUS_SCSI) { - BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; + BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; dev->status &= ~ERR_STAT; } else { BufLen = &blen; @@ -1503,8 +1416,6 @@ zip_command(zip_t *dev, uint8_t *cdb) dev->packet_len = 0; dev->request_pos = 0; - dev->data_pos = 0; - memcpy(dev->current_cdb, cdb, 12); if (cdb[0] != 0) { @@ -1539,7 +1450,7 @@ zip_command(zip_t *dev, uint8_t *cdb) break; case GPCMD_FORMAT_UNIT: - if ((dev->drv->bus_type == ZIP_BUS_SCSI) && dev->drv->read_only) { + if (dev->drv->read_only) { zip_write_protected(dev); return; } @@ -1553,24 +1464,24 @@ zip_command(zip_t *dev, uint8_t *cdb) max_len = cdb[4]; zip_buf_alloc(dev, 256); zip_set_buf_len(dev, BufLen, &max_len); - memset(zipbufferb, 0, 256); + memset(dev->buffer, 0, 256); if (cdb[2] == 1) { /* This page is related to disk health status - setting this page to 0 makes disk health read as "marginal". */ - zipbufferb[0] = 0x58; - zipbufferb[1] = 0x00; + dev->buffer[0] = 0x58; + dev->buffer[1] = 0x00; for (i = 0x00; i < 0x58; i++) - zipbufferb[i + 0x02] = 0xff; + dev->buffer[i + 0x02] = 0xff; } else if (cdb[2] == 2) { - zipbufferb[0] = 0x3d; - zipbufferb[1] = 0x00; + dev->buffer[0] = 0x3d; + dev->buffer[1] = 0x00; for (i = 0x00; i < 0x13; i++) - zipbufferb[i + 0x02] = 0x00; - zipbufferb[0x15] = 0x00; + dev->buffer[i + 0x02] = 0x00; + dev->buffer[0x15] = 0x00; if (dev->drv->read_only) - zipbufferb[0x15] |= 0x02; + dev->buffer[0x15] |= 0x02; for (i = 0x00; i < 0x27; i++) - zipbufferb[i + 0x16] = 0x00; + dev->buffer[i + 0x16] = 0x00; } else { zip_invalid_field(dev); zip_buf_free(dev); @@ -1590,23 +1501,31 @@ zip_command(zip_t *dev, uint8_t *cdb) should forget about the not ready, and report unit attention straight away. */ zip_set_phase(dev, SCSI_PHASE_DATA_IN); max_len = cdb[4]; + + if (!max_len) { + zip_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * ZIP_TIME; + zip_set_callback(dev); + break; + } + zip_buf_alloc(dev, 256); zip_set_buf_len(dev, BufLen, &max_len); len = (cdb[1] & 1) ? 8 : 18; - zip_request_sense(dev, zipbufferb, max_len, cdb[1] & 1); + zip_request_sense(dev, dev->buffer, max_len, cdb[1] & 1); zip_data_command_finish(dev, len, len, cdb[4], 0); break; case GPCMD_MECHANISM_STATUS: zip_set_phase(dev, SCSI_PHASE_DATA_IN); - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + len = (cdb[8] << 8) | cdb[9]; zip_buf_alloc(dev, 8); - zip_set_buf_len(dev, BufLen, &len); - memset(zipbufferb, 0, 8); - zipbufferb[5] = 1; + memset(dev->buffer, 0, 8); + dev->buffer[5] = 1; zip_data_command_finish(dev, 8, 8, len, 0); break; @@ -1637,8 +1556,8 @@ zip_command(zip_t *dev, uint8_t *cdb) if (!dev->sector_len) { zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ - dev->packet_status = ZIP_PHASE_COMPLETE; - dev->callback = 20LL * ZIP_TIME; + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); break; } @@ -1653,6 +1572,10 @@ zip_command(zip_t *dev, uint8_t *cdb) ret = zip_blocks(dev, &alloc_length, 1, 0); if (ret <= 0) { + zip_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * ZIP_TIME; + zip_set_callback(dev); zip_buf_free(dev); return; } @@ -1660,12 +1583,11 @@ zip_command(zip_t *dev, uint8_t *cdb) dev->requested_blocks = max_len; dev->packet_len = alloc_length; - zip_set_buf_len(dev, BufLen, &dev->packet_len); + zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); zip_data_command_finish(dev, alloc_length, 512, alloc_length, 0); - dev->all_blocks_total = dev->block_total; - if (dev->packet_status != ZIP_PHASE_COMPLETE) + if (dev->packet_status != PHASE_COMPLETE) ui_sb_update_icon(SB_ZIP | dev->id, 1); else ui_sb_update_icon(SB_ZIP | dev->id, 0); @@ -1687,7 +1609,7 @@ zip_command(zip_t *dev, uint8_t *cdb) zip_set_phase(dev, SCSI_PHASE_DATA_OUT); alloc_length = 512; - if ((dev->drv->bus_type == ZIP_BUS_SCSI) && dev->drv->read_only) { + if (dev->drv->read_only) { zip_write_protected(dev); return; } @@ -1696,6 +1618,8 @@ zip_command(zip_t *dev, uint8_t *cdb) case GPCMD_VERIFY_6: case GPCMD_WRITE_6: dev->sector_len = cdb[4]; + if (dev->sector_len == 0) + dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); break; case GPCMD_VERIFY_10: @@ -1713,25 +1637,17 @@ zip_command(zip_t *dev, uint8_t *cdb) break; } - if (dev->drv->is_250) { - if ((dev->sector_pos >= dev->drv->medium_size) || - ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) { - zip_lba_out_of_range(dev); - return; - } - } else { - if ((dev->sector_pos >= ZIP_SECTORS) || - ((dev->sector_pos + dev->sector_len - 1) >= ZIP_SECTORS)) { - zip_lba_out_of_range(dev); - return; - } + if ((dev->sector_pos >= dev->drv->medium_size)/* || + ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/) { + zip_lba_out_of_range(dev); + return; } if (!dev->sector_len) { zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ - dev->packet_status = ZIP_PHASE_COMPLETE; - dev->callback = 20LL * ZIP_TIME; + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); break; } @@ -1747,19 +1663,17 @@ zip_command(zip_t *dev, uint8_t *cdb) dev->requested_blocks = max_len; dev->packet_len = max_len << 9; - zip_set_buf_len(dev, BufLen, &dev->packet_len); + zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); - dev->all_blocks_total = dev->block_total; - if (dev->packet_status != ZIP_PHASE_COMPLETE) + if (dev->packet_status != PHASE_COMPLETE) ui_sb_update_icon(SB_ZIP | dev->id, 1); else ui_sb_update_icon(SB_ZIP | dev->id, 0); return; case GPCMD_WRITE_SAME_10: - zip_set_phase(dev, SCSI_PHASE_DATA_OUT); alloc_length = 512; if ((cdb[1] & 6) == 6) { @@ -1767,7 +1681,7 @@ zip_command(zip_t *dev, uint8_t *cdb) return; } - if ((dev->drv->bus_type == ZIP_BUS_SCSI) && dev->drv->read_only) { + if (dev->drv->read_only) { zip_write_protected(dev); return; } @@ -1775,46 +1689,34 @@ zip_command(zip_t *dev, uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - if (dev->drv->is_250) { - if ((dev->sector_pos >= dev->drv->medium_size) || - ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) { - zip_lba_out_of_range(dev); - return; - } - } else { - if ((dev->sector_pos >= ZIP_SECTORS) || - ((dev->sector_pos + dev->sector_len - 1) >= ZIP_SECTORS)) { - zip_lba_out_of_range(dev); - return; - } + if ((dev->sector_pos >= dev->drv->medium_size)/* || + ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/) { + zip_lba_out_of_range(dev); + return; } if (!dev->sector_len) { zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ - dev->packet_status = ZIP_PHASE_COMPLETE; - dev->callback = 20LL * ZIP_TIME; + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); break; } - max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ + zip_buf_alloc(dev, alloc_length); + zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - dev->packet_len = max_len * alloc_length; - zip_buf_alloc(dev, dev->packet_len); + max_len = 1; + dev->requested_blocks = 1; - dev->requested_blocks = max_len; dev->packet_len = alloc_length; - zip_set_buf_len(dev, BufLen, &dev->packet_len); + zip_set_phase(dev, SCSI_PHASE_DATA_OUT); - zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); + zip_data_command_finish(dev, 512, 512, alloc_length, 1); - dev->all_blocks_total = dev->block_total; - if (dev->packet_status != ZIP_PHASE_COMPLETE) + if (dev->packet_status != PHASE_COMPLETE) ui_sb_update_icon(SB_ZIP | dev->id, 1); else ui_sb_update_icon(SB_ZIP | dev->id, 0); @@ -1837,34 +1739,31 @@ zip_command(zip_t *dev, uint8_t *cdb) zip_buf_alloc(dev, 65536); } - dev->current_page_code = cdb[2] & 0x3F; - zip_log("Mode sense page: %02X\n", dev->current_page_code); - - if (!(zip_mode_sense_page_flags & (1LL << dev->current_page_code))) { + if (!(zip_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { zip_invalid_field(dev); zip_buf_free(dev); return; } - memset(zipbufferb, 0, len); + memset(dev->buffer, 0, len); alloc_length = len; if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = zip_mode_sense(dev, zipbufferb, 4, cdb[2], block_desc); + len = zip_mode_sense(dev, dev->buffer, 4, cdb[2], block_desc); len = MIN(len, alloc_length); - zipbufferb[0] = len - 1; - zipbufferb[1] = 0; + dev->buffer[0] = len - 1; + dev->buffer[1] = 0; if (block_desc) - zipbufferb[3] = 8; + dev->buffer[3] = 8; } else { - len = zip_mode_sense(dev, zipbufferb, 8, cdb[2], block_desc); + len = zip_mode_sense(dev, dev->buffer, 8, cdb[2], block_desc); len = MIN(len, alloc_length); - zipbufferb[0]=(len - 2) >> 8; - zipbufferb[1]=(len - 2) & 255; - zipbufferb[2] = 0; + dev->buffer[0]=(len - 2) >> 8; + dev->buffer[1]=(len - 2) & 255; + dev->buffer[2] = 0; if (block_desc) { - zipbufferb[6] = 0; - zipbufferb[7] = 8; + dev->buffer[6] = 0; + dev->buffer[7] = 8; } } @@ -1892,8 +1791,6 @@ zip_command(zip_t *dev, uint8_t *cdb) dev->total_length = len; dev->do_page_save = cdb[1] & 1; - dev->current_page_pos = 0; - zip_data_command_finish(dev, len, len, len, 1); return; @@ -1930,16 +1827,16 @@ zip_command(zip_t *dev, uint8_t *cdb) preamble_len = 4; size_idx = 3; - zipbufferb[idx++] = 05; - zipbufferb[idx++] = cdb[2]; - zipbufferb[idx++] = 0; + dev->buffer[idx++] = 05; + dev->buffer[idx++] = cdb[2]; + dev->buffer[idx++] = 0; idx++; switch (cdb[2]) { case 0x00: - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 0x83; + dev->buffer[idx++] = 0x00; + dev->buffer[idx++] = 0x83; break; case 0x83: if (idx + 24 > max_len) { @@ -1948,27 +1845,27 @@ zip_command(zip_t *dev, uint8_t *cdb) return; } - zipbufferb[idx++] = 0x02; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 20; - ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Serial */ + dev->buffer[idx++] = 0x02; + dev->buffer[idx++] = 0x00; + dev->buffer[idx++] = 0x00; + dev->buffer[idx++] = 20; + ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Serial */ idx += 20; if (idx + 72 > cdb[4]) goto atapi_out; - zipbufferb[idx++] = 0x02; - zipbufferb[idx++] = 0x01; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 68; - ide_padstr8(zipbufferb + idx, 8, "IOMEGA "); /* Vendor */ + dev->buffer[idx++] = 0x02; + dev->buffer[idx++] = 0x01; + dev->buffer[idx++] = 0x00; + dev->buffer[idx++] = 68; + ide_padstr8(dev->buffer + idx, 8, "IOMEGA "); /* Vendor */ idx += 8; if (dev->drv->is_250) - ide_padstr8(zipbufferb + idx, 40, "ZIP 250 "); /* Product */ + ide_padstr8(dev->buffer + idx, 40, "ZIP 250 "); /* Product */ else - ide_padstr8(zipbufferb + idx, 40, "ZIP 100 "); /* Product */ + ide_padstr8(dev->buffer + idx, 40, "ZIP 100 "); /* Product */ idx += 40; - ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Product */ + ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Product */ idx += 20; break; default: @@ -1981,50 +1878,47 @@ zip_command(zip_t *dev, uint8_t *cdb) preamble_len = 5; size_idx = 4; - memset(zipbufferb, 0, 8); + memset(dev->buffer, 0, 8); if (cdb[1] & 0xe0) - zipbufferb[0] = 0x60; /*No physical device on this LUN*/ + dev->buffer[0] = 0x60; /*No physical device on this LUN*/ else - zipbufferb[0] = 0x00; /*Hard disk*/ - zipbufferb[1] = 0x80; /*Removable*/ - if (dev->drv->is_250) { - zipbufferb[2] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - zipbufferb[3] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; - } else { - zipbufferb[2] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - zipbufferb[3] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; - } - zipbufferb[4] = 31; + dev->buffer[0] = 0x00; /*Hard disk*/ + dev->buffer[1] = 0x80; /*Removable*/ + dev->buffer[2] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + dev->buffer[3] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + // dev->buffer[4] = 31; + dev->buffer[4] = 0; if (dev->drv->bus_type == ZIP_BUS_SCSI) { - zipbufferb[6] = 1; /* 16-bit transfers supported */ - zipbufferb[7] = 0x20; /* Wide bus supported */ + dev->buffer[6] = 1; /* 16-bit transfers supported */ + dev->buffer[7] = 0x20; /* Wide bus supported */ } + dev->buffer[7] |= 0x02; - ide_padstr8(zipbufferb + 8, 8, "IOMEGA "); /* Vendor */ + ide_padstr8(dev->buffer + 8, 8, "IOMEGA "); /* Vendor */ if (dev->drv->is_250) { - ide_padstr8(zipbufferb + 16, 16, "ZIP 250 "); /* Product */ - ide_padstr8(zipbufferb + 32, 4, "42.S"); /* Revision */ + ide_padstr8(dev->buffer + 16, 16, "ZIP 250 "); /* Product */ + ide_padstr8(dev->buffer + 32, 4, "42.S"); /* Revision */ if (max_len >= 44) - ide_padstr8(zipbufferb + 36, 8, "08/08/01"); /* Date? */ + ide_padstr8(dev->buffer + 36, 8, "08/08/01"); /* Date? */ if (max_len >= 122) - ide_padstr8(zipbufferb + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ + ide_padstr8(dev->buffer + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ } else { - ide_padstr8(zipbufferb + 16, 16, "ZIP 100 "); /* Product */ - ide_padstr8(zipbufferb + 32, 4, "E.08"); /* Revision */ + ide_padstr8(dev->buffer + 16, 16, "ZIP 100 "); /* Product */ + ide_padstr8(dev->buffer + 32, 4, "E.08"); /* Revision */ } idx = 36; if (max_len == 96) { - zipbufferb[4] = 91; + dev->buffer[4] = 91; idx = 96; } else if (max_len == 128) { - zipbufferb[4] = 0x75; + dev->buffer[4] = 0x75; idx = 128; } } atapi_out: - zipbufferb[size_idx] = idx - preamble_len; + dev->buffer[size_idx] = idx - preamble_len; len=idx; len = MIN(len, max_len); @@ -2059,10 +1953,14 @@ atapi_out: zip_buf_alloc(dev, 8); - if (zip_read_capacity(dev, dev->current_cdb, zipbufferb, &len) == 0) { - zip_buf_free(dev); - return; - } + max_len = dev->drv->medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(dev->buffer, 0, 8); + dev->buffer[0] = (max_len >> 24) & 0xff; + dev->buffer[1] = (max_len >> 16) & 0xff; + dev->buffer[2] = (max_len >> 8) & 0xff; + dev->buffer[3] = max_len & 0xff; + dev->buffer[6] = 2; /* 512 = 0x0200 */ + len = 8; zip_set_buf_len(dev, BufLen, &len); @@ -2079,59 +1977,63 @@ atapi_out: len = (cdb[7] << 8) | cdb[8]; zip_buf_alloc(dev, len); - memset(zipbufferb, 0, len); + memset(dev->buffer, 0, len); pos = 0; /* List header */ - zipbufferb[pos++] = 0; - zipbufferb[pos++] = 0; - zipbufferb[pos++] = 0; + dev->buffer[pos++] = 0; + dev->buffer[pos++] = 0; + dev->buffer[pos++] = 0; if (dev->drv->f != NULL) - zipbufferb[pos++] = 16; + dev->buffer[pos++] = 16; else - zipbufferb[pos++] = 8; + dev->buffer[pos++] = 8; /* Current/Maximum capacity header */ if (dev->drv->is_250) { + /* ZIP 250 also supports ZIP 100 media, so if the medium is inserted, + we return the inserted medium's size, otherwise, the ZIP 250 size. */ if (dev->drv->f != NULL) { - zipbufferb[pos++] = (dev->drv->medium_size >> 24) & 0xff; - zipbufferb[pos++] = (dev->drv->medium_size >> 16) & 0xff; - zipbufferb[pos++] = (dev->drv->medium_size >> 8) & 0xff; - zipbufferb[pos++] = dev->drv->medium_size & 0xff; - zipbufferb[pos++] = 2; /* Current medium capacity */ + dev->buffer[pos++] = (dev->drv->medium_size >> 24) & 0xff; + dev->buffer[pos++] = (dev->drv->medium_size >> 16) & 0xff; + dev->buffer[pos++] = (dev->drv->medium_size >> 8) & 0xff; + dev->buffer[pos++] = dev->drv->medium_size & 0xff; + dev->buffer[pos++] = 2; /* Current medium capacity */ } else { - zipbufferb[pos++] = (ZIP_250_SECTORS >> 24) & 0xff; - zipbufferb[pos++] = (ZIP_250_SECTORS >> 16) & 0xff; - zipbufferb[pos++] = (ZIP_250_SECTORS >> 8) & 0xff; - zipbufferb[pos++] = ZIP_250_SECTORS & 0xff; - zipbufferb[pos++] = 3; /* Maximum medium capacity */ + dev->buffer[pos++] = (ZIP_250_SECTORS >> 24) & 0xff; + dev->buffer[pos++] = (ZIP_250_SECTORS >> 16) & 0xff; + dev->buffer[pos++] = (ZIP_250_SECTORS >> 8) & 0xff; + dev->buffer[pos++] = ZIP_250_SECTORS & 0xff; + dev->buffer[pos++] = 3; /* Maximum medium capacity */ } } else { - zipbufferb[pos++] = (ZIP_SECTORS >> 24) & 0xff; - zipbufferb[pos++] = (ZIP_SECTORS >> 16) & 0xff; - zipbufferb[pos++] = (ZIP_SECTORS >> 8) & 0xff; - zipbufferb[pos++] = ZIP_SECTORS & 0xff; + /* ZIP 100 only supports ZIP 100 media as well, so we always return + the ZIP 100 size. */ + dev->buffer[pos++] = (ZIP_SECTORS >> 24) & 0xff; + dev->buffer[pos++] = (ZIP_SECTORS >> 16) & 0xff; + dev->buffer[pos++] = (ZIP_SECTORS >> 8) & 0xff; + dev->buffer[pos++] = ZIP_SECTORS & 0xff; if (dev->drv->f != NULL) - zipbufferb[pos++] = 2; + dev->buffer[pos++] = 2; else - zipbufferb[pos++] = 3; + dev->buffer[pos++] = 3; } - zipbufferb[pos++] = 512 >> 16; - zipbufferb[pos++] = 512 >> 8; - zipbufferb[pos++] = 512 & 0xff; + dev->buffer[pos++] = 512 >> 16; + dev->buffer[pos++] = 512 >> 8; + dev->buffer[pos++] = 512 & 0xff; if (dev->drv->f != NULL) { /* Formattable capacity descriptor */ - zipbufferb[pos++] = (dev->drv->medium_size >> 24) & 0xff; - zipbufferb[pos++] = (dev->drv->medium_size >> 16) & 0xff; - zipbufferb[pos++] = (dev->drv->medium_size >> 8) & 0xff; - zipbufferb[pos++] = dev->drv->medium_size & 0xff; - zipbufferb[pos++] = 0; - zipbufferb[pos++] = 512 >> 16; - zipbufferb[pos++] = 512 >> 8; - zipbufferb[pos++] = 512 & 0xff; + dev->buffer[pos++] = (dev->drv->medium_size >> 24) & 0xff; + dev->buffer[pos++] = (dev->drv->medium_size >> 16) & 0xff; + dev->buffer[pos++] = (dev->drv->medium_size >> 8) & 0xff; + dev->buffer[pos++] = dev->drv->medium_size & 0xff; + dev->buffer[pos++] = 0; + dev->buffer[pos++] = 512 >> 16; + dev->buffer[pos++] = 512 >> 8; + dev->buffer[pos++] = 512 & 0xff; } zip_set_buf_len(dev, BufLen, &len); @@ -2151,23 +2053,37 @@ atapi_out: } +static void +zip_command_stop(scsi_common_t *sc) +{ + zip_t *dev = (zip_t *) sc; + + zip_command_complete(dev); + zip_buf_free(dev); +} + + /* The command second phase function, needed for Mode Select. */ static uint8_t -zip_phase_data_out(zip_t *dev) +zip_phase_data_out(scsi_common_t *sc) { + zip_t *dev = (zip_t *) sc; + uint16_t block_desc_len; uint16_t pos; uint8_t error = 0; uint8_t page, page_len; - uint16_t i = 0; + uint32_t i = 0; uint8_t hdr_len, val, old_val, ch; - uint32_t last_to_write = 0, len = 0; + uint32_t last_to_write = 0; uint32_t c, h, s; + int len = 0; + switch(dev->current_cdb[0]) { case GPCMD_VERIFY_6: case GPCMD_VERIFY_10: @@ -2183,35 +2099,32 @@ zip_phase_data_out(zip_t *dev) break; case GPCMD_WRITE_SAME_10: if (!dev->current_cdb[7] && !dev->current_cdb[8]) { - if (dev->drv->is_250) - last_to_write = (dev->drv->medium_size - 1); - else - last_to_write = (ZIP_SECTORS - 1); + last_to_write = (dev->drv->medium_size - 1); } else last_to_write = dev->sector_pos + dev->sector_len - 1; for (i = dev->sector_pos; i <= last_to_write; i++) { if (dev->current_cdb[1] & 2) { - zipbufferb[0] = (i >> 24) & 0xff; - zipbufferb[1] = (i >> 16) & 0xff; - zipbufferb[2] = (i >> 8) & 0xff; - zipbufferb[3] = i & 0xff; + dev->buffer[0] = (i >> 24) & 0xff; + dev->buffer[1] = (i >> 16) & 0xff; + dev->buffer[2] = (i >> 8) & 0xff; + dev->buffer[3] = i & 0xff; } else if (dev->current_cdb[1] & 4) { /* CHS are 96,1,2048 (ZIP 100) and 239,1,2048 (ZIP 250) */ s = (i % 2048); h = ((i - s) / 2048) % 1; c = ((i - s) / 2048) / 1; - zipbufferb[0] = (c >> 16) & 0xff; - zipbufferb[1] = (c >> 8) & 0xff; - zipbufferb[2] = c & 0xff; - zipbufferb[3] = h & 0xff; - zipbufferb[4] = (s >> 24) & 0xff; - zipbufferb[5] = (s >> 16) & 0xff; - zipbufferb[6] = (s >> 8) & 0xff; - zipbufferb[7] = s & 0xff; + dev->buffer[0] = (c >> 16) & 0xff; + dev->buffer[1] = (c >> 8) & 0xff; + dev->buffer[2] = c & 0xff; + dev->buffer[3] = h & 0xff; + dev->buffer[4] = (s >> 24) & 0xff; + dev->buffer[5] = (s >> 16) & 0xff; + dev->buffer[6] = (s >> 8) & 0xff; + dev->buffer[7] = s & 0xff; } fseek(dev->drv->f, dev->drv->base + (i << 9), SEEK_SET); - fwrite(zipbufferb, 1, 512, dev->drv->f); + fwrite(dev->buffer, 1, 512, dev->drv->f); } break; case GPCMD_MODE_SELECT_6: @@ -2223,13 +2136,13 @@ zip_phase_data_out(zip_t *dev) if (dev->drv->bus_type == ZIP_BUS_SCSI) { if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = zipbufferb[2]; + block_desc_len = dev->buffer[2]; block_desc_len <<= 8; - block_desc_len |= zipbufferb[3]; + block_desc_len |= dev->buffer[3]; } else { - block_desc_len = zipbufferb[6]; + block_desc_len = dev->buffer[6]; block_desc_len <<= 8; - block_desc_len |= zipbufferb[7]; + block_desc_len |= dev->buffer[7]; } } else block_desc_len = 0; @@ -2237,8 +2150,13 @@ zip_phase_data_out(zip_t *dev) pos = hdr_len + block_desc_len; while(1) { - page = zipbufferb[pos] & 0x3F; - page_len = zipbufferb[pos + 1]; + if (pos >= dev->current_cdb[4]) { + zip_log("ZIP %i: Buffer has only block descriptor\n", dev->id); + break; + } + + page = dev->buffer[pos] & 0x3F; + page_len = dev->buffer[pos + 1]; pos += 2; @@ -2247,7 +2165,7 @@ zip_phase_data_out(zip_t *dev) else { for (i = 0; i < page_len; i++) { ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; - val = zipbufferb[pos + i]; + val = dev->buffer[pos + i]; old_val = dev->ms_pages_saved.pages[page][i + 2]; if (val != old_val) { if (ch) @@ -2272,478 +2190,210 @@ zip_phase_data_out(zip_t *dev) } if (error) { + zip_buf_free(dev); zip_invalid_field_pl(dev); return 0; } break; } + zip_command_stop((scsi_common_t *) dev); return 1; } -/* This is the general ATAPI PIO request function. */ -static void -zip_pio_request(zip_t *dev, uint8_t out) -{ - int ret = 0; - - if (dev->drv->bus_type < ZIP_BUS_SCSI) { - zip_log("ZIP %i: Lowering IDE IRQ\n", dev->id); - ide_irq_lower(ide_drives[dev->drv->ide_channel]); - } - - dev->status = BUSY_STAT; - - if (dev->pos >= dev->packet_len) { - zip_log("ZIP %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read"); - - dev->pos = dev->request_pos = 0; - if (out) { - ret = zip_phase_data_out(dev); - /* If ret = 0 (phase 1 error), then we do not do anything else other than - free the buffer, as the phase and callback have already been set by the - error function. */ - if (ret) - zip_command_complete(dev); - } else - zip_command_complete(dev); - zip_buf_free(dev); - } else { - zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos, - out ? "written" : "read", dev->packet_len - dev->pos); - - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ - if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) - dev->max_transfer_len = dev->packet_len - dev->pos; - zip_log("ZIP %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, - dev->max_transfer_len); - - dev->packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; - - dev->status = BUSY_STAT; - dev->phase = 1; - zip_phase_callback(dev); - dev->callback = 0LL; - zip_set_callback(dev); - - dev->request_pos = 0; - } -} - - -static int -zip_read_from_ide_dma(uint8_t channel) -{ - zip_t *dev; - - uint8_t id = atapi_zip_drives[channel]; - int ret; - - if (id > ZIP_NUM) - return 0; - - dev = zip[id]; - - if (ide_bus_master_write) { - ret = ide_bus_master_write(channel >> 1, - zipbufferb, dev->packet_len, - ide_bus_master_priv[channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - zip_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; -} - - -static int -zip_read_from_scsi_dma(uint8_t scsi_id) -{ - zip_t *dev; - - uint8_t id = scsi_zip_drives[scsi_id]; - int32_t *BufLen = &SCSIDevices[scsi_id].BufferLength; - - if (id > ZIP_NUM) - return 0; - - dev = zip[id]; - - zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(zipbufferb, SCSIDevices[scsi_id].CmdBuffer, *BufLen); - return 1; -} - - -static void -zip_irq_raise(zip_t *dev) -{ - if (dev->drv->bus_type < ZIP_BUS_SCSI) - ide_irq_raise(ide_drives[dev->drv->ide_channel]); -} - - -static int -zip_read_from_dma(zip_t *dev) -{ - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; - int ret = 0; - - if (dev->drv->bus_type == ZIP_BUS_SCSI) - ret = zip_read_from_scsi_dma(dev->drv->scsi_device_id); - else - ret = zip_read_from_ide_dma(dev->drv->ide_channel); - - if (ret != 1) - return ret; - - if (dev->drv->bus_type == ZIP_BUS_SCSI) - zip_log("ZIP %i: SCSI Input data length: %i\n", dev->id, *BufLen); - else - zip_log("ZIP %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len); - - ret = zip_phase_data_out(dev); - - if (ret) - return 1; - else - return 0; -} - - -static int -zip_write_to_ide_dma(uint8_t channel) -{ - zip_t *dev; - - uint8_t id = atapi_zip_drives[channel]; - int ret; - - if (id > ZIP_NUM) { - zip_log("ZIP %i: Drive not found\n", id); - return 0; - } - - dev = zip[id]; - - if (ide_bus_master_read) { - ret = ide_bus_master_read(channel >> 1, - zipbufferb, dev->packet_len, - ide_bus_master_priv[channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - zip_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; -} - - -static int -zip_write_to_scsi_dma(uint8_t scsi_id) -{ - zip_t *dev; - - uint8_t id = scsi_zip_drives[scsi_id]; - int32_t *BufLen = &SCSIDevices[scsi_id].BufferLength; - - if (id > ZIP_NUM) - return 0; - - dev = zip[id]; - - zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(SCSIDevices[scsi_id].CmdBuffer, zipbufferb, *BufLen); - zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], - zipbufferb[6], zipbufferb[7]); - zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - SCSIDevices[scsi_id].CmdBuffer[0], SCSIDevices[scsi_id].CmdBuffer[1], - SCSIDevices[scsi_id].CmdBuffer[2], SCSIDevices[scsi_id].CmdBuffer[3], - SCSIDevices[scsi_id].CmdBuffer[4], SCSIDevices[scsi_id].CmdBuffer[5], - SCSIDevices[scsi_id].CmdBuffer[6], SCSIDevices[scsi_id].CmdBuffer[7]); - return 1; -} - - -static int -zip_write_to_dma(zip_t *dev) -{ - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; - int ret = 0; - - if (dev->drv->bus_type == ZIP_BUS_SCSI) { - zip_log("Write to SCSI DMA: (ID %02X)\n", dev->drv->scsi_device_id); - ret = zip_write_to_scsi_dma(dev->drv->scsi_device_id); - } else - ret = zip_write_to_ide_dma(dev->drv->ide_channel); - - if (dev->drv->bus_type == ZIP_BUS_SCSI) - zip_log("ZIP %i: SCSI Output data length: %i\n", dev->id, *BufLen); - else - zip_log("ZIP %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len); - - return ret; -} - - -void -zip_phase_callback(zip_t *dev) -{ - int ret; - - switch(dev->packet_status) { - case ZIP_PHASE_IDLE: - zip_log("ZIP %i: ZIP_PHASE_IDLE\n", dev->id); - dev->pos = 0; - dev->phase = 1; - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - return; - case ZIP_PHASE_COMMAND: - zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", dev->id); - dev->status = BUSY_STAT | (dev->status & ERR_STAT); - memcpy(dev->atapi_cdb, zipbufferb, 12); - zip_command(dev, dev->atapi_cdb); - return; - case ZIP_PHASE_COMPLETE: - zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", dev->id); - dev->status = READY_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; - ui_sb_update_icon(SB_ZIP | dev->id, 0); - zip_irq_raise(dev); - return; - case ZIP_PHASE_DATA_OUT: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 0; - zip_irq_raise(dev); - return; - case ZIP_PHASE_DATA_OUT_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", dev->id); - ret = zip_read_from_dma(dev); - - if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) { - zip_log("ZIP %i: DMA data out phase done\n"); - zip_buf_free(dev); - zip_command_complete(dev); - } else if (ret == 2) { - zip_log("ZIP %i: DMA out not enabled, wait\n"); - zip_command_bus(dev); - } else { - zip_log("ZIP %i: DMA data out phase failure\n"); - zip_buf_free(dev); - } - return; - case ZIP_PHASE_DATA_IN: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 2; - zip_irq_raise(dev); - return; - case ZIP_PHASE_DATA_IN_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", dev->id); - ret = zip_write_to_dma(dev); - - if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) { - zip_log("ZIP %i: DMA data in phase done\n", dev->id); - zip_buf_free(dev); - zip_command_complete(dev); - } else if (ret == 2) { - zip_log("ZIP %i: DMA in not enabled, wait\n", dev->id); - zip_command_bus(dev); - } else { - zip_log("ZIP %i: DMA data in phase failure\n", dev->id); - zip_buf_free(dev); - } - return; - case ZIP_PHASE_ERROR: - zip_log("ZIP %i: ZIP_PHASE_ERROR\n", dev->id); - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; - zip_irq_raise(dev); - ui_sb_update_icon(SB_ZIP | dev->id, 0); - return; - } -} - - -uint32_t -zip_read(uint8_t channel, int length) -{ - zip_t *dev; - - uint16_t *zipbufferw; - uint32_t *zipbufferl; - - uint8_t id = atapi_zip_drives[channel]; - - uint32_t temp = 0; - - if (id > ZIP_NUM) - return 0; - - dev = zip[id]; - - zipbufferw = (uint16_t *) zipbufferb; - zipbufferl = (uint32_t *) zipbufferb; - - if (!zipbufferb) - return 0; - - /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, - which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 512 bytes). */ - switch(length) { - case 1: - temp = (dev->pos < dev->packet_len) ? zipbufferb[dev->pos] : 0; - dev->pos++; - dev->request_pos++; - break; - case 2: - temp = (dev->pos < dev->packet_len) ? zipbufferw[dev->pos >> 1] : 0; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - temp = (dev->pos < dev->packet_len) ? zipbufferl[dev->pos >> 2] : 0; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return 0; - } - - if (dev->packet_status == ZIP_PHASE_DATA_IN) { - zip_log("ZIP %i: Returning: %04X (buffer position: %05i, request position: %05i)\n", - id, temp, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - zip_log("ZIP %i: Issuing read callback\n", id); - zip_pio_request(dev, 0); - } - return temp; - } else { - zip_log("ZIP %i: Returning: 0000 (buffer position: %05i, request position: %05i)\n", - id, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); - return 0; - } -} - - -void -zip_write(uint8_t channel, uint32_t val, int length) -{ - zip_t *dev; - - uint16_t *zipbufferw; - uint32_t *zipbufferl; - - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) - return; - - dev = zip[id]; - - if (dev->packet_status == ZIP_PHASE_IDLE) { - if (!zipbufferb) - zip_buf_alloc(dev, 12); - } - - zipbufferw = (uint16_t *) zipbufferb; - zipbufferl = (uint32_t *) zipbufferb; - - if (!zipbufferb) - return; - - switch(length) { - case 1: - zipbufferb[dev->pos] = val & 0xff; - dev->pos++; - dev->request_pos++; - break; - case 2: - zipbufferw[dev->pos >> 1] = val & 0xffff; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - zipbufferl[dev->pos >> 2] = val; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return; - } - - if (dev->packet_status == ZIP_PHASE_DATA_OUT) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - zip_pio_request(dev, 1); - } - return; - } else if (dev->packet_status == ZIP_PHASE_IDLE) { - if (dev->pos >= 12) { - dev->pos = 0; - dev->status = BUSY_STAT; - dev->packet_status = ZIP_PHASE_COMMAND; - timer_process(); - zip_phase_callback(dev); - timer_update_outstanding(); - } - return; - } -} - - /* Peform a master init on the entire module. */ void zip_global_init(void) { /* Clear the global data. */ - memset(zip, 0x00, sizeof(zip)); memset(zip_drives, 0x00, sizeof(zip_drives)); } +static int +zip_get_max(int ide_has_dma, int type) +{ + int ret; + + switch(type) { + case TYPE_PIO: + ret = ide_has_dma ? 3 : 0; + break; + case TYPE_SDMA: + default: + ret = -1; + break; + case TYPE_MDMA: + ret = ide_has_dma ? 1 : -1; + break; + case TYPE_UDMA: + ret = ide_has_dma ? 2 : -1; + break; + } + + return ret; +} + + +static int +zip_get_timings(int ide_has_dma, int type) +{ + int ret; + + switch(type) { + case TIMINGS_DMA: + ret = ide_has_dma ? 0x96 : 0; + break; + case TIMINGS_PIO: + ret = ide_has_dma ? 0xb4 : 0; + break; + case TIMINGS_PIO_FC: + ret = ide_has_dma ? 0xb4 : 0; + break; + default: + ret = 0; + break; + } + + return ret; +} + + +static void +zip_100_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ +} + + +static void +zip_250_identify(ide_t *ide, int ide_has_dma) +{ + ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ + + if (ide_has_dma) { + ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ + ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ + } +} + + +static void +zip_identify(ide_t *ide, int ide_has_dma) +{ + zip_t *zip; + + zip = (zip_t *) ide->sc; + + /* ATAPI device, direct-access device, removable media, interrupt DRQ: + + Using (2 << 5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive + as a LS-120. */ + ide->buffer[0] = 0x8000 | (0 << 8) | 0x80 | (1 << 5); + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (zip_drives[zip->id].is_250) + zip_250_identify(ide, ide_has_dma); + else + zip_100_identify(ide); +} + + +static void +zip_drive_reset(int c) +{ + zip_t *dev; + scsi_device_t *sd; + ide_t *id; + + if (!zip_drives[c].priv) { + zip_drives[c].priv = (zip_t *) malloc(sizeof(zip_t)); + memset(zip_drives[c].priv, 0, sizeof(zip_t)); + } + + dev = (zip_t *) zip_drives[c].priv; + + dev->id = c; + + if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { + /* SCSI ZIP, attach to the SCSI bus. */ + sd = &scsi_devices[zip_drives[c].scsi_device_id]; + + sd->sc = (scsi_common_t *) dev; + sd->command = zip_command; + sd->request_sense = zip_request_sense_for_scsi; + sd->reset = zip_reset; + sd->phase_data_out = zip_phase_data_out; + sd->command_stop = zip_command_stop; + sd->type = SCSI_REMOVABLE_DISK; + } else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) { + /* ATAPI CD-ROM, attach to the IDE bus. */ + id = ide_get_drive(zip_drives[c].ide_channel); + /* If the IDE channel is initialized, we attach to it, + otherwise, we do nothing - it's going to be a drive + that's not attached to anything. */ + if (id) { + id->sc = (scsi_common_t *) dev; + id->get_max = zip_get_max; + id->get_timings = zip_get_timings; + id->identify = zip_identify; + id->stop = NULL; + id->packet_command = zip_command; + id->device_reset = zip_reset; + id->phase_data_out = zip_phase_data_out; + id->command_stop = zip_command_stop; + id->bus_master_error = zip_bus_master_error; + id->interrupt_drq = 1; + + ide_atapi_attach(id); + } + } +} + + void zip_hard_reset(void) { + zip_t *dev; int c; for (c = 0; c < ZIP_NUM; c++) { - if (zip_drives[c].bus_type) { + if ((zip_drives[c].bus_type == ZIP_BUS_ATAPI) || (zip_drives[c].bus_type == ZIP_BUS_SCSI)) { zip_log("ZIP hard_reset drive=%d\n", c); - if (!zip[c]) { - zip[c] = (zip_t *) malloc(sizeof(zip_t)); - memset(zip[c], 0, sizeof(zip_t)); - } + /* Make sure to ignore any SCSI ZIP drive that has an out of range ID. */ + if ((zip_drives[c].bus_type == ZIP_BUS_SCSI) && (zip_drives[c].scsi_device_id > SCSI_ID_MAX)) + continue; - zip[c]->id = c; - zip[c]->drv = &zip_drives[c]; + /* Make sure to ignore any ATAPI ZIP drive that has an out of range IDE channel. */ + if ((zip_drives[c].bus_type == ZIP_BUS_ATAPI) && (zip_drives[c].ide_channel > 7)) + continue; - zip_init(zip[c]); + zip_drive_reset(c); + + dev = (zip_t *) zip_drives[c].priv; + + dev->id = c; + dev->drv = &zip_drives[c]; + + zip_init(dev); if (wcslen(zip_drives[c].image_path)) - zip_load(zip[c], zip_drives[c].image_path); + zip_load(dev, zip_drives[c].image_path); - zip_mode_sense_load(zip[c]); + zip_mode_sense_load(dev); + + if (zip_drives[c].bus_type == ZIP_BUS_SCSI) + zip_log("SCSI ZIP drive %i attached to SCSI ID %i\n", c, zip_drives[c].scsi_device_id); + else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) + zip_log("ATAPI ZIP drive %i attached to IDE channel %i\n", c, zip_drives[c].ide_channel); } } - - build_atapi_zip_map(); } @@ -2754,13 +2404,13 @@ zip_close(void) int c; for (c = 0; c < ZIP_NUM; c++) { - dev = zip[c]; + dev = (zip_t *) zip_drives[c].priv; if (dev) { - zip_disk_close(dev); + zip_disk_unload(dev); - free(zip[c]); - zip[c] = NULL; + free(dev); + zip_drives[c].priv = NULL; } } } diff --git a/src/disk/zip.h b/src/disk/zip.h index 67be6797b..02c355472 100644 --- a/src/disk/zip.h +++ b/src/disk/zip.h @@ -9,11 +9,11 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)zip.h 1.0.6 2018/04/30 + * Version: @(#)zip.h 1.0.10 2019/11/19 * * Author: Miran Grca, * - * Copyright 2018 Miran Grca. + * Copyright 2018,2019 Miran Grca. */ #ifndef EMU_ZIP_H #define EMU_ZIP_H @@ -21,18 +21,9 @@ #define ZIP_NUM 4 -#define ZIP_PHASE_IDLE 0x00 -#define ZIP_PHASE_COMMAND 0x01 -#define ZIP_PHASE_COMPLETE 0x02 -#define ZIP_PHASE_DATA_IN 0x03 -#define ZIP_PHASE_DATA_IN_DMA 0x04 -#define ZIP_PHASE_DATA_OUT 0x05 -#define ZIP_PHASE_DATA_OUT_DMA 0x06 -#define ZIP_PHASE_ERROR 0x80 - #define BUF_SIZE 32768 -#define ZIP_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) +#define ZIP_TIME 10.0 #define ZIP_SECTORS (96*2048) @@ -48,21 +39,25 @@ enum { typedef struct { - unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ - uint8_t ide_channel, - bus_mode; /* Bit 0 = PIO suported; + uint8_t id, + res, res0, /* Reserved for other ID's. */ + res1, + ide_channel, scsi_device_id, + bus_type, /* 0 = ATAPI, 1 = SCSI */ + bus_mode, /* Bit 0 = PIO suported; Bit 1 = DMA supportd. */ + read_only, /* Struct variable reserved for + media status. */ + pad, pad0; - unsigned int scsi_device_id, is_250; + FILE *f; + void *priv; wchar_t image_path[1024], prev_image_path[1024]; - int read_only, ui_writeprot; - - uint32_t medium_size, base; - - FILE *f; + uint32_t is_250, medium_size, + base; } zip_drive_t; typedef struct { @@ -70,34 +65,27 @@ typedef struct { zip_drive_t *drv; - uint8_t previous_command, - error, features, - status, phase, - id, *buffer, + uint8_t *buffer, atapi_cdb[16], current_cdb[16], sense[256]; + uint8_t status, phase, + error, id, + features, pad0, + pad1, pad2; + uint16_t request_length, max_transfer_len; - int toctimes, media_status, - is_dma, requested_blocks, - current_page_len, current_page_pos, - total_length, written_length, - mode_select_phase, do_page_save, - callback, data_pos, - packet_status, unit_attention, - cdb_len_setting, cdb_len, - request_pos, total_read, - block_total, all_blocks_total, - old_len, block_descriptor_len, - init_length; + int requested_blocks, packet_status, + total_length, do_page_save, + unit_attention, request_pos, + old_len, pad3; uint32_t sector_pos, sector_len, - packet_len, pos, - seek_pos; + packet_len, pos; - uint64_t current_page_code; + double callback; } zip_t; @@ -116,34 +104,14 @@ extern uint8_t scsi_zip_drives[16]; extern "C" { #endif -extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); -extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); -extern void (*ide_bus_master_set_irq)(int channel, void *priv); -extern void *ide_bus_master_priv[2]; - -extern void build_atapi_zip_map(void); -extern void build_scsi_zip_map(void); -extern int zip_ZIP_PHASE_to_scsi(zip_t *dev); -extern int zip_atapi_phase_to_scsi(zip_t *dev); -extern void zip_command(zip_t *dev, uint8_t *cdb); -extern void zip_phase_callback(zip_t *dev); -extern uint32_t zip_read(uint8_t channel, int length); -extern void zip_write(uint8_t channel, uint32_t val, int length); - extern void zip_disk_close(zip_t *dev); extern void zip_disk_reload(zip_t *dev); -extern void zip_reset(zip_t *dev); -extern void zip_set_signature(zip_t *dev); -extern void zip_request_sense_for_scsi(zip_t *dev, uint8_t *buffer, uint8_t alloc_length); -extern void zip_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); extern void zip_insert(zip_t *dev); -extern int find_zip_for_scsi_id(uint8_t scsi_id); -extern int zip_read_capacity(zip_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); - extern void zip_global_init(void); extern void zip_hard_reset(void); +extern void zip_reset(scsi_common_t *sc); extern int zip_load(zip_t *dev, wchar_t *fn); extern void zip_close(); diff --git a/src/dma.c b/src/dma.c index ef07c6137..7322f471e 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1,48 +1,35 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the Intel DMA controllers. * - * Version: @(#)dma.c 1.0.3 2018/03/13 + * Version: @(#)dma.c 1.0.7 2019/09/28 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include #include #include #include "86box.h" +#ifdef USE_NEW_DYNAREC +#include "cpu_new/cpu.h" +#include "cpu_new/x86.h" +#else #include "cpu/cpu.h" #include "cpu/x86.h" +#endif #include "machine/machine.h" #include "mca.h" #include "mem.h" @@ -61,8 +48,13 @@ static int dma_wp, static uint8_t dma_m; static uint8_t dma_stat; static uint8_t dma_stat_rq; +static uint8_t dma_stat_rq_pc; static uint8_t dma_command, dma16_command; +static uint8_t dma_req_is_soft; +static uint8_t dma_buffer[65536]; +static uint16_t dma16_buffer[65536]; + static struct { int xfr_command, xfr_channel; @@ -83,6 +75,47 @@ static struct { static void dma_ps2_run(int channel); +int +dma_get_drq(int channel) +{ + return !!(dma_stat_rq_pc & (1 << channel)); +} + + +void +dma_set_drq(int channel, int set) +{ + dma_stat_rq_pc &= ~(1 << channel); + if (set) + dma_stat_rq_pc |= (1 << channel); +} + + +static void +dma_block_transfer(int channel) +{ + int i, bit16; + + bit16 = (channel >= 4); + + dma_req_is_soft = 1; + for (i = 0; i <= dma[channel].cb; i++) { + if ((dma[channel].mode & 0x8c) == 0x84) { + if (bit16) + dma_channel_write(channel, dma16_buffer[i]); + else + dma_channel_write(channel, dma_buffer[i]); + } else if ((dma[channel].mode & 0x8c) == 0x88) { + if (bit16) + dma16_buffer[i] = dma_channel_read(channel); + else + dma_buffer[i] = dma_channel_read(channel); + } + } + dma_req_is_soft = 0; +} + + static uint8_t dma_read(uint16_t addr, void *priv) { @@ -111,11 +144,13 @@ dma_read(uint16_t addr, void *priv) return(temp); case 8: /*Status register*/ - temp = dma_stat & 0xf; + temp = dma_stat_rq_pc & 0xf; + temp <<= 4; + temp |= dma_stat & 0xf; dma_stat &= ~0xf; return(temp); - case 0xd: + case 0xd: /*Temporary register*/ return(0); } @@ -156,13 +191,25 @@ dma_write(uint16_t addr, uint8_t val, void *priv) case 8: /*Control register*/ dma_command = val; + if (val & 0x01) + fatal("Memory-to-memory enable\n"); return; + case 9: /*Request register */ + channel = (val & 3); + if (val & 4) { + dma_stat_rq_pc |= (1 << channel); + dma_block_transfer(channel); + } else + dma_stat_rq_pc &= ~(1 << channel); + break; + case 0xa: /*Mask*/ + channel = (val & 3); if (val & 4) - dma_m |= (1 << (val & 3)); - else - dma_m &= ~(1 << (val & 3)); + dma_m |= (1 << channel); + else + dma_m &= ~(1 << channel); return; case 0xb: /*Mode*/ @@ -186,6 +233,11 @@ dma_write(uint16_t addr, uint8_t val, void *priv) case 0xd: /*Master clear*/ dma_wp = 0; dma_m |= 0xf; + dma_stat_rq_pc &= ~0x0f; + return; + + case 0xe: /*Clear mask*/ + dma_m &= 0xf0; return; case 0xf: /*Mask write*/ @@ -387,7 +439,8 @@ dma16_read(uint16_t addr, void *priv) return(temp); case 8: /*Status register*/ - temp = dma_stat >> 4; + temp = (dma_stat_rq_pc & 0xf0); + temp |= dma_stat >> 4; dma_stat &= ~0xf0; return(temp); } @@ -438,11 +491,21 @@ dma16_write(uint16_t addr, uint8_t val, void *priv) case 8: /*Control register*/ return; + case 9: /*Request register */ + channel = (val & 3) + 4; + if (val & 4) { + dma_stat_rq_pc |= (1 << channel); + dma_block_transfer(channel); + } else + dma_stat_rq_pc &= ~(1 << channel); + break; + case 0xa: /*Mask*/ + channel = (val & 3); if (val & 4) - dma_m |= (0x10 << (val & 3)); - else - dma_m &= ~(0x10 << (val & 3)); + dma_m |= (0x10 << channel); + else + dma_m &= ~(0x10 << channel); return; case 0xb: /*Mode*/ @@ -466,6 +529,11 @@ dma16_write(uint16_t addr, uint8_t val, void *priv) case 0xd: /*Master clear*/ dma16_wp = 0; dma_m |= 0xf0; + dma_stat_rq_pc &= ~0xf0; + return; + + case 0xe: /*Clear mask*/ + dma_m &= 0x0f; return; case 0xf: /*Mask write*/ @@ -547,8 +615,8 @@ dma_reset(void) dma_wp = dma16_wp = 0; dma_m = 0; - for (c = 0; c < 16; c++) - dmaregs[c] = 0; + for (c = 0; c < 16; c++) + dmaregs[c] = dma16regs[c] = 0; for (c = 0; c < 8; c++) { dma[c].mode = 0; dma[c].ac = 0; @@ -557,12 +625,22 @@ dma_reset(void) dma[c].cb = 0; dma[c].size = (c & 4) ? 1 : 0; } + + dma_stat = 0x00; + dma_stat_rq = 0x00; + dma_stat_rq_pc = 0x00; + dma_req_is_soft = 0; + + memset(dma_buffer, 0x00, sizeof(dma_buffer)); + memset(dma16_buffer, 0x00, sizeof(dma16_buffer)); } void dma_init(void) { + dma_reset(); + io_sethandler(0x0000, 16, dma_read,NULL,NULL, dma_write,NULL,NULL, NULL); io_sethandler(0x0080, 8, @@ -574,6 +652,8 @@ dma_init(void) void dma16_init(void) { + dma_reset(); + io_sethandler(0x00C0, 32, dma16_read,NULL,NULL, dma16_write,NULL,NULL, NULL); io_sethandler(0x0088, 8, @@ -614,6 +694,8 @@ dma_alias_remove_piix(void) void ps2_dma_init(void) { + dma_reset(); + io_sethandler(0x0018, 1, dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); io_sethandler(0x001a, 1, @@ -625,7 +707,7 @@ ps2_dma_init(void) uint8_t _dma_read(uint32_t addr) { - uint8_t temp = mem_readb_phys_dma(addr); + uint8_t temp = mem_readb_phys(addr); return(temp); } @@ -634,7 +716,7 @@ _dma_read(uint32_t addr) void _dma_write(uint32_t addr, uint8_t val) { - mem_writeb_phys_dma(addr, val); + mem_writeb_phys(addr, val); mem_invalidate_range(addr, addr); } @@ -654,14 +736,16 @@ dma_channel_read(int channel) return(DMA_NODATA); } - if (! AT) - refreshread(); - - if (dma_m & (1 << channel)) + if ((dma_m & (1 << channel)) && !dma_req_is_soft) return(DMA_NODATA); if ((dma_c->mode & 0xC) != 8) return(DMA_NODATA); + if (!AT && !channel) + refreshread(); + /* if (!AT && channel) + pclog("DMA refresh read on channel %i\n", channel); */ + if (! dma_c->size) { temp = _dma_read(dma_c->ac); @@ -725,14 +809,16 @@ dma_channel_write(int channel, uint16_t val) return(DMA_NODATA); } - if (! AT) - refreshread(); - - if (dma_m & (1 << channel)) + if ((dma_m & (1 << channel)) && !dma_req_is_soft) return(DMA_NODATA); if ((dma_c->mode & 0xC) != 4) return(DMA_NODATA); + /* if (!AT) + refreshread(); + if (!AT) + pclog("DMA refresh write on channel %i\n", channel); */ + if (! dma_c->size) { _dma_write(dma_c->ac, val & 0xff); @@ -878,10 +964,7 @@ dma_ps2_run(int channel) int dma_mode(int channel) { - if (channel < 4) - return(dma[channel].mode); - else - return(dma[channel & 3].mode); + return(dma[channel].mode); } @@ -895,7 +978,7 @@ DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize) memcpy(DataRead, &ram[PhysAddress], TotalSize); #else for (i = 0; i < TotalSize; i++) - DataRead[i] = mem_readb_phys_dma(PhysAddress + i); + DataRead[i] = mem_readb_phys(PhysAddress + i); #endif } @@ -910,7 +993,7 @@ DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize) memcpy(&ram[PhysAddress], DataWrite, TotalSize); #else for (i = 0; i < TotalSize; i++) - mem_writeb_phys_dma(PhysAddress + i, DataWrite[i]); + mem_writeb_phys(PhysAddress + i, DataWrite[i]); mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); #endif diff --git a/src/dma.h b/src/dma.h index 32f90c4e7..75f923e66 100644 --- a/src/dma.h +++ b/src/dma.h @@ -78,6 +78,9 @@ extern int readdma3(void); extern void writedma2(uint8_t temp); +extern int dma_get_drq(int channel); +extern void dma_set_drq(int channel, int set); + extern int dma_channel_read(int channel); extern int dma_channel_write(int channel, uint16_t val); diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 2b4e38514..401093ef0 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -1,39 +1,21 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * Version: @(#)fdc.c 1.0.9 2018/06/12 + * Version: @(#)fdc.c 1.0.21 2019/10/20 * - * Authors: Miran Grca, - * Sarah Walker, + * Authors: Sarah Walker, + * Miran Grca, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -47,8 +29,6 @@ #include "../cpu/cpu.h" #include "../machine/machine.h" #include "../io.h" -#include "../mem.h" -#include "../rom.h" #include "../dma.h" #include "../pic.h" #include "../timer.h" @@ -57,7 +37,7 @@ #include "fdc.h" -extern int64_t motoron[FDD_NUM]; +extern uint64_t motoron[FDD_NUM]; const int command_has_drivesel[256] = { @@ -100,10 +80,10 @@ const int command_has_drivesel[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -uint8_t current_drive = 0; + +static uint8_t current_drive = 0; static void fdc_callback(void *priv); -int timetolive; int lastbyte=0; int floppymodified[4]; @@ -111,13 +91,11 @@ int floppyrate[4]; #ifdef ENABLE_FDC_LOG int fdc_do_log = ENABLE_FDC_LOG; -#endif static void fdc_log(const char *fmt, ...) { -#ifdef ENABLE_FDC_LOG va_list ap; if (fdc_do_log) @@ -126,21 +104,16 @@ fdc_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define fdc_log(fmt, ...) +#endif uint8_t -fdc_ps1_525(void) +fdc_get_current_drive(void) { - switch (romset) { - case ROM_IBMPS1_2011: - case ROM_IBMPS1_2121: - case ROM_IBMPS1_2121_ISA: - return fdd_is_525(current_drive) ? 0x40 : 0x00; - default: - return 0x00; - } + return current_drive; } @@ -333,7 +306,7 @@ fdc_fifo_buf_read(fdc_t *fdc) static -void fdc_int(fdc_t *fdc) +void fdc_int(fdc_t *fdc, int set_fintr) { int ienable = 0; @@ -343,7 +316,9 @@ void fdc_int(fdc_t *fdc) if (ienable) picint(1 << fdc->irq); - fdc->fintr = 1; + if (set_fintr) + fdc->fintr = 1; + fdc_log("fdc_int(%i): fdc->fintr = %i\n", set_fintr, fdc->fintr); } @@ -354,9 +329,8 @@ fdc_watchdog_poll(void *priv) fdc->watchdog_count--; if (fdc->watchdog_count) - fdc->watchdog_timer += 1000LL * TIMER_USEC; + timer_advance_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC); else { - fdc->watchdog_timer = 0LL; if (fdc->dor & 0x20) picint(1 << fdc->irq); } @@ -383,20 +357,6 @@ fdc_update_rates(fdc_t *fdc) } -void -fdc_update_is_nsc(fdc_t *fdc, int is_nsc) -{ - int old_is_nsc = fdc->flags & FDC_FLAG_NSC; - if (is_nsc) - fdc->flags |= FDC_FLAG_NSC; - else - fdc->flags &= ~FDC_FLAG_NSC; - if ((old_is_nsc ^ fdc->flags) & FDC_FLAG_NSC) - fdc->densel_force = fdc->densel_force ^ 3; - fdc_update_rates(fdc); -} - - void fdc_update_max_track(fdc_t *fdc, int max_track) { @@ -593,7 +553,6 @@ static void fdc_rate(fdc_t *fdc, int drive) { fdc_update_rate(fdc, drive); - fdd_set_rate(drive, fdc->drvrate[drive], fdc->rate); fdc_log("FDD %c: Setting rate: %i, %i, %i (%i, %i)\n", 0x41 + drive, fdc->drvrate[drive], fdc->rate, fdc_get_densel(fdc, drive), fdc->rwc[drive], fdc->densel_force); fdd_set_densel(fdc_get_densel(fdc, drive)); } @@ -613,8 +572,6 @@ void fdc_seek(fdc_t *fdc, int drive, int params) { fdd_seek(real_drive(fdc, drive), params); - fdc->time = 5000LL * (1 << TIMER_SHIFT); - fdc->stat |= (1 << fdc->drive); } @@ -636,9 +593,7 @@ fdc_bad_command(fdc_t *fdc) { fdc->stat = 0x10; fdc->interrupt = 0xfc; - timer_clock(); - fdc->time = 200LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 100 * TIMER_USEC); } @@ -655,8 +610,7 @@ fdc_io_command_phase1(fdc_t *fdc, int out) fdc->dtl = fdc->params[7]; fdc_implied_seek(fdc); fdc->rw_track = fdc->params[1]; - fdc->time = 0LL; - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 1); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); fdc->stat = out ? 0x90 : 0x50; if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) fdc->stat |= 0x20; @@ -677,7 +631,7 @@ fdc_sis(fdc_t *fdc) if (fdc->reset_stat) { drive_num = real_drive(fdc, 4 - fdc->reset_stat); - if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) { + if ((drive_num < FDD_NUM) && fdd_get_flags(drive_num)) { fdd_stop(drive_num); fdd_set_head(drive_num, 0); fdc->res[9] = 0xc0 | (4 - fdc->reset_stat) | (fdd_get_head(drive_num) ? 4 : 0); @@ -712,7 +666,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_log("Write FDC %04X %02X\n", addr, val); - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); switch (addr&7) { case 0: @@ -722,31 +676,26 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 2: /*DOR*/ if (fdc->flags & FDC_FLAG_PCJR) { if ((fdc->dor & 0x40) && !(val & 0x40)) { - fdc->watchdog_timer = 1000LL * TIMER_USEC; - fdc->watchdog_count = 1000LL; + timer_set_delay_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC); + fdc->watchdog_count = 1000; picintc(1 << fdc->irq); } if ((val & 0x80) && !(fdc->dor & 0x80)) { - timer_clock(); - fdc->time = 128LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); fdc->interrupt = -1; ui_sb_update_icon(SB_FLOPPY | 0, 0); fdc_ctrl_reset(fdc); fdd_changed[0] = 1; - fdd_changed[1] = 1; - fdd_changed[2] = 1; - fdd_changed[3] = 1; } if (!fdd_get_flags(0)) val &= 0xfe; - motoron[0] = val & 0x01; + fdd_set_motor_enable(0, val & 0x01); fdc->st0 &= ~0x07; fdc->st0 |= (fdd_get_head(0) ? 4 : 0); } else { if (!(val & 8) && (fdc->dor & 8)) { fdc->tc = 1; - fdc_int(fdc); + fdc_int(fdc, 1); } if (!(val&4)) { fdd_stop(real_drive(fdc, val & 3)); @@ -758,9 +707,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->pnum = fdc->ptot = 0; } if ((val&4) && !(fdc->dor&4)) { - timer_clock(); - fdc->time = 128LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); fdc->interrupt = -1; fdc->perp &= 0xfc; @@ -769,18 +716,16 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_ctrl_reset(fdc); } - timer_clock(); - timer_update_outstanding(); /* We can now simplify this since each motor now spins separately. */ for (i = 0; i < FDD_NUM; i++) { drive_num = real_drive(fdc, i); if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) val &= ~(0x10 << drive_num); else - motoron[i] = (val & (0x10 << drive_num)); + fdd_set_motor_enable(i, (val & (0x10 << drive_num))); } drive_num = real_drive(fdc, val & 0x03); - current_drive = real_drive(fdc, val & 0x03); + current_drive = drive_num; fdc->st0 &= ~0x07; fdc->st0 |= real_drive(fdc, drive_num); fdc->st0 |= (fdd_get_head(drive_num) ? 4 : 0); @@ -795,15 +740,11 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) return; case 4: if (val & 0x80) { - timer_clock(); - fdc->time = 128LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); fdc->interrupt = -1; fdc->perp &= 0xfc; fdc_ctrl_reset(fdc); } - /* if (fdc->flags & FDC_FLAG_PS1) - fdc->rate = val & 0x03; */ return; case 5: /*Command register*/ if ((fdc->stat & 0xf0) == 0xb0) { @@ -817,7 +758,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } break; } - if (fdc->pnum==fdc->ptot) { + if (fdc->pnum == fdc->ptot) { if ((fdc->stat & 0xf0) != 0x80) { /* If bit 4 of the MSR is set, or the MSR is 0x00, the fdc_t is NOT in the command phase, therefore @@ -978,15 +919,39 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->stat |= (1 << real_drive(fdc, fdc->drive)); } } - if (fdc->pnum==fdc->ptot) { + if (fdc->pnum == fdc->ptot) { fdc_log("Got all params %02X\n", fdc->command); fdc->interrupt = fdc->command & 0x1F; - timer_clock(); - fdc->time = 1024LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); fdc->reset_stat = 0; + /* Disable timer if enabled. */ + timer_disable(&fdc->timer); + /* Start timer if needed at this point. */ + switch (fdc->interrupt & 0x1f) { + case 0x02: /* Read a track */ + case 0x03: /* Specify */ + case 0x0a: /* Read sector ID */ + case 0x05: /* Write data */ + case 0x06: /* Read data */ + case 0x09: /* Write deleted data */ + case 0x0c: /* Read deleted data */ + case 0x11: /* Scan equal */ + case 0x12: /* Perpendicular mode */ + case 0x16: /* Verify */ + case 0x19: /* Scan low or equal */ + case 0x1d: /* Scan high or equal */ + /* Do nothing. */ + break; + case 0x07: /* Recalibrate */ + case 0x0f: /* Seek */ + timer_set_delay_u64(&fdc->timer, 1000 * TIMER_USEC); + break; + default: + timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); + break; + } + /* Process the firt phase of the command. */ switch (fdc->interrupt & 0x1F) { - case 2: /*Read a track*/ + case 0x02: /* Read a track */ fdc_io_command_phase1(fdc, 0); fdc->read_track_sector.id.c = fdc->params[1]; fdc->read_track_sector.id.h = fdc->params[2]; @@ -998,28 +963,17 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } fdd_readsector(real_drive(fdc, fdc->drive), SECTOR_FIRST, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); break; - case 3: /*Specify*/ - fdc->stat=0x80; + 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; - fdc->time = 0LL; break; - case 0x12: - fdc->stat=0x80; - if (fdc->params[0] & 0x80) - fdc->perp = fdc->params[0] & 0x3f; - else { - fdc->perp &= 0xfc; - fdc->perp |= (fdc->params[0] & 0x03); - } - fdc->time = 0LL; - return; - case 4: + case 0x04: /*Sense drive status*/ fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); break; - case 5: /*Write data*/ - case 9: /*Write deleted data*/ + case 0x05: /* Write data */ + case 0x09: /* Write deleted data */ fdc_io_command_phase1(fdc, 1); if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { fdc_noidam(fdc); @@ -1027,9 +981,9 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } fdd_writesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); break; - case 0x11: /*Scan equal*/ - case 0x19: /*Scan low or equal*/ - case 0x1D: /*Scan high or equal*/ + case 0x11: /* Scan equal */ + case 0x19: /* Scan low or equal */ + case 0x1d: /* Scan high or equal */ fdc_io_command_phase1(fdc, 1); if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { fdc_noidam(fdc); @@ -1037,11 +991,11 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } fdd_comparesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); break; - case 0x16: /*Verify*/ + case 0x16: /* Verify */ if (fdc->params[0] & 0x80) fdc->sc = fdc->params[7]; - case 6: /*Read data*/ - case 0xC: /*Read deleted data*/ + case 0x06: /* Read data */ + case 0x0c: /* Read deleted data */ fdc_io_command_phase1(fdc, 0); fdc_log("Reading sector (drive %i) (%i) (%i %i %i %i) (%i %i %i)\n", fdc->drive, fdc->params[0], fdc->params[1], fdc->params[2], fdc->params[3], fdc->params[4], fdc->params[5], fdc->params[6], fdc->params[7]); if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { @@ -1057,12 +1011,14 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdd_readsector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); break; - case 7: /*Recalibrate*/ - fdc->stat = (1 << real_drive(fdc, fdc->drive)) | 0x80; - fdc->st0 = fdc->drive & 0x03; + case 0x07: /* Recalibrate */ + fdc->rw_drive = fdc->params[0] & 3; + fdc->stat = (1 << real_drive(fdc, fdc->drive)); + if (!(fdc->flags & FDC_FLAG_PCJR)) + fdc->stat |= 0x80; + fdc->st0 = fdc->params[0] & 3; fdc->st0 |= fdd_get_head(real_drive(fdc, fdc->drive)) ? 0x04 : 0x00; fdc->st0 |= 0x80; - fdc->time = 0LL; drive_num = real_drive(fdc, fdc->drive); /* Three conditions under which the command should fail. */ if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num] || fdd_track0(drive_num)) { @@ -1072,19 +1028,33 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) else fdc->st0 = 0x20 | (fdc->params[0] & 3); fdc->pcn[fdc->params[0] & 3] = 0; - fdc->interrupt = -3; - timer_clock(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->fintr = 1; + fdc->interrupt = -4; + } else + fdc->interrupt = -3; break; } if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) fdc_seek(fdc, fdc->drive, -fdc->max_track); fdc_log("Recalibrating...\n"); - fdc->time = 5000LL * (1 << TIMER_SHIFT); - fdc->step = fdc->seek_dir = 1; + fdc->seek_dir = fdc->step = 1; break; - case 0x0d: /*Format*/ + case 0x0a: /* Read sector ID */ + fdc_rate(fdc, fdc->drive); + fdc->head = (fdc->params[0] & 4) ? 1 : 0; + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) { + fdd_readaddress(real_drive(fdc, fdc->drive), fdc->head, fdc->rate); + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat = 0x70; + else + fdc->stat = 0x50; + } + else + fdc_noidam(fdc); + break; + case 0x0d: /* Format */ fdc_rate(fdc, fdc->drive); fdc->head = (fdc->params[0] & 4) ? 1 : 0; fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); @@ -1096,14 +1066,16 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->pos = 0; fdc->stat = 0x10; break; - case 0xf: /*Seek*/ - fdc->stat = (1 << fdc->drive) | 0x80; + case 0x0f: /* Seek */ + fdc->rw_drive = fdc->params[0] & 3; + fdc->stat = (1 << fdc->drive); + if (!(fdc->flags & FDC_FLAG_PCJR)) + fdc->stat |= 0x80; fdc->head = (fdc->params[0] & 4) ? 1 : 0; - fdc->st0 = fdc->drive & 0x03; + fdc->st0 = fdc->params[0] & 0x03; fdc->st0 |= (fdc->params[0] & 4); fdc->st0 |= 0x80; fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); - fdc->time = 0LL; drive_num = real_drive(fdc, fdc->drive); /* Three conditions under which the command should fail. */ if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num]) { @@ -1117,9 +1089,6 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } else fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; fdc->interrupt = -3; - timer_clock(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); break; } if (fdc->command & 0x80) { @@ -1135,14 +1104,10 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_seek(fdc, fdc->drive, -fdc->params[1]); fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; } - fdc->time = 5000LL * (1 << TIMER_SHIFT); fdc->step = 1; } else { fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - timer_clock(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); break; } } else { @@ -1151,9 +1116,6 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_log("Failed seek\n"); fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - timer_clock(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); break; } if (fdc->params[1] > fdc->pcn[fdc->params[0] & 3]) @@ -1162,33 +1124,25 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->seek_dir = 1; fdc_seek(fdc, fdc->drive, fdc->params[1] - fdc->pcn[fdc->params[0] & 3]); fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; - fdc->time = 5000LL * (1 << TIMER_SHIFT); fdc->step = 1; - fdc_log("fdc->time = %i\n", fdc->time); } break; - case 10: /*Read sector ID*/ - fdc_rate(fdc, fdc->drive); - fdc->time = 0LL; - fdc->head = (fdc->params[0] & 4) ? 1 : 0; - fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); - if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) { - fdd_readaddress(real_drive(fdc, fdc->drive), fdc->head, fdc->rate); - if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) - fdc->stat = 0x70; - else - fdc->stat = 0x50; + case 0x12: /* Perpendicular mode */ + fdc->stat = 0x80; + if (fdc->params[0] & 0x80) + fdc->perp = fdc->params[0] & 0x3f; + else { + fdc->perp &= 0xfc; + fdc->perp |= (fdc->params[0] & 0x03); } - else - fdc_noidam(fdc); - break; + return; } } else fdc->stat = 0x90 | (fdc->stat & 0xf); } return; case 7: - if (!(fdc->flags & FDC_FLAG_AT)) + if (!(fdc->flags & FDC_FLAG_TOSHIBA) && !(fdc->flags & FDC_FLAG_AT)) return; fdc->rate = val & 0x03; if (fdc->flags & FDC_FLAG_PS1) @@ -1205,9 +1159,9 @@ fdc_read(uint16_t addr, void *priv) uint8_t ret; int drive; - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); - switch (addr&7) { + switch (addr & 7) { case 0: /* STA */ if (fdc->flags & FDC_FLAG_PS1) { drive = real_drive(fdc, fdc->dor & 3); @@ -1216,9 +1170,9 @@ fdc_read(uint16_t addr, void *priv) Bit 2: INDEX (best return always 0 as it goes by very fast) Bit 6: DRQ */ - if (writeprot[drive]) /* WRITEPROT */ - ret |= 0x01; if (fdc->seek_dir) /* nDIRECTION */ + ret |= 0x01; + if (writeprot[drive]) /* WRITEPROT */ ret |= 0x02; if (!fdd_get_head(drive)) /* nHDSEL */ ret |= 0x08; @@ -1239,18 +1193,28 @@ fdc_read(uint16_t addr, void *priv) if (!fdd_get_type(1)) ret |= 80; /* -Drive Select 1,0 */ - if (drive) - ret |= 0x20; - else - ret |= 0x40; + switch (drive) { + case 0: + ret |= 0x43; + break; + case 1: + ret |= 0x23; + break; + case 2: + ret |= 0x62; + break; + case 3: + ret |= 0x61; + break; + } } else { - if (is486) + if (is486 || !fdc->enable_3f1) return 0xff; - drive = real_drive(fdc, fdc->dor & 3); - if (!fdc->enable_3f1) - ret = 0xff; ret = 0x70; + + drive = real_drive(fdc, fdc->dor & 3); + if (drive) ret &= ~0x40; else @@ -1334,14 +1298,22 @@ fdc_read(uint16_t addr, void *priv) } else ret = 0x00; } else { - if (fdc->dor & (0x10 << drive)) - ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x80 : 0x00; - else + if (fdc->dor & (0x10 << drive)) { + if ((drive == 1) && (fdc->flags & FDC_FLAG_TOSHIBA)) + ret = 0x00; + else + ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x80 : 0x00; + } else ret = 0x00; if (fdc->flags & FDC_FLAG_DISKCHG_ACTLOW) /*PC2086/3086 seem to reverse this bit*/ ret ^= 0x80; - ret |= 0x01; + /* 0 = ????, 1 = Ext. FDD off, 2 = Ext. FDD = FDD A, 3 = Ext. FDD = FDD B */ + if (fdc->flags & FDC_FLAG_TOSHIBA) { + ret |= (3 << 5); + ret |= 0x01; + } else + ret |= 0x7F; } fdc->step = 0; @@ -1356,7 +1328,7 @@ fdc_read(uint16_t addr, void *priv) static void fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) { - fdc_int(fdc); + fdc_int(fdc, 1); if (!(fdc->flags & FDC_FLAG_PS1)) fdc->fintr = 0; fdc->stat = 0xD0; @@ -1395,7 +1367,7 @@ fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) fdc->res[9]=fdc->sector; fdc->res[10]=fdc->params[4]; fdc_log("Read/write finish (%02X %02X %02X %02X %02X %02X %02X)\n" , fdc->res[4], fdc->res[5], fdc->res[6], fdc->res[7], fdc->res[8], fdc->res[9], fdc->res[10]); - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 0); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; } @@ -1413,7 +1385,7 @@ fdc_poll_readwrite_finish(fdc_t *fdc, int compare) static void fdc_no_dma_end(fdc_t *fdc, int compare) { - fdc->time = 0LL; + timer_disable(&fdc->timer); fdc_poll_common_finish(fdc, compare, 0x80); } @@ -1426,28 +1398,28 @@ fdc_callback(void *priv) int compare = 0; int drive_num = 0; int old_sector = 0; - fdc->time = 0LL; fdc_log("fdc_callback(): %i\n", fdc->interrupt); switch (fdc->interrupt) { case -3: /*End of command with interrupt*/ - fdc_int(fdc); + case -4: /*Recalibrate/seek interrupt (PCjr only)*/ + fdc_int(fdc, fdc->interrupt & 1); fdc->stat = (fdc->stat & 0xf) | 0x80; return; case -2: /*End of command*/ fdc->stat = (fdc->stat & 0xf) | 0x80; return; case -1: /*Reset*/ - fdc_int(fdc); + fdc_int(fdc, 1); fdc->fintr = 0; memset(fdc->pcn, 0, 4 * sizeof(int)); fdc->reset_stat = 4; return; - case 1: /*Mode*/ + case 0x01: /* Mode */ fdc->stat=0x80; fdc->densel_force = (fdc->params[2] & 0xC0) >> 6; return; - case 2: /*Read track*/ - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 1); + case 0x02: /* Read track */ + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); fdc->eot[fdc->drive]--; fdc->read_track_sector.id.r++; if (!fdc->eot[fdc->drive] || fdc->tc) { @@ -1462,7 +1434,7 @@ fdc_callback(void *priv) } fdc->inread = 1; return; - case 4: /*Sense drive status*/ + case 0x04: /* Sense drive status */ fdc->res[10] = (fdc->params[0] & 7) | 0x20; if (fdd_is_double_sided(real_drive(fdc, fdc->drive))) fdc->res[10] |= 0x08; @@ -1476,16 +1448,15 @@ fdc_callback(void *priv) fdc->stat = (fdc->stat & 0xf) | 0xd0; fdc->paramstogo = 1; fdc->interrupt = 0; - fdc->time = 0LL; return; - case 5: /*Write data*/ - case 9: /*Write deleted data*/ - case 6: /*Read data*/ - case 0xC: /*Read deleted data*/ - case 0x11: /*Scan equal*/ - case 0x19: /*Scan low or equal*/ - case 0x1C: /*Verify*/ - case 0x1D: /*Scan high or equal*/ + case 0x05: /* Write data */ + case 0x09: /* Write deleted data */ + case 0x06: /* Read data */ + case 0x0c: /* Read deleted data */ + case 0x11: /* Scan equal */ + case 0x19: /* Scan low or equal */ + case 0x1c: /* Verify */ + case 0x1d: /* Scan high or equal */ if ((fdc->interrupt == 0x11) || (fdc->interrupt == 0x19) || (fdc->interrupt == 0x1D)) compare = 1; else @@ -1568,7 +1539,7 @@ fdc_callback(void *priv) } } else if (fdc->sector < fdc->params[5]) fdc->sector++; - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 1); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); switch (fdc->interrupt) { case 5: case 9: @@ -1599,30 +1570,30 @@ fdc_callback(void *priv) } fdc->inread = 1; return; - case 7: /*Recalibrate*/ + case 0x07: /* Recalibrate */ fdc->pcn[fdc->params[0] & 3] = 0; drive_num = real_drive(fdc, fdc->rw_drive); fdc->st0 = 0x20 | (fdc->params[0] & 3); if (!fdd_track0(drive_num)) fdc->st0 |= 0x50; - fdc->interrupt = -3; - timer_clock(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); - fdc->stat = 0x80 | (1 << fdc->drive); + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->fintr = 1; + fdc->interrupt = -4; + } else + fdc->interrupt = -3; + timer_set_delay_u64(&fdc->timer, 2048 * TIMER_USEC); + fdc->stat = 0x80 | (1 << fdc->rw_drive); return; case 0x0d: /*Format track*/ if (fdc->format_state == 1) { fdc->format_state = 2; - timer_clock(); - fdc->time = 128LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); } else if (fdc->format_state == 2) { fdd_format(real_drive(fdc, fdc->drive), fdc->head, fdc->rate, fdc->params[4]); fdc->format_state = 3; } else { fdc->interrupt = -2; - fdc_int(fdc); + fdc_int(fdc, 1); if (!(fdc->flags & FDC_FLAG_PS1)) fdc->fintr = 0; fdc->stat = 0xD0; @@ -1651,17 +1622,18 @@ fdc_callback(void *priv) fdc->res[10] = fdc->pretrk; fdc->paramstogo = 10; fdc->interrupt = 0; - fdc->time = 0LL; return; case 0x0f: /*Seek*/ - drive_num = real_drive(fdc, fdc->rw_drive); fdc->st0 = 0x20 | (fdc->params[0] & 7); - fdc->interrupt = -3; - /* timer_clock(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); */ - fdc->stat = 0x80 | (1 << fdc->drive); - fdc_callback(fdc); + fdc->stat = 0x80 | (1 << fdc->rw_drive); + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->fintr = 1; + fdc->interrupt = -4; + timer_set_delay_u64(&fdc->timer, 1024 * TIMER_USEC); + } else { + fdc->interrupt = -3; + fdc_callback(fdc); + } return; case 0x10: /*Version*/ case 0x18: /*NSC*/ @@ -1669,7 +1641,6 @@ fdc_callback(void *priv) fdc->res[10] = (fdc->interrupt & 0x08) ? 0x73 : 0x90; fdc->paramstogo = 1; fdc->interrupt = 0; - fdc->time = 0LL; return; case 0x13: /*Configure*/ fdc->config = fdc->params[1]; @@ -1677,7 +1648,6 @@ fdc_callback(void *priv) fdc->fifo = (fdc->params[1] & 0x20) ? 0 : 1; fdc->tfifo = (fdc->params[1] & 0xF); fdc->stat = 0x80; - fdc->time = 0LL; return; case 0x14: /*Unlock*/ case 0x94: /*Lock*/ @@ -1686,7 +1656,6 @@ fdc_callback(void *priv) fdc->res[10] = (fdc->interrupt & 0x80) ? 0x10 : 0x00; fdc->paramstogo = 1; fdc->interrupt = 0; - fdc->time = 0LL; return; case 0xfc: /*Invalid*/ fdc->dat = fdc->st0 = 0x80; @@ -1694,7 +1663,6 @@ fdc_callback(void *priv) fdc->res[10] = fdc->st0; fdc->paramstogo = 1; fdc->interrupt = 0; - fdc->time = 0LL; return; } } @@ -1703,9 +1671,9 @@ fdc_callback(void *priv) void fdc_error(fdc_t *fdc, int st5, int st6) { - fdc->time = 0LL; + timer_disable(&fdc->timer); - fdc_int(fdc); + fdc_int(fdc, 1); if (!(fdc->flags & FDC_FLAG_PS1)) fdc->fintr = 0; fdc->stat = 0xD0; @@ -1737,7 +1705,7 @@ fdc_error(fdc_t *fdc, int st5, int st6) fdc->res[10]=0; break; } - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 0); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; } @@ -1966,7 +1934,7 @@ int fdc_getdata(fdc_t *fdc, int last) void fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2) { - fdc_int(fdc); + fdc_int(fdc, 1); fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->drive; fdc->res[5] = 0; @@ -1975,7 +1943,7 @@ fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, uint8_t sector, uint8_t si fdc->res[8] = side; fdc->res[9] = sector; fdc->res[10] = size; - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 0); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; } @@ -2030,16 +1998,22 @@ fdc_set_base(fdc_t *fdc, int base) { int super_io = (fdc->flags & FDC_FLAG_SUPERIO); - if (fdc->flags & FDC_FLAG_AT) { + if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_sethandler(base + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { - io_sethandler(base + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); - io_sethandler(base + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); - io_sethandler(base + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + if (fdc->flags & FDC_FLAG_PCJR) + io_sethandler(base, 0x0010, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + else { + io_sethandler(base + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_sethandler(base + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_sethandler(base + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + if (fdc->flags & FDC_FLAG_TOSHIBA) + io_sethandler(base + 0x0007, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } } fdc->base_address = base; - fdc_log("fdc_t Base address set%s (%04X)\n", super_io ? " for Super I/O" : "", fdc->base_address); + fdc_log("FDC Base address set%s (%04X)\n", super_io ? " for Super I/O" : "", fdc->base_address); } @@ -2048,14 +2022,20 @@ fdc_remove(fdc_t *fdc) { int super_io = (fdc->flags & FDC_FLAG_SUPERIO); - fdc_log("fdc_t Removed (%04X)\n", fdc->base_address); - if (fdc->flags & FDC_FLAG_AT) { + fdc_log("FDC Removed (%04X)\n", fdc->base_address); + if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_removehandler(fdc->base_address + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { - io_removehandler(fdc->base_address + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); - io_removehandler(fdc->base_address + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); - io_removehandler(fdc->base_address + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + if (fdc->flags & FDC_FLAG_PCJR) + io_removehandler(fdc->base_address, 0x0010, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + else { + io_removehandler(fdc->base_address + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + if (fdc->flags & FDC_FLAG_TOSHIBA) + io_removehandler(fdc->base_address + 0x0007, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } } } @@ -2072,13 +2052,15 @@ fdc_reset(void *priv) fdc->enable_3f1 = 1; - fdc_update_is_nsc(fdc, 0); fdc_update_enh_mode(fdc, 0); if (fdc->flags & FDC_FLAG_PS1) fdc_update_densel_polarity(fdc, 0); else fdc_update_densel_polarity(fdc, 1); - fdc_update_densel_force(fdc, 0); + if (fdc->flags & FDC_FLAG_NSC) + fdc_update_densel_force(fdc, 3); + else + fdc_update_densel_force(fdc, 0); fdc_update_rwc(fdc, 0, default_rwc); fdc_update_rwc(fdc, 1, default_rwc); fdc_update_rwc(fdc, 2, default_rwc); @@ -2088,6 +2070,7 @@ fdc_reset(void *priv) fdc_update_drvrate(fdc, 2, 0); fdc_update_drvrate(fdc, 3, 0); fdc_update_drv2en(fdc, 1); + fdc_update_rates(fdc); fdc->fifo = 0; fdc->tfifo = 1; @@ -2127,11 +2110,8 @@ fdc_close(void *priv) fdc_reset(fdc); /* Stop timers. */ - fdc->watchdog_timer = 0; fdc->watchdog_count = 0; - fdc->time = 0; - free(fdc); } @@ -2148,19 +2128,20 @@ fdc_init(const device_t *info) fdc->irq = 6; if (fdc->flags & FDC_FLAG_PCJR) - timer_add(fdc_watchdog_poll, &fdc->watchdog_timer, &fdc->watchdog_timer, fdc); + timer_add(&fdc->watchdog_timer, fdc_watchdog_poll, fdc, 0); else fdc->dma_ch = 2; fdc_log("FDC added: %04X (flags: %08X)\n", fdc->base_address, fdc->flags); - timer_add(fdc_callback, &fdc->time, &fdc->time, fdc); + timer_add(&fdc->timer, fdc_callback, fdc, 0); d86f_set_fdc(fdc); fdi_set_fdc(fdc); fdd_set_fdc(fdc); imd_set_fdc(fdc); img_set_fdc(fdc); + mfm_set_fdc(fdc); fdc_reset(fdc); @@ -2185,6 +2166,27 @@ const device_t fdc_xt_device = { NULL, NULL, NULL }; +const device_t fdc_xt_t1x00_device = { + "PC/XT Floppy Drive Controller (Toshiba)", + 0, + FDC_FLAG_TOSHIBA, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + +const device_t fdc_xt_amstrad_device = { + "PC/XT Floppy Drive Controller (Amstrad)", + 0, + FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AMSTRAD, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + + const device_t fdc_pcjr_device = { "PCjr Floppy Drive Controller", 0, diff --git a/src/floppy/fdc.h b/src/floppy/fdc.h index dbc3fdd0a..c6c3a90bf 100644 --- a/src/floppy/fdc.h +++ b/src/floppy/fdc.h @@ -1,41 +1,23 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * Version: @(#)fdc.h 1.0.4 2018/04/12 + * Version: @(#)fdc.h 1.0.8 2019/10/20 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #ifndef EMU_FDC_H # define EMU_FDC_H @@ -49,6 +31,8 @@ #define FDC_FLAG_START_RWC_1 0x20 /* W83877F, W83977F */ #define FDC_FLAG_MORE_TRACKS 0x40 /* W83877F, W83977F, PC87306, PC87309 */ #define FDC_FLAG_NSC 0x80 /* PC87306, PC87309 */ +#define FDC_FLAG_TOSHIBA 0x100 /* T1000, T1200 */ +#define FDC_FLAG_AMSTRAD 0x200 /* Non-AT Amstrad machines */ typedef struct { @@ -98,8 +82,9 @@ typedef struct { sector_id_t read_track_sector; - int64_t time; - int64_t watchdog_timer, watchdog_count; + uint64_t watchdog_count; + + pc_timer_t timer, watchdog_timer; } fdc_t; @@ -179,10 +164,12 @@ extern void fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, extern uint8_t fdc_read(uint16_t addr, void *priv); extern void fdc_reset(void *priv); -extern uint8_t fdc_ps1_525(void); +extern uint8_t fdc_get_current_drive(void); #ifdef EMU_DEVICE_H extern const device_t fdc_xt_device; +extern const device_t fdc_xt_t1x00_device; +extern const device_t fdc_xt_amstrad_device; extern const device_t fdc_pcjr_device; extern const device_t fdc_at_device; extern const device_t fdc_at_actlow_device; diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 0508d5343..92bffd9be 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -1,40 +1,22 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the floppy drive emulation. * - * Version: @(#)fdd.c 1.0.9 2018/05/13 + * Version: @(#)fdd.c 1.0.15 2019/10/20 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #include #include @@ -43,10 +25,6 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../machine/machine.h" -#include "../mem.h" -#include "../rom.h" -#include "../config.h" #include "../timer.h" #include "../plat.h" #include "../ui.h" @@ -56,99 +34,11 @@ #include "fdd_imd.h" #include "fdd_img.h" #include "fdd_json.h" +#include "fdd_mfm.h" #include "fdd_td0.h" #include "fdc.h" -extern int driveempty[4]; - -wchar_t floppyfns[4][512]; - -int64_t fdd_poll_time[FDD_NUM] = { 16LL, 16LL, 16LL, 16LL }; - -int fdd_cur_track[FDD_NUM]; -int writeprot[FDD_NUM], fwriteprot[FDD_NUM]; - -DRIVE drives[FDD_NUM]; -int drive_type[FDD_NUM]; - -int curdrive = 0; - -int defaultwriteprot = 0; - -int fdc_ready; - -int drive_empty[FDD_NUM] = {1, 1, 1, 1}; -int fdd_changed[FDD_NUM]; - -int motorspin; -int64_t motoron[FDD_NUM]; - -int fdc_indexcount = 52; - -fdc_t *fdd_fdc; - -d86f_handler_t d86f_handler[FDD_NUM]; - -static const struct -{ - wchar_t *ext; - void (*load)(int drive, wchar_t *fn); - void (*close)(int drive); - int size; -} loaders[]= -{ - {L"001", img_load, img_close, -1}, - {L"002", img_load, img_close, -1}, - {L"003", img_load, img_close, -1}, - {L"004", img_load, img_close, -1}, - {L"005", img_load, img_close, -1}, - {L"006", img_load, img_close, -1}, - {L"007", img_load, img_close, -1}, - {L"008", img_load, img_close, -1}, - {L"009", img_load, img_close, -1}, - {L"010", img_load, img_close, -1}, - {L"12", img_load, img_close, -1}, - {L"144", img_load, img_close, -1}, - {L"360", img_load, img_close, -1}, - {L"720", img_load, img_close, -1}, - {L"86F", d86f_load, d86f_close, -1}, - {L"BIN", img_load, img_close, -1}, - {L"CQ", img_load, img_close, -1}, - {L"CQM", img_load, img_close, -1}, - {L"DDI", img_load, img_close, -1}, - {L"DSK", img_load, img_close, -1}, - {L"FDI", fdi_load, fdi_close, -1}, - {L"FDF", img_load, img_close, -1}, - {L"FLP", img_load, img_close, -1}, - {L"HDM", img_load, img_close, -1}, - {L"IMA", img_load, img_close, -1}, - {L"IMD", imd_load, imd_close, -1}, - {L"IMG", img_load, img_close, -1}, - {L"JSON", json_load, json_close, -1}, - {L"TD0", td0_load, td0_close, -1}, - {L"VFD", img_load, img_close, -1}, - {L"XDF", img_load, img_close, -1}, - {0,0,0} -}; - -static int driveloaders[4]; - - -typedef struct { - int type; - int track; - int densel; - int head; - int turbo; - int check_bpb; -} fdd_t; - - -fdd_t fdd[FDD_NUM]; -int ui_writeprot[FDD_NUM] = {0, 0, 0, 0}; - - /* Flags: Bit 0: 300 rpm supported; Bit 1: 360 rpm supported; @@ -162,8 +52,8 @@ int ui_writeprot[FDD_NUM] = {0, 0, 0, 0}; Bit 9: ignore DENSEL; Bit 10: drive is a PS/2 drive; */ -#define FLAG_RPM_300 1 -#define FLAG_RPM_360 2 +#define FLAG_RPM_300 1 +#define FLAG_RPM_360 2 #define FLAG_525 4 #define FLAG_DS 8 #define FLAG_HOLE0 16 @@ -174,70 +64,146 @@ int ui_writeprot[FDD_NUM] = {0, 0, 0, 0}; #define FLAG_IGNORE_DENSEL 512 #define FLAG_PS2 1024 + +typedef struct { + int type; + int track; + int densel; + int head; + int turbo; + int check_bpb; +} fdd_t; + + +fdd_t fdd[FDD_NUM]; + +wchar_t floppyfns[FDD_NUM][512]; + +pc_timer_t fdd_poll_time[FDD_NUM]; + +static int fdd_notfound = 0, + driveloaders[FDD_NUM]; + +int writeprot[FDD_NUM], fwriteprot[FDD_NUM], + fdd_changed[FDD_NUM], ui_writeprot[FDD_NUM] = {0, 0, 0, 0}, + drive_empty[FDD_NUM] = {1, 1, 1, 1}; + +DRIVE drives[FDD_NUM]; + +uint64_t motoron[FDD_NUM]; + +fdc_t *fdd_fdc; + +d86f_handler_t d86f_handler[FDD_NUM]; + + static const struct { - int max_track; - int flags; - char name[64]; - char internal_name[24]; + wchar_t *ext; + void (*load)(int drive, wchar_t *fn); + void (*close)(int drive); + int size; +} loaders[]= +{ + {L"001", img_load, img_close, -1}, + {L"002", img_load, img_close, -1}, + {L"003", img_load, img_close, -1}, + {L"004", img_load, img_close, -1}, + {L"005", img_load, img_close, -1}, + {L"006", img_load, img_close, -1}, + {L"007", img_load, img_close, -1}, + {L"008", img_load, img_close, -1}, + {L"009", img_load, img_close, -1}, + {L"010", img_load, img_close, -1}, + {L"12", img_load, img_close, -1}, + {L"144", img_load, img_close, -1}, + {L"360", img_load, img_close, -1}, + {L"720", img_load, img_close, -1}, + {L"86F", d86f_load, d86f_close, -1}, + {L"BIN", img_load, img_close, -1}, + {L"CQ", img_load, img_close, -1}, + {L"CQM", img_load, img_close, -1}, + {L"DDI", img_load, img_close, -1}, + {L"DSK", img_load, img_close, -1}, + {L"FDI", fdi_load, fdi_close, -1}, + {L"FDF", img_load, img_close, -1}, + {L"FLP", img_load, img_close, -1}, + {L"HDM", img_load, img_close, -1}, + {L"IMA", img_load, img_close, -1}, + {L"IMD", imd_load, imd_close, -1}, + {L"IMG", img_load, img_close, -1}, + {L"JSON", json_load, json_close, -1}, + {L"MFM", mfm_load, mfm_close, -1}, + {L"TD0", td0_load, td0_close, -1}, + {L"VFD", img_load, img_close, -1}, + {L"XDF", img_load, img_close, -1}, + {0, 0, 0, 0} +}; + + +static const struct +{ + int max_track; + int flags; + const char *name; + const char *internal_name; } drive_types[] = { - { /*None*/ - 0, 0, "None", "none" - }, - { /*5.25" 1DD*/ - 43, FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0, "5.25\" 180k", "525_1dd" - }, - { /*5.25" DD*/ - 43, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0, "5.25\" 360k", "525_2dd" - }, - { /*5.25" QD*/ - 86, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "5.25\" 720k", "525_2qd" - }, - { /*5.25" HD PS/2*/ - 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "5.25\" 1.2M PS/2", "525_2hd_ps2" - }, - { /*5.25" HD*/ - 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M", "525_2hd" - }, - { /*5.25" HD Dual RPM*/ - 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M 300/360 RPM", "525_2hd_dualrpm" - }, - { /*3.5" 1DD*/ - 86, FLAG_RPM_300 | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 360k", "35_1dd" - }, - { /*3.5" DD*/ - 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 720k", "35_2dd" - }, - { /*3.5" HD PS/2*/ - 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "3.5\" 1.44M PS/2", "35_2hd_ps2" - }, - { /*3.5" HD*/ - 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M", "35_2hd" - }, - { /*3.5" HD PC-98*/ - 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL, "3.5\" 1.25M PC-98", "35_2hd_nec" - }, - { /*3.5" HD 3-Mode*/ - 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M 300/360 RPM", "35_2hd_3mode" - }, - { /*3.5" ED*/ - 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M", "35_2ed" - }, - { /*End of list*/ - -1, -1, "", "" - } + { /*None*/ + 0, 0, "None", "none" + }, + { /*5.25" 1DD*/ + 43, FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0, "5.25\" 180k", "525_1dd" + }, + { /*5.25" DD*/ + 43, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0, "5.25\" 360k", "525_2dd" + }, + { /*5.25" QD*/ + 86, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "5.25\" 720k", "525_2qd" + }, + { /*5.25" HD PS/2*/ + 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "5.25\" 1.2M PS/2", "525_2hd_ps2" + }, + { /*5.25" HD*/ + 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M", "525_2hd" + }, + { /*5.25" HD Dual RPM*/ + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M 300/360 RPM", "525_2hd_dualrpm" + }, + { /*3.5" 1DD*/ + 86, FLAG_RPM_300 | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 360k", "35_1dd" + }, + { /*3.5" DD*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 720k", "35_2dd" + }, + { /*3.5" HD PS/2*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "3.5\" 1.44M PS/2", "35_2hd_ps2" + }, + { /*3.5" HD*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M", "35_2hd" + }, + { /*3.5" HD PC-98*/ + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL, "3.5\" 1.25M PC-98", "35_2hd_nec" + }, + { /*3.5" HD 3-Mode*/ + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M 300/360 RPM", "35_2hd_3mode" + }, + { /*3.5" ED*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M", "35_2ed" + }, + { /*End of list*/ + -1, -1, "", "" + } }; + #ifdef ENABLE_FDD_LOG int fdd_do_log = ENABLE_FDD_LOG; -#endif static void fdd_log(const char *fmt, ...) { -#ifdef ENABLE_FDD_LOG va_list ap; if (fdd_do_log) @@ -246,503 +212,500 @@ fdd_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define fdd_log(fmt, ...) #endif -} -char *fdd_getname(int type) +char * +fdd_getname(int type) { - return (char *)drive_types[type].name; + return (char *)drive_types[type].name; } -char *fdd_get_internal_name(int type) + +char * +fdd_get_internal_name(int type) { - return (char *)drive_types[type].internal_name; + return (char *)drive_types[type].internal_name; } -int fdd_get_from_internal_name(char *s) + +int +fdd_get_from_internal_name(char *s) { - int c = 0; - - while (strlen(drive_types[c].internal_name)) - { - if (!strcmp((char *)drive_types[c].internal_name, s)) - return c; - c++; - } - - return 0; + int c = 0; + + while (strlen(drive_types[c].internal_name)) { + if (!strcmp((char *)drive_types[c].internal_name, s)) + return c; + c++; + } + + return 0; } + /* This is needed for the dump as 86F feature. */ -void fdd_do_seek(int drive, int track) +void +fdd_do_seek(int drive, int track) { - if (drives[drive].seek) { - drives[drive].seek(drive, track); - } + if (drives[drive].seek) + drives[drive].seek(drive, track); } -void fdd_forced_seek(int drive, int track_diff) + +void +fdd_forced_seek(int drive, int track_diff) { - fdd[drive].track += track_diff; - - if (fdd[drive].track < 0) - fdd[drive].track = 0; + fdd[drive].track += track_diff; - if (fdd[drive].track > drive_types[fdd[drive].type].max_track) - fdd[drive].track = drive_types[fdd[drive].type].max_track; + if (fdd[drive].track < 0) + fdd[drive].track = 0; - fdd_do_seek(drive, fdd[drive].track); + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; + + fdd_do_seek(drive, fdd[drive].track); } -void fdd_seek(int drive, int track_diff) + +void +fdd_seek(int drive, int track_diff) { - if (!track_diff) - return; + if (!track_diff) + return; - fdd[drive].track += track_diff; + fdd[drive].track += track_diff; - if (fdd[drive].track < 0) - fdd[drive].track = 0; + if (fdd[drive].track < 0) + fdd[drive].track = 0; - if (fdd[drive].track > drive_types[fdd[drive].type].max_track) - fdd[drive].track = drive_types[fdd[drive].type].max_track; + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; - fdd_changed[drive] = 0; + fdd_changed[drive] = 0; - fdd_do_seek(drive, fdd[drive].track); + fdd_do_seek(drive, fdd[drive].track); } -int fdd_track0(int drive) -{ - /* If drive is disabled, TRK0 never gets set. */ - if (!drive_types[fdd[drive].type].max_track) return 0; - return !fdd[drive].track; +int +fdd_track0(int drive) +{ + /* If drive is disabled, TRK0 never gets set. */ + if (!drive_types[fdd[drive].type].max_track) return 0; + + return !fdd[drive].track; } -int fdd_current_track(int drive) + +int +fdd_current_track(int drive) { - return fdd[drive].track; + return fdd[drive].track; } -void fdd_set_densel(int densel) + +void +fdd_set_densel(int densel) { - int i = 0; + int i = 0; - for (i = 0; i < 4; i++) - { - if (drive_types[fdd[i].type].flags & FLAG_INVERT_DENSEL) - { - fdd[i].densel = densel ^ 1; - } - else - { - fdd[i].densel = densel; - } - } -} - -int fdd_getrpm(int drive) -{ - int hole = fdd_hole(drive); - - int densel = 0; - - densel = fdd[drive].densel; - - if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) - { - densel ^= 1; - } - - if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) return 300; - if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) return 360; - - if (drive_types[fdd[drive].type].flags & FLAG_525) - { - return densel ? 360 : 300; - } + for (i = 0; i < 4; i++) { + if (drive_types[fdd[i].type].flags & FLAG_INVERT_DENSEL) + fdd[i].densel = densel ^ 1; else - { - /* fdd_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */ - if (hole == 1) - { - return densel ? 300 : 360; - } - else - { - return 300; - } - } + fdd[i].densel = densel; + } } -int fdd_can_read_medium(int drive) + +int +fdd_getrpm(int drive) { - int hole = fdd_hole(drive); + int densel = 0; + int hole; - hole = 1 << (hole + 4); + hole = fdd_hole(drive); + densel = fdd[drive].densel; - return (drive_types[fdd[drive].type].flags & hole) ? 1 : 0; -} + if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) + densel ^= 1; -int fdd_doublestep_40(int drive) -{ - return (drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP) ? 1 : 0; -} + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) + return 300; + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) + return 360; -void fdd_set_type(int drive, int type) -{ - int old_type = fdd[drive].type; - fdd[drive].type = type; - if ((drive_types[old_type].flags ^ drive_types[type].flags) & FLAG_INVERT_DENSEL) - { - fdd[drive].densel ^= 1; - } -} - -int fdd_get_type(int drive) -{ - return fdd[drive].type; -} - -int fdd_get_flags(int drive) -{ - return drive_types[fdd[drive].type].flags; -} - -int fdd_is_525(int drive) -{ - return drive_types[fdd[drive].type].flags & FLAG_525; -} - -int fdd_is_dd(int drive) -{ - return (drive_types[fdd[drive].type].flags & 0x70) == 0x10; -} - -int fdd_is_ed(int drive) -{ - return drive_types[fdd[drive].type].flags & FLAG_HOLE2; -} - -int fdd_is_double_sided(int drive) -{ - return drive_types[fdd[drive].type].flags & FLAG_DS; -} - -void fdd_set_head(int drive, int head) -{ - if (head && !fdd_is_double_sided(drive)) - fdd[drive].head = 0; + if (drive_types[fdd[drive].type].flags & FLAG_525) + return densel ? 360 : 300; + else { + /* fdd_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */ + if (hole == 1) + return densel ? 300 : 360; else - fdd[drive].head = head; + return 300; + } } -int fdd_get_head(int drive) + +int +fdd_can_read_medium(int drive) { - if (!fdd_is_double_sided(drive)) - return 0; - return fdd[drive].head; + int hole = fdd_hole(drive); + + hole = 1 << (hole + 4); + + return !!(drive_types[fdd[drive].type].flags & hole); } -void fdd_set_turbo(int drive, int turbo) + +int +fdd_doublestep_40(int drive) { - fdd[drive].turbo = turbo; + return !!(drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP); } -int fdd_get_turbo(int drive) + +void +fdd_set_type(int drive, int type) { - return fdd[drive].turbo; + int old_type = fdd[drive].type; + fdd[drive].type = type; + if ((drive_types[old_type].flags ^ drive_types[type].flags) & FLAG_INVERT_DENSEL) + fdd[drive].densel ^= 1; } + +int +fdd_get_type(int drive) +{ + return fdd[drive].type; +} + + +int +fdd_get_flags(int drive) +{ + return drive_types[fdd[drive].type].flags; +} + + +int +fdd_is_525(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_525; +} + + +int +fdd_is_dd(int drive) +{ + return (drive_types[fdd[drive].type].flags & 0x70) == 0x10; +} + + +int +fdd_is_ed(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_HOLE2; +} + + +int +fdd_is_double_sided(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_DS; +} + + +void +fdd_set_head(int drive, int head) +{ + if (head && !fdd_is_double_sided(drive)) + fdd[drive].head = 0; + else + fdd[drive].head = head; +} + + +int +fdd_get_head(int drive) +{ + if (!fdd_is_double_sided(drive)) + return 0; + return fdd[drive].head; +} + + +void +fdd_set_turbo(int drive, int turbo) +{ + fdd[drive].turbo = turbo; +} + + +int +fdd_get_turbo(int drive) +{ + return fdd[drive].turbo; +} + + void fdd_set_check_bpb(int drive, int check_bpb) { - fdd[drive].check_bpb = check_bpb; + fdd[drive].check_bpb = check_bpb; } -int fdd_get_check_bpb(int drive) + +int +fdd_get_check_bpb(int drive) { - return fdd[drive].check_bpb; + return fdd[drive].check_bpb; } -int fdd_get_densel(int drive) + +int +fdd_get_densel(int drive) { - if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) - { - return fdd[drive].densel ^ 1; + return fdd[drive].densel; +} + + +void +fdd_load(int drive, wchar_t *fn) +{ + int c = 0, size; + wchar_t *p; + FILE *f; + + fdd_log("FDD: loading drive %d with '%ls'\n", drive, fn); + + if (!fn) + return; + p = plat_get_extension(fn); + if (!p) + return; + f = plat_fopen(fn, L"rb"); + if (!f) + return; + fseek(f, -1, SEEK_END); + size = ftell(f) + 1; + fclose(f); + while (loaders[c].ext) { + if (!wcscasecmp(p, (wchar_t *) loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) { + driveloaders[drive] = c; + memcpy(floppyfns[drive], fn, (wcslen(fn) << 1) + 2); + d86f_setup(drive); + loaders[c].load(drive, floppyfns[drive]); + drive_empty[drive] = 0; + fdd_forced_seek(drive, 0); + fdd_changed[drive] = 1; + return; } - else - { - return fdd[drive].densel; - } -} - -void fdd_load(int drive, wchar_t *fn) -{ - int c = 0, size; - wchar_t *p; - FILE *f; - - fdd_log("FDD: loading drive %d with '%ls'\n", drive, fn); - - if (!fn) return; - p = plat_get_extension(fn); - if (!p) return; - f = plat_fopen(fn, L"rb"); - if (!f) return; - fseek(f, -1, SEEK_END); - size = ftell(f) + 1; - fclose(f); - while (loaders[c].ext) - { - if (!wcscasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) - { - driveloaders[drive] = c; - memcpy(floppyfns[drive], fn, (wcslen(fn) << 1) + 2); - d86f_setup(drive); - loaders[c].load(drive, floppyfns[drive]); - drive_empty[drive] = 0; - fdd_forced_seek(drive, 0); - fdd_changed[drive] = 1; - return; - } - c++; - } - fdd_log("FDD: could not load '%ls' %s\n",fn,p); - drive_empty[drive] = 1; - fdd_set_head(drive, 0); - memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); - ui_sb_update_icon_state(drive, 1); -} - -void fdd_close(int drive) -{ - fdd_log("FDD: closing drive %d\n", drive); - - if (loaders[driveloaders[drive]].close) loaders[driveloaders[drive]].close(drive); - drive_empty[drive] = 1; - fdd_set_head(drive, 0); - floppyfns[drive][0] = 0; - drives[drive].hole = NULL; - drives[drive].poll = NULL; - drives[drive].seek = NULL; - drives[drive].readsector = NULL; - drives[drive].writesector = NULL; - drives[drive].comparesector = NULL; - drives[drive].readaddress = NULL; - drives[drive].format = NULL; - drives[drive].byteperiod = NULL; - drives[drive].stop = NULL; - d86f_destroy(drive); - ui_sb_update_icon_state(drive, 1); -} - -int fdd_notfound = 0; -static int fdd_period = 32; - -int fdd_hole(int drive) -{ - if (drives[drive].hole) - { - return drives[drive].hole(drive); - } - else - { - return 0; - } -} - -double fdd_byteperiod(int drive) -{ - if (drives[drive].byteperiod) - { - return drives[drive].byteperiod(drive); - } - else - { - return 32.0; - } -} - -double fdd_real_period(int drive) -{ - double ddbp; - double dusec; - - ddbp = fdd_byteperiod(drive); - - dusec = (double) TIMER_USEC; - - /* This is a giant hack but until the timings become even more correct, this is needed to make floppies work right on that BIOS. */ - if (fdd_get_turbo(drive)) - { - return (32.0 * dusec); - } - - return (ddbp * dusec); -} - -void fdd_poll(int drive) -{ - if (drive >= FDD_NUM) - { - fatal("Attempting to poll floppy drive %i that is not supposed to be there\n", drive); - } - - fdd_poll_time[drive] += (int64_t) fdd_real_period(drive); - - if (drives[drive].poll) - drives[drive].poll(drive); - - if (fdd_notfound) - { - fdd_notfound--; - if (!fdd_notfound) - fdc_noidam(fdd_fdc); - } -} - -void fdd_poll_0(void *priv) -{ - fdd_poll(0); -} - -void fdd_poll_1(void *priv) -{ - fdd_poll(1); -} - -void fdd_poll_2(void *priv) -{ - fdd_poll(2); -} - -void fdd_poll_3(void *priv) -{ - fdd_poll(3); -} - -int fdd_get_bitcell_period(int rate) -{ - int bit_rate = 250; - - switch (rate) - { - case 0: /*High density*/ - bit_rate = 500; - break; - case 1: /*Double density (360 rpm)*/ - bit_rate = 300; - break; - case 2: /*Double density*/ - bit_rate = 250; - break; - case 3: /*Extended density*/ - bit_rate = 1000; - break; - } - - return 1000000 / bit_rate*2; /*Bitcell period in ns*/ + c++; + } + fdd_log("FDD: could not load '%ls' %s\n",fn,p); + drive_empty[drive] = 1; + fdd_set_head(drive, 0); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + ui_sb_update_icon_state(drive, 1); } -void fdd_set_rate(int drive, int drvden, int rate) +void +fdd_close(int drive) { - switch (rate) - { - case 0: /*High density*/ - fdd_period = 16; - break; - case 1: - switch(drvden) - { - case 0: /*Double density (360 rpm)*/ - fdd_period = 26; - break; - case 1: /*High density (360 rpm)*/ - fdd_period = 16; - break; - case 2: - fdd_period = 4; - break; - } - case 2: /*Double density*/ - fdd_period = 32; - break; - case 3: /*Extended density*/ - fdd_period = 8; - break; - } + fdd_log("FDD: closing drive %d\n", drive); + + d86f_stop(drive); /* Call this first of all to make sure the 86F poll is back to idle state. */ + if (loaders[driveloaders[drive]].close) + loaders[driveloaders[drive]].close(drive); + drive_empty[drive] = 1; + fdd_set_head(drive, 0); + floppyfns[drive][0] = 0; + drives[drive].hole = NULL; + drives[drive].poll = NULL; + drives[drive].seek = NULL; + drives[drive].readsector = NULL; + drives[drive].writesector = NULL; + drives[drive].comparesector = NULL; + drives[drive].readaddress = NULL; + drives[drive].format = NULL; + drives[drive].byteperiod = NULL; + drives[drive].stop = NULL; + d86f_destroy(drive); + ui_sb_update_icon_state(drive, 1); } -void fdd_reset() + +int +fdd_hole(int drive) { - curdrive = 0; - fdd_period = 32; - timer_add(fdd_poll_0, &(fdd_poll_time[0]), &(motoron[0]), NULL); - timer_add(fdd_poll_1, &(fdd_poll_time[1]), &(motoron[1]), NULL); - timer_add(fdd_poll_2, &(fdd_poll_time[2]), &(motoron[2]), NULL); - timer_add(fdd_poll_3, &(fdd_poll_time[3]), &(motoron[3]), NULL); + if (drives[drive].hole) + return drives[drive].hole(drive); + else + return 0; } -int oldtrack[FDD_NUM] = {0, 0, 0, 0}; -void fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size) +uint64_t +fdd_byteperiod(int drive) { - if (drives[drive].readsector) - drives[drive].readsector(drive, sector, track, side, density, sector_size); - else - fdd_notfound = 1000; + if (!fdd_get_turbo(drive) && drives[drive].byteperiod) + return drives[drive].byteperiod(drive); + else + return 32ULL * TIMER_USEC; } -void fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size) + +void +fdd_set_motor_enable(int drive, int motor_enable) { - if (drives[drive].writesector) - drives[drive].writesector(drive, sector, track, side, density, sector_size); - else - fdd_notfound = 1000; + /* I think here is where spin-up and spin-down should be implemented. */ + if (motor_enable && !motoron[drive]) + timer_set_delay_u64(&fdd_poll_time[drive], fdd_byteperiod(drive)); + else if (!motor_enable) + timer_disable(&fdd_poll_time[drive]); + motoron[drive] = motor_enable; } -void fdd_comparesector(int drive, int sector, int track, int side, int density, int sector_size) + +static void +fdd_poll(void *priv) { - if (drives[drive].comparesector) - drives[drive].comparesector(drive, sector, track, side, density, sector_size); - else - fdd_notfound = 1000; + int drive; + DRIVE *drv = (DRIVE *) priv; + + drive = drv->id; + + if (drive >= FDD_NUM) + fatal("Attempting to poll floppy drive %i that is not supposed to be there\n", drive); + + timer_advance_u64(&fdd_poll_time[drive], fdd_byteperiod(drive)); + + if (drv->poll) + drv->poll(drive); + + if (fdd_notfound) { + fdd_notfound--; + if (!fdd_notfound) + fdc_noidam(fdd_fdc); + } } -void fdd_readaddress(int drive, int side, int density) + +int +fdd_get_bitcell_period(int rate) { - if (drives[drive].readaddress) - drives[drive].readaddress(drive, side, density); + int bit_rate = 250; + + switch (rate) { + case 0: /*High density*/ + bit_rate = 500; + break; + case 1: /*Double density (360 rpm)*/ + bit_rate = 300; + break; + case 2: /*Double density*/ + bit_rate = 250; + break; + case 3: /*Extended density*/ + bit_rate = 1000; + break; + } + + return 1000000 / bit_rate*2; /*Bitcell period in ns*/ } -void fdd_format(int drive, int side, int density, uint8_t fill) + +void +fdd_reset(void) { - if (drives[drive].format) - drives[drive].format(drive, side, density, fill); - else - fdd_notfound = 1000; + int i; + + for (i = 0; i < 4; i++) { + drives[i].id = i; + timer_add(&(fdd_poll_time[i]), fdd_poll, &drives[i], 0); + } } -void fdd_stop(int drive) + +void +fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size) { - if (drives[drive].stop) - drives[drive].stop(drive); + if (drives[drive].readsector) + drives[drive].readsector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; } -void fdd_set_fdc(void *fdc) + +void +fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size) { - fdd_fdc = (fdc_t *) fdc; + if (drives[drive].writesector) + drives[drive].writesector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; } -void fdd_init(void) + +void +fdd_comparesector(int drive, int sector, int track, int side, int density, int sector_size) { - drives[0].poll = drives[1].poll = drives[2].poll = drives[3].poll = 0; - drives[0].seek = drives[1].seek = drives[2].seek = drives[3].seek = 0; - drives[0].readsector = drives[1].readsector = drives[2].readsector = drives[3].readsector = 0; - fdd_reset(); + if (drives[drive].comparesector) + drives[drive].comparesector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; +} + + +void +fdd_readaddress(int drive, int side, int density) +{ + if (drives[drive].readaddress) + drives[drive].readaddress(drive, side, density); +} + + +void +fdd_format(int drive, int side, int density, uint8_t fill) +{ + if (drives[drive].format) + drives[drive].format(drive, side, density, fill); + else + fdd_notfound = 1000; +} + + +void +fdd_stop(int drive) +{ + if (drives[drive].stop) + drives[drive].stop(drive); +} + + +void +fdd_set_fdc(void *fdc) +{ + fdd_fdc = (fdc_t *) fdc; +} + + +void +fdd_init(void) +{ + int i; + + for (i = 0; i < 4; i++) { + drives[i].poll = 0; + drives[i].seek = 0; + drives[i].readsector = 0; + } img_init(); d86f_init(); diff --git a/src/floppy/fdd.h b/src/floppy/fdd.h index 70414804f..149d06378 100644 --- a/src/floppy/fdd.h +++ b/src/floppy/fdd.h @@ -1,40 +1,22 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Definitions for the floppy drive emulation. * - * Version: @(#)fdd.h 1.0.4 2018/04/12 + * Version: @(#)fdd.h 1.0.7 2019/12/05 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 Fred N. van Kempen. */ #ifndef EMU_FDD_H # define EMU_FDD_H @@ -50,7 +32,7 @@ extern "C" { extern int fdd_swap; - +extern void fdd_set_motor_enable(int drive, int motor_enable); extern void fdd_do_seek(int drive, int track); extern void fdd_forced_seek(int drive, int track_diff); extern void fdd_seek(int drive, int track_diff); @@ -85,6 +67,8 @@ extern int fdd_current_track(int drive); typedef struct { + int id; + void (*seek)(int drive, int track); void (*readsector)(int drive, int sector, int track, int side, int density, int sector_size); @@ -95,17 +79,16 @@ typedef struct { void (*readaddress)(int drive, int side, int density); void (*format)(int drive, int side, int density, uint8_t fill); int (*hole)(int drive); - double (*byteperiod)(int drive); + uint64_t (*byteperiod)(int drive); void (*stop)(int drive); void (*poll)(int drive); } DRIVE; -extern DRIVE drives[FDD_NUM]; -extern wchar_t floppyfns[FDD_NUM][512]; -extern int driveempty[FDD_NUM]; -extern int64_t fdd_poll_time[FDD_NUM]; -extern int ui_writeprot[FDD_NUM]; +extern DRIVE drives[FDD_NUM]; +extern wchar_t floppyfns[FDD_NUM][512]; +extern pc_timer_t fdd_poll_time[FDD_NUM]; +extern int ui_writeprot[FDD_NUM]; extern int curdrive; @@ -118,11 +101,6 @@ extern void fdd_new(int drive, char *fn); extern void fdd_close(int drive); extern void fdd_init(void); extern void fdd_reset(void); -extern void fdd_poll(int drive); -extern void fdd_poll_0(void* priv); -extern void fdd_poll_1(void* priv); -extern void fdd_poll_2(void* priv); -extern void fdd_poll_3(void* priv); extern void fdd_seek(int drive, int track); extern void fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size); @@ -133,12 +111,10 @@ extern void fdd_comparesector(int drive, int sector, int track, extern void fdd_readaddress(int drive, int side, int density); extern void fdd_format(int drive, int side, int density, uint8_t fill); extern int fdd_hole(int drive); -extern double fdd_byteperiod(int drive); extern void fdd_stop(int drive); -extern void fdd_set_rate(int drive, int drvden, int rate); extern int motorspin; -extern int64_t motoron[FDD_NUM]; +extern uint64_t motoron[FDD_NUM]; extern int swwp; extern int disable_write; @@ -146,10 +122,8 @@ extern int disable_write; extern int defaultwriteprot; extern int writeprot[FDD_NUM], fwriteprot[FDD_NUM]; -extern int fdd_cur_track[FDD_NUM]; extern int fdd_changed[FDD_NUM]; extern int drive_empty[FDD_NUM]; -extern int drive_type[FDD_NUM]; /*Used in the Read A Track command. Only valid for fdd_readsector(). */ #define SECTOR_FIRST -2 @@ -182,39 +156,6 @@ typedef struct { } d86f_handler_t; extern const int gap3_sizes[5][8][48]; -extern d86f_handler_t d86f_handler[FDD_NUM]; - -extern void d86f_setup(int drive); -extern void d86f_destroy(int drive); -extern int d86f_export(int drive, wchar_t *fn); -extern void d86f_unregister(int drive); -extern void d86f_common_handlers(int drive); -extern void d86f_set_version(int drive, uint16_t version); -extern int d86f_is_40_track(int drive); -extern void d86f_reset_index_hole_pos(int drive, int side); -extern uint16_t d86f_prepare_pretrack(int drive, int side, int iso); -extern uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, - uint8_t *id_buf, uint8_t *data_buf, - int data_len, int gap2, int gap3, - int deleted, int bad_crc); -extern void d86f_set_track_pos(int drive, uint32_t track_pos); -extern void d86f_set_cur_track(int drive, int track); -extern void d86f_zero_track(int drive); -extern void d86f_initialize_last_sector_id(int drive, int c, int h, - int r, int n); -extern void d86f_initialize_linked_lists(int drive); -extern void d86f_destroy_linked_lists(int drive, int side); -extern uint16_t *common_encoded_data(int drive, int side); -extern void common_read_revolution(int drive); -extern uint32_t common_get_raw_size(int drive, int side); -extern void null_writeback(int drive); -extern void null_write_data(int drive, int side, uint16_t pos, - uint8_t data); -extern int null_format_conditions(int drive); -extern int32_t null_extra_bit_cells(int drive, int side); -extern void null_set_sector(int drive, int side, uint8_t c, uint8_t h, - uint8_t r, uint8_t n); -extern uint32_t null_index_hole_pos(int drive, int side); extern const uint8_t dmf_r[21]; extern const uint8_t xdf_physical_sectors[2][2]; @@ -254,6 +195,7 @@ void fdi_set_fdc(void *fdc); void fdd_set_fdc(void *fdc); void imd_set_fdc(void *fdc); void img_set_fdc(void *fdc); +void mfm_set_fdc(void *fdc); #ifdef __cplusplus diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 60df4620e..4fb68c606 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -1,40 +1,22 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the 86F floppy image format (stores the * data in the form of FM/MFM-encoded transitions) which also * forms the core of the emulator's floppy disk emulation. * - * Version: @(#)fdd_86f.c 1.0.10 2018/06/12 + * Version: @(#)fdd_86f.c 1.0.20 2019/12/06 * - * Authors: Fred N. van Kempen, - * Miran Grca, + * Authors: Miran Grca, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * - * 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. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #include #include @@ -45,8 +27,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../config.h" -#include "../device.h" +#include "../timer.h" #include "../dma.h" #include "../nvr.h" #include "../random.h" @@ -175,6 +156,7 @@ typedef union { typedef struct { uint8_t c, h, r, n; + uint8_t flags, pad, pad0, pad1; void *prev; } sector_t; @@ -192,6 +174,10 @@ typedef struct { * Bits 10, 9 Zone type (3 = Commodore 64 zoned, 2 = Apple zoned, * 1 = Pre-Apple zoned #2, 0 = Pre-Apple zoned #1) * Bit 11 Data and surface bits are stored in reverse byte endianness + * Bit 12 If bits 6, 5 are not 0, they specify % of speedup instead + * of slowdown; + * If bits 6, 5 are 0, and bit 7 is 1, the extra bitcell count + * specifies the entire bitcell count */ typedef struct { FILE *f; @@ -241,11 +227,6 @@ typedef struct { } d86f_t; -#ifdef ENABLE_D86F_LOG -int d86f_do_log = ENABLE_D86F_LOG; -#endif - - static const uint8_t encoded_fm[64] = { 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, @@ -282,19 +263,24 @@ void d86f_poll_write_data(int drive, int side, uint16_t pos, uint8_t data); int d86f_format_conditions(int drive); -static void -d86f_log(const char *format, ...) -{ #ifdef ENABLE_D86F_LOG +int d86f_do_log = ENABLE_D86F_LOG; + + +static void +d86f_log(const char *fmt, ...) +{ va_list ap; if (d86f_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define d86f_log(fmt, ...) +#endif static void @@ -362,6 +348,14 @@ d86f_get_rpm_mode(int drive) return (d86f_handler[drive].disk_flags(drive) & 0x60) >> 5; } + +int +d86f_get_speed_shift_dir(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 0x1000) >> 12; +} + + int d86f_reverse_bytes(int drive) { @@ -523,12 +517,23 @@ common_get_raw_size(int drive, int side) double rpm, rpm_diff; double size = 100000.0; int mfm; + int rm, ssd; + uint32_t extra_bc = 0; mfm = d86f_is_mfm(drive); rpm = ((d86f_track_flags(drive) & 0xE0) == 0x20) ? 360.0 : 300.0; rpm_diff = 1.0; + rm = d86f_get_rpm_mode(drive); + ssd = d86f_get_speed_shift_dir(drive); - switch (d86f_get_rpm_mode(drive)) { + /* 0% speed shift and shift direction 1: special case where extra bit cells are the entire track size. */ + if (!rm && ssd) + extra_bc = d86f_handler[drive].extra_bit_cells(drive, side); + + if (extra_bc) + return extra_bc; + + switch (rm) { case 1: rpm_diff = 1.01; break; @@ -546,6 +551,9 @@ common_get_raw_size(int drive, int side) break; } + if (ssd) + rpm_diff = 1.0 / rpm_diff; + switch (d86f_track_flags(drive) & 7) { case 0: rate = 500.0; @@ -638,29 +646,34 @@ d86f_register_86f(int drive) int -d86f_get_array_size(int drive, int side) +d86f_get_array_size(int drive, int side, int words) { int array_size; int hole, rm; + int ssd; rm = d86f_get_rpm_mode(drive); + ssd = d86f_get_speed_shift_dir(drive); hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1; - switch (hole) { + + if (!rm && ssd) /* Special case - extra bit cells size specifies entire array size. */ + array_size = 0; + else switch (hole) { case 0: case 1: default: array_size = 12500; switch (rm) { case 1: - array_size = 12625; + array_size = ssd ? 12376 : 12625; break; case 2: - array_size = 12687; + array_size = ssd ? 12315 : 12687; break; case 3: - array_size = 12750; + array_size = ssd ? 12254 : 12750; break; default: @@ -672,15 +685,15 @@ d86f_get_array_size(int drive, int side) array_size = 25000; switch (rm) { case 1: - array_size = 25250; + array_size = ssd ? 24752 : 25250; break; case 2: - array_size = 25375; + array_size = ssd ? 24630 : 25375; break; case 3: - array_size = 25500; + array_size = ssd ? 24509 : 25500; break; default: @@ -692,15 +705,15 @@ d86f_get_array_size(int drive, int side) array_size = 50000; switch (rm) { case 1: - array_size = 50500; + array_size = ssd ? 49504 : 50500; break; case 2: - array_size = 50750; + array_size = ssd ? 49261 : 50750; break; case 3: - array_size = 51000; + array_size = ssd ? 49019 : 51000; break; default: @@ -711,10 +724,14 @@ d86f_get_array_size(int drive, int side) array_size <<= 4; array_size += d86f_handler[drive].extra_bit_cells(drive, side); - array_size >>= 4; - if (d86f_handler[drive].extra_bit_cells(drive, side) & 15) - array_size++; + if (array_size & 15) + array_size = (array_size >> 4) + 1; + else + array_size = (array_size >> 4); + + if (!words) + array_size <<= 1; return array_size; } @@ -744,9 +761,12 @@ d86f_valid_bit_rate(int drive) case 3: /* ED with 2000 kbps support */ if (rate < 3) return 0; return 1; + + default: + break; } - return 1; //FIXME: should be 0 for error? + return 0; } @@ -767,37 +787,39 @@ d86f_get_encoding(int drive) } -double +uint64_t d86f_byteperiod(int drive) { + double dusec = (double) TIMER_USEC; + double p = 2.0; + switch (d86f_track_flags(drive) & 0x0f) { case 0x02: /* 125 kbps, FM */ - return 4.0; - + p = 4.0; + break; case 0x01: /* 150 kbps, FM */ - return 20.0 / 6.0; - + p = 20.0 / 6.0; + break; case 0x0a: /* 250 kbps, MFM */ case 0x00: /* 250 kbps, FM */ - return 2.0; - - case 0x09: /* 300 kbps, MFM */ - return 10.0 / 6.0; - - case 0x08: /* 500 kbps, MFM */ - return 1.0; - - case 0x0b: /* 1000 kbps, MFM */ - return 0.5; - - case 0x0d: /* 2000 kbps, MFM */ - return 0.25; - default: + p = 2.0; + break; + case 0x09: /* 300 kbps, MFM */ + p = 10.0 / 6.0; + break; + case 0x08: /* 500 kbps, MFM */ + p = 1.0; + break; + case 0x0b: /* 1000 kbps, MFM */ + p = 0.5; + break; + case 0x0d: /* 2000 kbps, MFM */ + p = 0.25; break; } - return 2.0; + return (uint64_t) (p * dusec); } @@ -1082,7 +1104,9 @@ d86f_get_bit(int drive, int side) encoded_data |= (d86f_handler[drive].encoded_data(drive, side)[track_word] >> 8); } - if (d86f_has_surface_desc(drive)) { + /* In some cases, misindentification occurs so we need to make sure the surface data array is not + not NULL. */ + if (d86f_has_surface_desc(drive) && dev->track_surface_data[side]) { if (d86f_reverse_bytes(drive)) { surface_data = dev->track_surface_data[side][track_word] & 0xFF; } else { @@ -1094,25 +1118,16 @@ d86f_get_bit(int drive, int side) current_bit = (encoded_data >> track_bit) & 1; dev->last_word[side] <<= 1; - if (d86f_has_surface_desc(drive)) { + if (d86f_has_surface_desc(drive) && dev->track_surface_data[side]) { surface_bit = (surface_data >> track_bit) & 1; - if (! surface_bit) { - if (! current_bit) { - /* Bit is 0 and is not set to fuzzy, we add it as read. */ - dev->last_word[side] |= 1; - } else { - /* Bit is 1 and is not set to fuzzy, we add it as read. */ - dev->last_word[side] |= 1; - } - } else { - if (current_bit) { - /* Bit is 1 and is set to fuzzy, we randomly generate it. */ - dev->last_word[side] |= (random_generate() & 1); - } + if (! surface_bit) + dev->last_word[side] |= current_bit; + else { + /* Bit is either 0 or 1 and is set to fuzzy, we randomly generate it. */ + dev->last_word[side] |= (random_generate() & 1); } - } else { + } else dev->last_word[side] |= current_bit; - } } @@ -1245,18 +1260,19 @@ d86f_word_is_aligned(int drive, int side, uint32_t base_pos) d86f_t *dev = d86f[drive]; uint32_t adjusted_track_pos = dev->track_pos; - if (base_pos == 0xFFFFFFFF) return 0; + if (base_pos == 0xFFFFFFFF) + return 0; /* * This is very important, it makes sure alignment is detected * correctly even across the index hole of a track whose length * is not divisible by 16. */ - if (adjusted_track_pos < base_pos) { + if (adjusted_track_pos < base_pos) adjusted_track_pos += d86f_handler[drive].get_raw_size(drive, side); - } - if ((adjusted_track_pos & 15) == (base_pos & 15)) return 1; + if ((adjusted_track_pos & 15) == (base_pos & 15)) + return 1; return 0; } @@ -1264,7 +1280,7 @@ d86f_word_is_aligned(int drive, int side, uint32_t base_pos) /* State 1: Find sector ID */ void -d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t ignore_other_am) +d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) { d86f_t *dev = d86f[drive]; @@ -1280,6 +1296,15 @@ d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, ui return; } + if ((wrong_am) && (dev->last_word[side] == wrong_am)) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_nodataam(d86f_fdc); + return; + } + if ((ignore_other_am & 2) && (dev->last_word[side] == other_am)) { dev->calc_crc.word = 0xFFFF; fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); @@ -1326,7 +1351,7 @@ d86f_write_find_address_mark_fm(int drive, int side, find_t *find) void -d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t ignore_other_am) +d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) { d86f_t *dev = d86f[drive]; @@ -1338,6 +1363,15 @@ d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, u return; } + if ((wrong_am) && (dev->last_word[side] == wrong_am) && (find->sync_marks >= 3)) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_nodataam(d86f_fdc); + return; + } + if ((dev->last_word[side] == req_am) && (find->sync_marks >= 3)) { if (d86f_word_is_aligned(drive, side, find->sync_pos)) { dev->calc_crc.word = 0xCDB4; @@ -1427,7 +1461,7 @@ d86f_read_sector_id(int drive, int side, int match) if (dev->id_find.bytes_obtained == 6) { /* We've got the ID. */ - if (dev->calc_crc.word != dev->track_crc.word) { + if ((dev->calc_crc.word != dev->track_crc.word) && (dev->last_sector.dword == dev->req_sector.dword)) { dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; d86f_log("86F: ID CRC error: %04X != %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword); if ((dev->state != STATE_02_READ_ID) && (dev->state != STATE_0A_READ_ID)) { @@ -1551,7 +1585,17 @@ d86f_read_sector_data(int drive, int side) /* We've got a byte. */ d86f_log("86F: We've got a byte.\n"); if (dev->data_find.bytes_obtained < sector_len) { - data = decodefm(drive, dev->last_word[side]); + if (d86f_handler[drive].read_data != NULL) + data = d86f_handler[drive].read_data(drive, side, dev->data_find.bytes_obtained); + else { +#ifdef HACK_FOR_DBASE_III + if ((dev->last_sector.id.c == 39) && (dev->last_sector.id.h == 0) && + (dev->last_sector.id.r == 5) && (dev->data_find.bytes_obtained >= 272)) + data = (random_generate() & 0xff); + else +#endif + data = decodefm(drive, dev->last_word[side]); + } if (dev->state == STATE_11_SCAN_DATA) { /* Scan/compare command. */ recv_data = d86f_get_data(drive, 0); @@ -1586,7 +1630,7 @@ d86f_read_sector_data(int drive, int side) fdc_track_finishread(d86f_fdc, dev->error_condition); } else { /* CRC is valid. */ - d86f_log("86F: Data CRC OK: %04X != %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword); + d86f_log("86F: Data CRC OK: %04X == %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword); dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; dev->error_condition = 0; dev->state = STATE_IDLE; @@ -2092,6 +2136,28 @@ d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n) } +static uint8_t +d86f_sector_flags(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + d86f_t *dev = d86f[drive]; + sector_t *s, *t; + + if (dev->last_side_sector[side]) { + s = dev->last_side_sector[side]; + while (s) { + if ((s->c == c) && (s->h == h) && (s->r == r) && (s->n == n)) + return s->flags; + if (! s->prev) + break; + t = s->prev; + s = t; + } + } + + return 0x00; +} + + void d86f_turbo_read(int drive, int side) { @@ -2099,8 +2165,12 @@ d86f_turbo_read(int drive, int side) uint8_t dat = 0; int recv_data = 0; int read_status = 0; + uint8_t flags = d86f_sector_flags(drive, side, dev->req_sector.id.c, dev->req_sector.id.h, dev->req_sector.id.r, dev->req_sector.id.n); - dat = d86f_handler[drive].read_data(drive, side, dev->turbo_pos); + if (d86f_handler[drive].read_data != NULL) + dat = d86f_handler[drive].read_data(drive, side, dev->turbo_pos); + else + dat = (random_generate() & 0xff); dev->turbo_pos++; if (dev->state == STATE_11_SCAN_DATA) { @@ -2118,15 +2188,30 @@ d86f_turbo_read(int drive, int side) } if (dev->turbo_pos >= (128 << dev->last_sector.id.n)) { - /* CRC is valid. */ dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; - dev->error_condition = 0; - if (dev->state == STATE_11_SCAN_DATA) { + if ((flags & SECTOR_CRC_ERROR) && (dev->state != STATE_02_READ_DATA)) { +#ifdef ENABLE_D86F_LOG + d86f_log("86F: Data CRC error in turbo mode\n"); +#endif + dev->error_condition = 0; dev->state = STATE_IDLE; - fdc_sector_finishcompare(d86f_fdc, (dev->satisfying_bytes == ((128 << ((uint32_t) dev->last_sector.id.n)) - 1)) ? 1 : 0); + fdc_finishread(d86f_fdc); + fdc_datacrcerror(d86f_fdc); + } else if ((dev->calc_crc.word != dev->track_crc.word) && (dev->state == STATE_02_READ_DATA)) { + dev->error_condition |= 2; /* Mark that there was a data error. */ + dev->state = STATE_IDLE; + fdc_track_finishread(d86f_fdc, dev->error_condition); } else { + /* CRC is valid. */ +#ifdef ENABLE_D86F_LOG + d86f_log("86F: Data CRC OK error in turbo mode\n"); +#endif + dev->error_condition = 0; dev->state = STATE_IDLE; - fdc_sector_finishread(d86f_fdc); + if (dev->state == STATE_11_SCAN_DATA) + fdc_sector_finishcompare(d86f_fdc, (dev->satisfying_bytes == ((128 << ((uint32_t) dev->last_sector.id.n)) - 1)) ? 1 : 0); + else + fdc_sector_finishread(d86f_fdc); } } } @@ -2250,11 +2335,8 @@ d86f_turbo_poll(int drive, int side) return; case STATE_02_FIND_ID: - if (! d86f_sector_is_present(drive, side, - fdc_get_read_track_sector(d86f_fdc).id.c, - fdc_get_read_track_sector(d86f_fdc).id.h, - fdc_get_read_track_sector(d86f_fdc).id.r, - fdc_get_read_track_sector(d86f_fdc).id.n)) { + if (! d86f_sector_is_present(drive, side, fdc_get_read_track_sector(d86f_fdc).id.c, fdc_get_read_track_sector(d86f_fdc).id.h, + fdc_get_read_track_sector(d86f_fdc).id.r, fdc_get_read_track_sector(d86f_fdc).id.n)) { dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; fdc_nosector(d86f_fdc); dev->state = STATE_IDLE; @@ -2275,15 +2357,16 @@ d86f_turbo_poll(int drive, int side) case STATE_0C_FIND_ID: case STATE_11_FIND_ID: case STATE_16_FIND_ID: - if (! d86f_sector_is_present(drive, side, - dev->req_sector.id.c, - dev->req_sector.id.h, - dev->req_sector.id.r, - dev->req_sector.id.n)) { + if (! d86f_sector_is_present(drive, side, dev->req_sector.id.c, dev->req_sector.id.h, dev->req_sector.id.r, dev->req_sector.id.n)) { dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; fdc_nosector(d86f_fdc); dev->state = STATE_IDLE; return; + } else if (d86f_sector_flags(drive, side, dev->req_sector.id.c, dev->req_sector.id.h, dev->req_sector.id.r, dev->req_sector.id.n) & SECTOR_NO_ID) { + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_noidam(d86f_fdc); + dev->state = STATE_IDLE; + return; } dev->last_sector.id.c = dev->req_sector.id.c; dev->last_sector.id.h = dev->req_sector.id.h; @@ -2398,9 +2481,9 @@ d86f_poll(int drive) case STATE_11_FIND_ID: case STATE_16_FIND_ID: if (mfm) - d86f_find_address_mark_mfm(drive, side, &(dev->id_find), 0x5554, 0, 0); + d86f_find_address_mark_mfm(drive, side, &(dev->id_find), 0x5554, 0, 0, 0); else - d86f_find_address_mark_fm(drive, side, &(dev->id_find), 0xF57E, 0, 0); + d86f_find_address_mark_fm(drive, side, &(dev->id_find), 0xF57E, 0, 0, 0); break; case STATE_0A_READ_ID: @@ -2419,18 +2502,18 @@ d86f_poll(int drive) case STATE_02_FIND_DATA: if (mfm) - d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 2); + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 0x5554, 2); else - d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 2); + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 0xF57E, 2); break; case STATE_06_FIND_DATA: case STATE_11_FIND_DATA: case STATE_16_FIND_DATA: if (mfm) - d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, fdc_is_sk(d86f_fdc) | 2); + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 0x5554, fdc_is_sk(d86f_fdc) | 2); else - d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, fdc_is_sk(d86f_fdc) | 2); + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 0xF57E, fdc_is_sk(d86f_fdc) | 2); break; case STATE_05_FIND_DATA: @@ -2443,9 +2526,9 @@ d86f_poll(int drive) case STATE_0C_FIND_DATA: if (mfm) - d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x554A, 0x5545, fdc_is_sk(d86f_fdc) | 2); + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x554A, 0x5545, 0x5554, fdc_is_sk(d86f_fdc) | 2); else - d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56A, 0xF56F, fdc_is_sk(d86f_fdc) | 2); + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56A, 0xF56F, 0xF57E, fdc_is_sk(d86f_fdc) | 2); break; case STATE_02_READ_DATA: @@ -2510,7 +2593,6 @@ d86f_poll(int drive) case STATE_05_FIND_DATA: case STATE_09_FIND_DATA: case STATE_0C_FIND_DATA: - dev->state = STATE_IDLE; fdc_nodataam(d86f_fdc); break; @@ -2540,9 +2622,8 @@ d86f_poll(int drive) fdc_nosector(d86f_fdc); } else fdc_nosector(d86f_fdc); - } else { + } else fdc_noidam(d86f_fdc); - } break; } } @@ -2577,7 +2658,11 @@ d86f_prepare_pretrack(int drive, int side, int iso) sync_len = mfm ? 12 : 6; real_gap1_len = mfm ? 50 : 26; gap_fill = mfm ? 0x4E : 0xFF; - raw_size = d86f_handler[drive].get_raw_size(drive, side) >> 4; + raw_size = d86f_handler[drive].get_raw_size(drive, side); + if (raw_size & 15) + raw_size = (raw_size >> 4) + 1; + else + raw_size = (raw_size >> 4); dev->index_hole_pos[side] = 0; @@ -2618,7 +2703,7 @@ d86f_prepare_pretrack(int drive, int side, int iso) uint16_t -d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t *data_buf, int data_len, int gap2, int gap3, int deleted, int bad_crc) +d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t *data_buf, int data_len, int gap2, int gap3, int flags) { d86f_t *dev = d86f[drive]; uint16_t pos; @@ -2645,6 +2730,7 @@ d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t s->h = id_buf[1]; s->r = id_buf[2]; s->n = id_buf[3]; + s->flags = flags; if (dev->last_side_sector[side]) s->prev = dev->last_side_sector[side]; dev->last_side_sector[side] = s; @@ -2653,69 +2739,81 @@ d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t mfm = d86f_is_mfm(drive); gap_fill = mfm ? 0x4E : 0xFF; - raw_size = d86f_handler[drive].get_raw_size(drive, side) >> 4; + raw_size = d86f_handler[drive].get_raw_size(drive, side); + if (raw_size & 15) + raw_size = (raw_size >> 4) + 1; + else + raw_size = (raw_size >> 4); pos = prev_pos; sync_len = mfm ? 12 : 6; - for (i = 0; i < sync_len; i++) { - d86f_write_direct_common(drive, side, 0, 0, pos); - pos = (pos + 1) % raw_size; - } - dev->calc_crc.word = 0xffff; - if (mfm) { - for (i = 0; i < 3; i++) { - d86f_write_direct_common(drive, side, 0x8944, 1, pos); + if (!(flags & SECTOR_NO_ID)) { + for (i = 0; i < sync_len; i++) { + d86f_write_direct_common(drive, side, 0, 0, pos); + pos = (pos + 1) % raw_size; + } + + dev->calc_crc.word = 0xffff; + if (mfm) { + for (i = 0; i < 3; i++) { + d86f_write_direct_common(drive, side, 0x8944, 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, 0xA1); + } + } + d86f_write_direct_common(drive, side, mfm ? idam_mfm : idam_fm, 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, 0xFE); + for (i = 0; i < 4; i++) { + d86f_write_direct_common(drive, side, id_buf[i], 0, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, id_buf[i]); + } + for (i = 1; i >= 0; i--) { + d86f_write_direct_common(drive, side, dev->calc_crc.bytes[i], 0, pos); + pos = (pos + 1) % raw_size; + } + for (i = 0; i < real_gap2_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); pos = (pos + 1) % raw_size; - d86f_calccrc(dev, 0xA1); } } - d86f_write_direct_common(drive, side, mfm ? idam_mfm : idam_fm, 1, pos); - pos = (pos + 1) % raw_size; - d86f_calccrc(dev, 0xFE); - for (i = 0; i < 4; i++) { - d86f_write_direct_common(drive, side, id_buf[i], 0, pos); - pos = (pos + 1) % raw_size; - d86f_calccrc(dev, id_buf[i]); - } - for (i = 1; i >= 0; i--) { - d86f_write_direct_common(drive, side, dev->calc_crc.bytes[i], 0, pos); - pos = (pos + 1) % raw_size; - } - for (i = 0; i < real_gap2_len; i++) { - d86f_write_direct_common(drive, side, gap_fill, 0, pos); - pos = (pos + 1) % raw_size; - } - for (i = 0; i < sync_len; i++) { - d86f_write_direct_common(drive, side, 0, 0, pos); - pos = (pos + 1) % raw_size; - } - dev->calc_crc.word = 0xffff; - if (mfm) { - for (i = 0; i < 3; i++) { - d86f_write_direct_common(drive, side, 0x8944, 1, pos); + + if (!(flags & SECTOR_NO_DATA)) { + for (i = 0; i < sync_len; i++) { + d86f_write_direct_common(drive, side, 0, 0, pos); pos = (pos + 1) % raw_size; - d86f_calccrc(dev, 0xA1); } - } - d86f_write_direct_common(drive, side, mfm ? (deleted ? datadam_mfm : dataam_mfm) : (deleted ? datadam_fm : dataam_fm), 1, pos); - pos = (pos + 1) % raw_size; - d86f_calccrc(dev, deleted ? 0xF8 : 0xFB); - for (i = 0; i < data_len; i++) { - d86f_write_direct_common(drive, side, data_buf[i], 0, pos); - pos = (pos + 1) % raw_size; - d86f_calccrc(dev, data_buf[i]); - } - if (bad_crc) - dev->calc_crc.word ^= 0xffff; - for (i = 1; i >= 0; i--) { - d86f_write_direct_common(drive, side, dev->calc_crc.bytes[i], 0, pos); - pos = (pos + 1) % raw_size; - } - for (i = 0; i < real_gap3_len; i++) { - d86f_write_direct_common(drive, side, gap_fill, 0, pos); + dev->calc_crc.word = 0xffff; + if (mfm) { + for (i = 0; i < 3; i++) { + d86f_write_direct_common(drive, side, 0x8944, 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, 0xA1); + } + } + d86f_write_direct_common(drive, side, mfm ? ((flags & SECTOR_DELETED_DATA) ? datadam_mfm : dataam_mfm) : ((flags & SECTOR_DELETED_DATA) ? datadam_fm : dataam_fm), 1, pos); pos = (pos + 1) % raw_size; + d86f_calccrc(dev, (flags & SECTOR_DELETED_DATA) ? 0xF8 : 0xFB); + if (data_len > 0) { + for (i = 0; i < data_len; i++) { + d86f_write_direct_common(drive, side, data_buf[i], 0, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, data_buf[i]); + } + if (!(flags & SECTOR_CRC_ERROR)) { + for (i = 1; i >= 0; i--) { + d86f_write_direct_common(drive, side, dev->calc_crc.bytes[i], 0, pos); + pos = (pos + 1) % raw_size; + } + } + for (i = 0; i < real_gap3_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); + pos = (pos + 1) % raw_size; + } + } } return pos; @@ -2733,9 +2831,9 @@ d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t * - One is regular and one is fuzzy -> Output is fuzzy; * - Both are fuzzy -> Output is fuzzy; * - Both are physical holes -> Output is a physical hole; - * - One is regular and one is a physical hole -> Output is puzzy, + * - One is regular and one is a physical hole -> Output is fuzzy, * the hole half is handled appropriately on writeback; - * - One is fuzzy and one is a physical hole -> Output is puzzy, + * - One is fuzzy and one is a physical hole -> Output is fuzzy, * the hole half is handled appropriately on writeback; * - On write back, apart from the above notes, the final two tracks * are written; @@ -2759,7 +2857,7 @@ d86f_construct_encoded_buffer(int drive, int side) uint16_t *src1_s = dev->thin_track_surface_data[0][side]; uint16_t *src2 = dev->thin_track_encoded_data[1][side]; uint16_t *src2_s = dev->thin_track_surface_data[1][side]; - len = d86f_get_array_size(drive, side); + len = d86f_get_array_size(drive, side, 1); for (i = 0; i < len; i++) { /* The two bits differ. */ @@ -2805,7 +2903,8 @@ d86f_decompose_encoded_buffer(int drive, int side) uint16_t *src1_s = dev->thin_track_surface_data[0][side]; uint16_t *src2 = dev->thin_track_encoded_data[1][side]; uint16_t *src2_s = dev->thin_track_surface_data[1][side]; - len = d86f_get_array_size(drive, side); + dst = d86f_handler[drive].encoded_data(drive, side); + len = d86f_get_array_size(drive, side, 1); for (i = 0; i < len; i++) { if (d86f_has_surface_desc(drive)) { @@ -2854,18 +2953,20 @@ d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *da, ui fread(&(dev->side_flags[side]), 2, 1, dev->f); if (d86f_has_extra_bit_cells(drive)) { fread(&(dev->extra_bit_cells[side]), 4, 1, dev->f); - if (dev->extra_bit_cells[side] < -32768) - dev->extra_bit_cells[side] = -32768; - if (dev->extra_bit_cells[side] > 32768) - dev->extra_bit_cells[side] = 32768; - } else { + /* If RPM shift is 0% and direction is 1, do not adjust extra bit cells, + as that is the whole track length. */ + if (d86f_get_rpm_mode(drive) || !d86f_get_speed_shift_dir(drive)) { + if (dev->extra_bit_cells[side] < -32768) + dev->extra_bit_cells[side] = -32768; + if (dev->extra_bit_cells[side] > 32768) + dev->extra_bit_cells[side] = 32768; + } + } else dev->extra_bit_cells[side] = 0; - } fread(&(dev->index_hole_pos[side]), 4, 1, dev->f); - } else { + } else fseek(dev->f, dev->track_offset[logical_track] + d86f_track_header_size(drive), SEEK_SET); - } - array_size = d86f_get_array_size(drive, side) << 1; + array_size = d86f_get_array_size(drive, side, 0); if (d86f_has_surface_desc(drive)) fread(sa, 1, array_size, dev->f); fread(da, 1, array_size, dev->f); @@ -2951,6 +3052,7 @@ d86f_seek(int drive, int track) void d86f_write_track(int drive, FILE **f, int side, uint16_t *da0, uint16_t *sa0) { + uint32_t array_size = d86f_get_array_size(drive, side, 0); uint16_t side_flags = d86f_handler[drive].side_flags(drive); uint32_t extra_bit_cells = d86f_handler[drive].extra_bit_cells(drive, side); uint32_t index_hole_pos = d86f_handler[drive].index_hole_pos(drive, side); @@ -2963,9 +3065,9 @@ d86f_write_track(int drive, FILE **f, int side, uint16_t *da0, uint16_t *sa0) fwrite(&index_hole_pos, 1, 4, *f); if (d86f_has_surface_desc(drive)) - fwrite(sa0, 1, d86f_get_array_size(drive, side) << 1, *f); + fwrite(sa0, 1, array_size, *f); - fwrite(da0, 1, d86f_get_array_size(drive, side) << 1, *f); + fwrite(da0, 1, array_size, *f); } @@ -2994,22 +3096,26 @@ void d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) { d86f_t *dev = d86f[drive]; - int sides; + int sides, fdd_side; int side, thin_track; int logical_track = 0; + uint32_t *tbl; + tbl = dev->track_offset; + fdd_side = fdd_get_head(drive); sides = d86f_get_sides(drive); - uint32_t *tbl = dev->track_offset; - int fdd_side = fdd_get_head(drive); if (track_table) tbl = track_table; - if (! fdd_doublestep_40(drive)) { - for (side = 0; side < sides; side++) { - fdd_set_head(drive, side); - d86f_decompose_encoded_buffer(drive, side); + if (!fdd_doublestep_40(drive)) { + d86f_decompose_encoded_buffer(drive, 0); + if (sides == 2) + d86f_decompose_encoded_buffer(drive, 1); + + for (thin_track = 0; thin_track < 2; thin_track++) { + for (side = 0; side < sides; side++) { + fdd_set_head(drive, side); - for (thin_track = 0; thin_track < 2; thin_track++) { if (sides == 2) logical_track = ((dev->cur_track + thin_track) << 1) + side; else @@ -3017,8 +3123,9 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) if (track_table && !tbl[logical_track]) { fseek(*f, 0, SEEK_END); - track_table[logical_track] = ftell(*f); + tbl[logical_track] = ftell(*f); } + if (tbl[logical_track]) { fseek(*f, tbl[logical_track], SEEK_SET); d86f_write_track(drive, f, side, dev->thin_track_encoded_data[thin_track][side], dev->thin_track_surface_data[thin_track][side]); @@ -3035,12 +3142,12 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) if (track_table && !tbl[logical_track]) { fseek(*f, 0, SEEK_END); - track_table[logical_track] = ftell(*f); + tbl[logical_track] = ftell(*f); } if (tbl[logical_track]) { fseek(*f, tbl[logical_track], SEEK_SET); - d86f_write_track(drive, f, side, dev->track_encoded_data[side], dev->track_surface_data[side]); + d86f_write_track(drive, f, side, d86f_handler[drive].encoded_data(drive, side), dev->track_surface_data[side]); } } } @@ -3111,7 +3218,8 @@ d86f_stop(int drive) { d86f_t *dev = d86f[drive]; - dev->state = STATE_IDLE; + if (dev) + dev->state = STATE_IDLE; } @@ -3124,13 +3232,12 @@ d86f_common_command(int drive, int sector, int track, int side, int rate, int se dev->req_sector.id.c = track; dev->req_sector.id.h = side; - if (sector == SECTOR_FIRST) { + if (sector == SECTOR_FIRST) dev->req_sector.id.r = 1; - } else if (sector == SECTOR_NEXT) { + else if (sector == SECTOR_NEXT) dev->req_sector.id.r++; - } else { + else dev->req_sector.id.r = sector; - } dev->req_sector.id.n = sector_size; if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1)) { @@ -3231,8 +3338,7 @@ d86f_add_track(int drive, int track, int side) uint32_t array_size; int logical_track; - array_size = d86f_get_array_size(drive, side); - array_size <<= 1; + array_size = d86f_get_array_size(drive, side, 0); if (d86f_get_sides(drive) == 2) { logical_track = (track << 1) + side; @@ -3288,7 +3394,7 @@ d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) return; } - array_size = d86f_get_array_size(drive, side); + array_size = d86f_get_array_size(drive, side, 0); if (d86f_has_surface_desc(drive)) { /* Preserve the physical holes but get rid of the fuzzy bytes. */ @@ -3301,7 +3407,7 @@ d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) } /* Zero the data buffer. */ - memset(dev->track_encoded_data[side], 0, array_size << 1); + memset(dev->track_encoded_data[side], 0, array_size); d86f_add_track(drive, dev->cur_track, side); if (! fdd_doublestep_40(drive)) @@ -3371,7 +3477,7 @@ d86f_export(int drive, wchar_t *fn) int i; int inc = 1; uint32_t magic = 0x46423638; - uint16_t version = 0x020B; + uint16_t version = 0x020C; uint16_t disk_flags = d86f_handler[drive].disk_flags(drive); memset(tt, 0, 512 * sizeof(uint32_t)); @@ -3677,8 +3783,10 @@ d86f_load(int drive, wchar_t *fn) fread(&(dev->side_flags[0]), 2, 1, dev->f); if (dev->disk_flags & 0x80) { fread(&(dev->extra_bit_cells[0]), 4, 1, dev->f); - if (dev->extra_bit_cells[0] < -32768) dev->extra_bit_cells[0] = -32768; - if (dev->extra_bit_cells[0] > 32768) dev->extra_bit_cells[0] = 32768; + if ((dev->disk_flags & 0x1060) != 0x1000) { + if (dev->extra_bit_cells[0] < -32768) dev->extra_bit_cells[0] = -32768; + if (dev->extra_bit_cells[0] > 32768) dev->extra_bit_cells[0] = 32768; + } } else { dev->extra_bit_cells[0] = 0; } @@ -3688,8 +3796,10 @@ d86f_load(int drive, wchar_t *fn) fread(&(dev->side_flags[1]), 2, 1, dev->f); if (dev->disk_flags & 0x80) { fread(&(dev->extra_bit_cells[1]), 4, 1, dev->f); - if (dev->extra_bit_cells[1] < -32768) dev->extra_bit_cells[1] = -32768; - if (dev->extra_bit_cells[1] > 32768) dev->extra_bit_cells[1] = 32768; + if ((dev->disk_flags & 0x1060) != 0x1000) { + if (dev->extra_bit_cells[1] < -32768) dev->extra_bit_cells[1] = -32768; + if (dev->extra_bit_cells[1] > 32768) dev->extra_bit_cells[1] = 32768; + } } else { dev->extra_bit_cells[0] = 0; } @@ -3848,4 +3958,6 @@ d86f_destroy(int drive) free(d86f[drive]); d86f[drive] = NULL; + + d86f_handler[drive].read_data = NULL; } diff --git a/src/floppy/fdd_86f.h b/src/floppy/fdd_86f.h index 8242f5bb7..ced699711 100644 --- a/src/floppy/fdd_86f.h +++ b/src/floppy/fdd_86f.h @@ -1,70 +1,34 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Definitions for the 86F floppy image format. * - * Version: @(#)floppy_86f.h 1.0.4 2018/03/17 + * Version: @(#)floppy_86f.h 1.0.6 2019/12/05 * - * Authors: Fred N. van Kempen, - * Miran Grca, + * Authors: Miran Grca, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * - * 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. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #ifndef EMU_FLOPPY_86F_H # define EMU_FLOPPY_86F_H -#define D86FVER 0x020B +#define D86FVER 0x020C - -extern void d86f_init(void); -extern void d86f_load(int drive, wchar_t *fn); -extern void d86f_close(int drive); -extern void d86f_seek(int drive, int track); -extern int d86f_hole(int drive); -extern double d86f_byteperiod(int drive); -extern void d86f_stop(int drive); -extern void d86f_poll(int drive); -extern int d86f_realtrack(int track, int drive); -extern void d86f_reset(int drive, int side); -extern void d86f_readsector(int drive, int sector, int track, int side, int density, int sector_size); -extern void d86f_writesector(int drive, int sector, int track, int side, int density, int sector_size); -extern void d86f_comparesector(int drive, int sector, int track, int side, int rate, int sector_size); -extern void d86f_readaddress(int drive, int side, int density); -extern void d86f_format(int drive, int side, int density, uint8_t fill); - -extern void d86f_prepare_track_layout(int drive, int side); -extern void d86f_set_version(int drive, uint16_t version); -extern uint16_t d86f_side_flags(int drive); -extern uint16_t d86f_track_flags(int drive); -extern void d86f_initialize_last_sector_id(int drive, int c, int h, - int r, int n); -extern void d86f_initialize_linked_lists(int drive); -extern void d86f_destroy_linked_lists(int drive, int side); +/* Thesere were borrowed from TeleDisk. */ +#define SECTOR_DUPLICATED 0x01 +#define SECTOR_CRC_ERROR 0x02 +#define SECTOR_DELETED_DATA 0x04 +#define SECTOR_DATA_SKIPPED 0x10 +#define SECTOR_NO_DATA 0x20 +#define SECTOR_NO_ID 0x40 #define length_gap0 80 #define length_gap1 50 @@ -86,4 +50,61 @@ extern void d86f_destroy_linked_lists(int drive, int side); #define post_gap length_crc +extern d86f_handler_t d86f_handler[FDD_NUM]; + + +extern void d86f_init(void); +extern void d86f_load(int drive, wchar_t *fn); +extern void d86f_close(int drive); +extern void d86f_seek(int drive, int track); +extern int d86f_hole(int drive); +extern uint64_t d86f_byteperiod(int drive); +extern void d86f_stop(int drive); +extern void d86f_poll(int drive); +extern int d86f_realtrack(int track, int drive); +extern void d86f_reset(int drive, int side); +extern void d86f_readsector(int drive, int sector, int track, int side, int density, int sector_size); +extern void d86f_writesector(int drive, int sector, int track, int side, int density, int sector_size); +extern void d86f_comparesector(int drive, int sector, int track, int side, int rate, int sector_size); +extern void d86f_readaddress(int drive, int side, int density); +extern void d86f_format(int drive, int side, int density, uint8_t fill); + +extern void d86f_prepare_track_layout(int drive, int side); +extern void d86f_set_version(int drive, uint16_t version); +extern uint16_t d86f_side_flags(int drive); +extern uint16_t d86f_track_flags(int drive); +extern void d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n); +extern void d86f_initialize_linked_lists(int drive); +extern void d86f_destroy_linked_lists(int drive, int side); + +extern uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t *data_buf, + int data_len, int gap2, int gap3, int flags); +extern void d86f_setup(int drive); +extern void d86f_destroy(int drive); +extern int d86f_export(int drive, wchar_t *fn); +extern void d86f_unregister(int drive); +extern void d86f_common_handlers(int drive); +extern void d86f_set_version(int drive, uint16_t version); +extern int d86f_is_40_track(int drive); +extern void d86f_reset_index_hole_pos(int drive, int side); +extern uint16_t d86f_prepare_pretrack(int drive, int side, int iso); +extern void d86f_set_track_pos(int drive, uint32_t track_pos); +extern void d86f_set_cur_track(int drive, int track); +extern void d86f_zero_track(int drive); +extern void d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n); +extern void d86f_initialize_linked_lists(int drive); +extern void d86f_destroy_linked_lists(int drive, int side); + +extern uint16_t *common_encoded_data(int drive, int side); +extern void common_read_revolution(int drive); +extern uint32_t common_get_raw_size(int drive, int side); + +extern void null_writeback(int drive); +extern void null_write_data(int drive, int side, uint16_t pos, uint8_t data); +extern int null_format_conditions(int drive); +extern int32_t null_extra_bit_cells(int drive, int side); +extern void null_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n); +extern uint32_t null_index_hole_pos(int drive, int side); + + #endif /*EMU_FLOPPY_86F_H*/ diff --git a/src/floppy/fdd_common.c b/src/floppy/fdd_common.c index 5638b0565..3b3bfa338 100644 --- a/src/floppy/fdd_common.c +++ b/src/floppy/fdd_common.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Shared code for all the floppy modules. * @@ -13,24 +13,6 @@ * Author: Fred N. van Kempen, * * Copyright 2017,2018 Fred N. van Kempen. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. */ #include #include @@ -38,6 +20,7 @@ #include #include #include "../86box.h" +#include "../timer.h" #include "fdd.h" #include "fdd_common.h" diff --git a/src/floppy/fdd_common.h b/src/floppy/fdd_common.h index 02ff78375..509fdfa7d 100644 --- a/src/floppy/fdd_common.h +++ b/src/floppy/fdd_common.h @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Shared code for all the floppy modules. * @@ -13,24 +13,6 @@ * Author: Fred N. van Kempen, * * Copyright 2017,2018 Fred N. van Kempen. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. */ #ifndef FDD_COMMON_H # define FDD_COMMON_H diff --git a/src/floppy/fdd_fdi.c b/src/floppy/fdd_fdi.c index a8c7a0dce..d49c851a5 100644 --- a/src/floppy/fdd_fdi.c +++ b/src/floppy/fdd_fdi.c @@ -1,41 +1,23 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the FDI floppy stream image format * interface to the FDI2RAW module. * - * Version: @(#)fdd_fdi.c 1.0.3 2018/04/29 + * Version: @(#)fdd_fdi.c 1.0.4 2018/10/18 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 Fred N. van Kempen. */ #include #include @@ -45,6 +27,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../plat.h" #include "fdd.h" #include "fdd_86f.h" @@ -75,13 +58,11 @@ static fdc_t *fdi_fdc; #ifdef ENABLE_FDI_LOG int fdi_do_log = ENABLE_FDI_LOG; -#endif static void fdi_log(const char *fmt, ...) { -#ifdef ENABLE_FDI_LOG va_list ap; if (fdi_do_log) @@ -90,8 +71,10 @@ fdi_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define fdi_log(fmt, ...) +#endif static uint16_t diff --git a/src/floppy/fdd_fdi.h b/src/floppy/fdd_fdi.h index 4808ecb03..9e3f258a4 100644 --- a/src/floppy/fdd_fdi.h +++ b/src/floppy/fdd_fdi.h @@ -1,41 +1,23 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the FDI floppy stream image format * interface to the FDI2RAW module. * * Version: @(#)floppy_fdi.h 1.0.2 2018/03/17 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 Fred N. van Kempen. */ #ifndef EMU_FLOPPY_FDI_H # define EMU_FLOPPY_FDI_H diff --git a/src/floppy/fdd_imd.c b/src/floppy/fdd_imd.c index 9e690a479..421e339cf 100644 --- a/src/floppy/fdd_imd.c +++ b/src/floppy/fdd_imd.c @@ -1,38 +1,20 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the IMD floppy image format. * - * Version: @(#)fdd_imd.c 1.0.7 2018/04/29 + * Version: @(#)fdd_imd.c 1.0.9 2019/12/05 * * Authors: Fred N. van Kempen, * Miran Grca, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * - * 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. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #include #include @@ -42,8 +24,10 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../plat.h" #include "fdd.h" +#include "fdd_86f.h" #include "fdd_imd.h" #include "fdc.h" @@ -61,6 +45,7 @@ typedef struct { uint32_t sector_data_size[255]; uint32_t gap3_len; uint16_t side_flags; + uint8_t max_sector_size; } imd_track_t; typedef struct { @@ -86,13 +71,11 @@ static fdc_t *imd_fdc; #ifdef ENABLE_IMD_LOG int imd_do_log = ENABLE_IMD_LOG; -#endif static void imd_log(const char *fmt, ...) { -#ifdef ENABLE_IMD_LOG va_list ap; if (imd_do_log) @@ -101,8 +84,10 @@ imd_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define imd_log(fmt, ...) +#endif static uint32_t @@ -300,7 +285,7 @@ imd_seek(int drive, int track) { uint32_t track_buf_pos[2] = { 0, 0 }; uint8_t id[4] = { 0, 0, 0, 0 }; - uint8_t type, deleted, bad_crc; + uint8_t type; imd_t *dev = imd[drive]; int sector, current_pos; int side, c = 0, h, n; @@ -321,6 +306,7 @@ imd_seek(int drive, int track) char *r_map; char *n_map = NULL; uint8_t *data; + int flags = 0x00; if (dev->f == NULL) return; @@ -394,16 +380,22 @@ imd_seek(int drive, int track) id[1] = (h & 0x40) ? h_map[actual_sector] : (h & 1); id[2] = real_sector; id[3] = (n == 0xFF) ? n_map[actual_sector] : n; - ssize = 128 << ((uint32_t) id[3]); data = dev->track_buffer[side] + track_buf_pos[side]; type = dev->buffer[dev->tracks[track][side].sector_data_offs[actual_sector]]; type = (type >> 1) & 7; - deleted = bad_crc = 0; - if ((type == 2) || (type == 4)) deleted = 1; - if ((type == 3) || (type == 4)) bad_crc = 1; + flags = 0x00; + if ((type == 2) || (type == 4)) + flags |= SECTOR_DELETED_DATA; + if ((type == 3) || (type == 4)) + flags |= SECTOR_CRC_ERROR; + + if (((flags & 0x02) || (id[3] > dev->tracks[track][side].max_sector_size)) && !fdd_get_turbo(drive)) + ssize = 3; + else + ssize = 128 << ((uint32_t) id[3]); sector_to_buffer(drive, track, side, data, actual_sector, ssize); - current_pos = d86f_prepare_sector(drive, side, current_pos, id, data, ssize, 22, track_gap3, deleted, bad_crc); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, data, ssize, 22, track_gap3, flags); track_buf_pos[side] += ssize; if (sector == 0) @@ -418,21 +410,28 @@ imd_seek(int drive, int track) id[1] = side; id[2] = xdf_disk_layout[xdf_type][is_trackx][xdf_sector].id.r; id[3] = is_trackx ? (id[2] & 7) : 2; - ssize = 128 << ((uint32_t) id[3]); ordered_pos = dev->xdf_ordered_pos[id[2]][side]; data = dev->track_buffer[side] + track_buf_pos[side]; type = dev->buffer[dev->tracks[track][side].sector_data_offs[ordered_pos]]; type = (type >> 1) & 7; - deleted = bad_crc = 0; - if ((type == 2) || (type == 4)) deleted = 1; - if ((type == 3) || (type == 4)) bad_crc = 1; + flags = 0x00; + if ((type == 2) || (type == 4)) + flags |= SECTOR_DELETED_DATA; + if ((type == 3) || (type == 4)) + flags |= SECTOR_CRC_ERROR; + + if (((flags & 0x02) || (id[3] > dev->tracks[track][side].max_sector_size)) && !fdd_get_turbo(drive)) + ssize = 3; + else + ssize = 128 << ((uint32_t) id[3]); + sector_to_buffer(drive, track, side, data, ordered_pos, ssize); if (is_trackx) - current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[xdf_type][xdf_sector], id, data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], deleted, bad_crc); - else - current_pos = d86f_prepare_sector(drive, side, current_pos, id, data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], deleted, bad_crc); + current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[xdf_type][xdf_sector], id, data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], flags); + else + current_pos = d86f_prepare_sector(drive, side, current_pos, id, data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], flags); track_buf_pos[side] += ssize; @@ -614,6 +613,8 @@ imd_load(int drive, wchar_t *fn) uint32_t minimum_gap3 = 0; uint32_t minimum_gap4 = 0; uint8_t converted_rate; + uint8_t type; + int size_diff, gap_sum; d86f_unregister(drive); @@ -642,12 +643,11 @@ imd_load(int drive, wchar_t *fn) if (magic != 0x20444D49) { imd_log("IMD: Not a valid ImageDisk image\n"); fclose(dev->f); - free(dev);; + free(dev); memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); return; - } else { + } else imd_log("IMD: Valid ImageDisk image\n"); - } fseek(dev->f, 0, SEEK_END); fsize = ftell(dev->f); @@ -714,6 +714,12 @@ imd_load(int drive, wchar_t *fn) dev->tracks[track][side].side_flags |= 0x20; if ((dev->tracks[track][side].side_flags & 7) == 1) dev->tracks[track][side].side_flags |= 0x20; + if ((dev->tracks[track][side].side_flags & 0x07) == 0x00) + dev->tracks[track][side].max_sector_size = 6; + else + dev->tracks[track][side].max_sector_size = 5; + if (!mfm) + dev->tracks[track][side].max_sector_size--; /* imd_log("Side flags for (%02i)(%01i): %02X\n", track, side, dev->tracks[track][side].side_flags); */ dev->tracks[track][side].is_present = 1; dev->tracks[track][side].file_offs = (buffer2 - buffer); @@ -748,7 +754,12 @@ imd_load(int drive, wchar_t *fn) last_offset += dev->tracks[track][side].sector_data_size[i]; if (!(buffer[dev->tracks[track][side].sector_data_offs[i]] & 1)) fwriteprot[drive] = writeprot[drive] = 1; - track_total += (pre_sector + data_size + 2); + type = dev->buffer[dev->tracks[track][side].sector_data_offs[i]]; + type = (type >> 1) & 7; + if ((type == 3) || (type == 4) || (data_size > (128 << dev->tracks[track][side].max_sector_size))) + track_total += (pre_sector + 3); + else + track_total += (pre_sector + data_size + 2); } } else { dev->tracks[track][side].data_offs = last_offset; @@ -763,7 +774,12 @@ imd_load(int drive, wchar_t *fn) last_offset += dev->tracks[track][side].sector_data_size[i]; if (!(buffer[dev->tracks[track][side].sector_data_offs[i]] & 1)) fwriteprot[drive] = writeprot[drive] = 1; - track_total += (pre_sector + data_size + 2); + type = dev->buffer[dev->tracks[track][side].sector_data_offs[i]]; + type = (type >> 1) & 7; + if ((type == 3) || (type == 4) || (sector_size > dev->tracks[track][side].max_sector_size)) + track_total += (pre_sector + 3); + else + track_total += (pre_sector + data_size + 2); } } buffer2 = buffer + last_offset; @@ -782,12 +798,15 @@ imd_load(int drive, wchar_t *fn) converted_rate = dev->tracks[track][side].side_flags & 0x03; if (gap3_sizes[converted_rate][sector_size][track_spt] == 0x00) { - if ((raw_tsize - track_total + (mfm ? 146 : 73)) < (minimum_gap3 + minimum_gap4)) { + size_diff = raw_tsize - track_total; + gap_sum = minimum_gap3 + minimum_gap4; + if (size_diff < gap_sum) { /* If we can't fit the sectors with a reasonable minimum gap at perfect RPM, let's try 2% slower. */ raw_tsize = get_raw_tsize(dev->tracks[track][side].side_flags, 1); /* Set disk flags so that rotation speed is 2% slower. */ dev->disk_flags |= (3 << 5); - if ((raw_tsize - track_total + (mfm ? 146 : 73)) < (minimum_gap3 + minimum_gap4)) { + size_diff = raw_tsize - track_total; + if (size_diff < gap_sum) { /* If we can't fit the sectors with a reasonable minimum gap even at 2% slower RPM, abort. */ imd_log("IMD: Unable to fit the %i sectors in a track\n", track_spt); fclose(dev->f); @@ -798,7 +817,7 @@ imd_load(int drive, wchar_t *fn) } } - dev->tracks[track][side].gap3_len = (raw_tsize - track_total - minimum_gap4 + (mfm ? 146 : 73)) / track_spt; + dev->tracks[track][side].gap3_len = (size_diff - minimum_gap4) / track_spt; } else if (gap3_sizes[converted_rate][sector_size][track_spt] != 0x00) dev->tracks[track][side].gap3_len = gap3_sizes[converted_rate][sector_size][track_spt]; diff --git a/src/floppy/fdd_imd.h b/src/floppy/fdd_imd.h index 4e16bd096..02363a64a 100644 --- a/src/floppy/fdd_imd.h +++ b/src/floppy/fdd_imd.h @@ -1,20 +1,20 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Definitions for the IMD floppy image format. * * Version: @(#)floppy_imd.h 1.0.2 2018/03/17 * - * Authors: Fred N. van Kempen, - * Miran Grca, + * Authors: Miran Grca, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. * Copyright 2016-2018 Miran Grca. + * Copyright 2018 Fred N. van Kempen. * * 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 diff --git a/src/floppy/fdd_img.c b/src/floppy/fdd_img.c index 09bd27655..5e0bfaacd 100644 --- a/src/floppy/fdd_img.c +++ b/src/floppy/fdd_img.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the raw sector-based floppy image format, * as well as the Japanese FDI, CopyQM, and FDF formats. @@ -13,33 +13,15 @@ * re-merged with the other files. Much of it is generic to * all formats. * - * Version: @(#)fdd_img.c 1.0.8 2018/05/09 + * Version: @(#)fdd_img.c 1.0.10 2018/12/05 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #include #include @@ -49,9 +31,11 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../config.h" #include "../plat.h" #include "fdd.h" +#include "fdd_86f.h" #include "fdd_img.h" #include "fdc.h" @@ -301,13 +285,11 @@ const int gap3_sizes[5][8][48] = { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, #ifdef ENABLE_IMG_LOG int img_do_log = ENABLE_IMG_LOG; -#endif static void img_log(const char *fmt, ...) { -#ifdef ENABLE_IMG_LOG va_list ap; if (img_do_log) @@ -316,8 +298,10 @@ img_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define img_log(fmt, ...) +#endif /* Generic */ @@ -553,7 +537,7 @@ img_seek(int drive, int track) id[3] = dev->sector_size; dev->sector_pos_side[side][sr] = side; dev->sector_pos[side][sr] = (sr - 1) * ssize; - current_pos = d86f_prepare_sector(drive, side, current_pos, id, &dev->track_data[side][(sr - 1) * ssize], ssize, dev->gap2_size, dev->gap3_size, 0, 0); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, &dev->track_data[side][(sr - 1) * ssize], ssize, dev->gap2_size, dev->gap3_size, 0); if (sector == 0) d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]); @@ -598,11 +582,11 @@ img_seek(int drive, int track) if (is_t0) { id[3] = 2; - current_pos = d86f_prepare_sector(drive, side, current_pos, id, &dev->track_data[buf_side][buf_pos], ssize, dev->gap2_size, xdf_gap3_sizes[current_xdft][!is_t0], 0, 0); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, &dev->track_data[buf_side][buf_pos], ssize, dev->gap2_size, xdf_gap3_sizes[current_xdft][!is_t0], 0); } else { id[3] = id[2] & 7; ssize = (128 << id[3]); - current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[current_xdft][array_sector], id, &dev->track_data[buf_side][buf_pos], ssize, dev->gap2_size, xdf_gap3_sizes[current_xdft][!is_t0], 0, 0); + current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[current_xdft][array_sector], id, &dev->track_data[buf_side][buf_pos], ssize, dev->gap2_size, xdf_gap3_sizes[current_xdft][!is_t0], 0); } if (sector == 0) @@ -620,6 +604,16 @@ img_init(void) } +int +is_divisible(uint16_t total, uint8_t what) +{ + if ((total != 0) && (what != 0)) + return ((total % what) == 0); + else + return 0; +} + + void img_load(int drive, wchar_t *fn) { @@ -968,10 +962,13 @@ jump_if_fdf: img_log("BPB reports %i sides and %i bytes per sector (%i sectors total)\n", bpb_sides, bpb_bps, bpb_total); - guess = (bpb_sides < 1); - guess = guess || (bpb_sides > 2); - guess = guess || !bps_is_valid(bpb_bps); - guess = guess || !first_byte_is_valid(first_byte); + /* Invalid conditions: */ + guess = (bpb_sides < 1); /* Sides < 1; */ + guess = guess || (bpb_sides > 2); /* Sides > 2; */ + guess = guess || !bps_is_valid(bpb_bps); /* Invalid number of bytes per sector; */ + guess = guess || !first_byte_is_valid(first_byte); /* Invalid first bytes; */ + guess = guess || !is_divisible(bpb_total, bpb_sectors); /* Total sectors not divisible by sectors per track; */ + guess = guess || !is_divisible(bpb_total, bpb_sides); /* Total sectors not divisible by sides. */ guess = guess || !fdd_get_check_bpb(drive); guess = guess && !fdi; guess = guess && !cqm; diff --git a/src/floppy/fdd_img.h b/src/floppy/fdd_img.h index b5bddb4ad..dde817dab 100644 --- a/src/floppy/fdd_img.h +++ b/src/floppy/fdd_img.h @@ -1,41 +1,23 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the raw sector-based floppy image format, * as well as the Japanese FDI, CopyQM, and FDF formats. * * Version: @(#)floppy_img.h 1.0.2 2018/03/17 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 Fred N. van Kempen. */ #ifndef EMU_FLOPPY_IMG_H # define EMU_FLOPPY_IMG_H diff --git a/src/floppy/fdd_json.c b/src/floppy/fdd_json.c index c56bbd80d..d194b811d 100644 --- a/src/floppy/fdd_json.c +++ b/src/floppy/fdd_json.c @@ -8,11 +8,11 @@ * * Implementation of the PCjs JSON floppy image format. * - * Version: @(#)fdd_json.c 1.0.5 2018/04/29 + * Version: @(#)fdd_json.c 1.0.7 2019/12/05 * * Author: Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -52,8 +52,10 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../plat.h" #include "fdd.h" +#include "fdd_86f.h" #include "fdc.h" #include "fdd_common.h" #include "fdd_json.h" @@ -108,13 +110,11 @@ static json_t *images[FDD_NUM]; #ifdef ENABLE_JSON_LOG int json_do_log = ENABLE_JSON_LOG; -#endif static void json_log(const char *fmt, ...) { -#ifdef ENABLE_JSON_LOG va_list ap; if (json_do_log) @@ -123,8 +123,10 @@ json_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define json_log(fmt, ...) +#endif static void @@ -455,8 +457,7 @@ json_seek(int drive, int track) drive, side, pos, id, dev->sects[track][side][asec].data, ssize, gap2, gap3, - 0, /*deleted flag*/ - 0 /*bad_crc flag*/ + 0 /*flags*/ ); if (sector == 0) diff --git a/src/floppy/fdd_mfm.c b/src/floppy/fdd_mfm.c new file mode 100644 index 000000000..879bc200e --- /dev/null +++ b/src/floppy/fdd_mfm.c @@ -0,0 +1,522 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the HxC MFM image format. + * + * Version: @(#)fdd_mfm.c 1.0.2 2019/12/05 + * + * Authors: Miran Grca, + * + * Copyright 2018,2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../timer.h" +#include "../plat.h" +#include "fdd.h" +#include "fdd_86f.h" +#include "fdd_img.h" +#include "fdd_mfm.h" +#include "fdc.h" + + +#pragma pack(push,1) +typedef struct { + uint8_t hdr_name[7]; + + uint16_t tracks_no; + uint8_t sides_no; + + uint16_t rpm; + uint16_t bit_rate; + uint8_t if_type; + + uint32_t track_list_offset; +} mfm_header_t; + +typedef struct { + uint16_t track_no; + uint8_t side_no; + uint32_t track_size; + uint32_t track_offset; +} mfm_track_t; + +typedef struct { + uint16_t track_no; + uint8_t side_no; + uint16_t rpm; + uint16_t bit_rate; + uint32_t track_size; + uint32_t track_offset; +} mfm_adv_track_t; +#pragma pack(pop) + +typedef struct { + FILE *f; + + mfm_header_t hdr; + mfm_track_t *tracks; + mfm_adv_track_t *adv_tracks; + + uint16_t disk_flags, pad; + uint16_t side_flags[2]; + + int br_rounded, rpm_rounded, + total_tracks, cur_track; + + uint8_t track_data[2][256*1024]; +} mfm_t; + + +static mfm_t *mfm[FDD_NUM]; +static fdc_t *mfm_fdc; + + +#ifdef ENABLE_MFM_LOG +int mfm_do_log = ENABLE_MFM_LOG; + + +static void +mfm_log(const char *fmt, ...) +{ + va_list ap; + + if (mfm_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define mfm_log(fmt, ...) +#endif + + +static int +get_track_index(int drive, int side, int track) +{ + mfm_t *dev = mfm[drive]; + int i, ret = -1; + + for (i = 0; i < dev->total_tracks; i++) { + if ((dev->tracks[i].track_no == track) && + (dev->tracks[i].side_no == side)) { + ret = i; + break; + } + } + + return ret; +} + + +static int +get_adv_track_index(int drive, int side, int track) +{ + mfm_t *dev = mfm[drive]; + int i, ret = -1; + + for (i = 0; i < dev->total_tracks; i++) { + if ((dev->adv_tracks[i].track_no == track) && + (dev->adv_tracks[i].side_no == side)) { + ret = i; + break; + } + } + + return ret; +} + + +static void +get_adv_track_bitrate(int drive, int side, int track, int *br, int *rpm) +{ + mfm_t *dev = mfm[drive]; + int track_index; + double dbr; + + track_index = get_adv_track_index(drive, side, track); + + if (track_index == -1) { + *br = 250; + *rpm = 300; + } else { + dbr = round(((double) dev->adv_tracks[track_index].bit_rate) / 50.0) * 50.0; + *br = ((int) dbr); + dbr = round(((double) dev->adv_tracks[track_index].rpm) / 60.0) * 60.0; + *rpm = ((int) dbr); + } +} + + +static void +set_disk_flags(int drive) +{ + int br = 250, rpm = 300; + mfm_t *dev = mfm[drive]; + uint16_t temp_disk_flags = 0x1080; /* We ALWAYS claim to have extra bit cells, even if the actual amount is 0; + Bit 12 = 1, bits 6, 5 = 0 - extra bit cells field specifies the entire + amount of bit cells per track. */ + + /* If this is the modified MFM format, get bit rate (and RPM) from track 0 instead. */ + if (dev->hdr.if_type & 0x80) + get_adv_track_bitrate(drive, 0, 0, &br, &rpm); + else { + br = dev->br_rounded; + rpm = dev->rpm_rounded; + } + + switch (br) { + case 500: + temp_disk_flags |= 2; + break; + + case 300: + case 250: + default: + temp_disk_flags |= 0; + break; + + case 1000: + temp_disk_flags |= 4; + break; + } + + if (dev->hdr.sides_no == 2) + temp_disk_flags |= 8; + + dev->disk_flags = temp_disk_flags; +} + + +static uint16_t +disk_flags(int drive) +{ + mfm_t *dev = mfm[drive]; + + return dev->disk_flags; +} + + +static void +set_side_flags(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + uint16_t temp_side_flags = 0; + int br = 250, rpm = 300; + + if (dev->hdr.if_type & 0x80) + get_adv_track_bitrate(drive, side, dev->cur_track, &br, &rpm); + else { + br = dev->br_rounded; + rpm = dev->rpm_rounded; + } + + /* 300 kbps @ 360 rpm = 250 kbps @ 200 rpm */ + if ((br == 300) && (rpm == 360)) { + br = 250; + rpm = 300; + } + + switch (br) { + case 500: + temp_side_flags = 0; + break; + + case 300: + temp_side_flags = 1; + break; + + case 250: + default: + temp_side_flags = 2; + break; + + case 1000: + temp_side_flags = 3; + break; + } + + if (rpm == 360) + temp_side_flags |= 0x20; + + /* + * Set the encoding value to match that provided by the FDC. + * Then if it's wrong, it will sector not found anyway. + */ + temp_side_flags |= 0x08; + + dev->side_flags[side] = temp_side_flags; +} + + +static uint16_t +side_flags(int drive) +{ + mfm_t *dev = mfm[drive]; + int side; + + side = fdd_get_head(drive); + + return dev->side_flags[side]; +} + + +static uint32_t +get_raw_size(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int track_index, is_300_rpm; + int br = 250, rpm = 300; + + if (dev->hdr.if_type & 0x80) { + track_index = get_adv_track_index(drive, side, dev->cur_track); + get_adv_track_bitrate(drive, 0, 0, &br, &rpm); + } else { + track_index = get_track_index(drive, side, dev->cur_track); + br = dev->br_rounded; + rpm = dev->rpm_rounded; + } + + is_300_rpm = (rpm == 300); + + if (track_index == -1) { + mfm_log("MFM: Unable to find track (%i, %i)\n", dev->cur_track, side); + switch (br) { + case 250: + default: + return is_300_rpm ? 100000 : 83333; + case 300: + return is_300_rpm ? 120000 : 100000; + case 500: + return is_300_rpm ? 200000 : 166666; + case 1000: + return is_300_rpm ? 400000 : 333333; + } + } + + /* Bit 7 on - my extension of the HxC MFM format to output exact bitcell counts + for each track instead of rounded byte counts. */ + if (dev->hdr.if_type & 0x80) + return dev->adv_tracks[track_index].track_size; + else + return dev->tracks[track_index].track_size * 8; +} + + +static int32_t +extra_bit_cells(int drive, int side) +{ + return (int32_t) get_raw_size(drive, side); +} + + +static uint16_t * +encoded_data(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + + return((uint16_t *)dev->track_data[side]); +} + + +void +mfm_read_side(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int track_index, track_size; + int track_bytes; + + if (dev->hdr.if_type & 0x80) + track_index = get_adv_track_index(drive, side, dev->cur_track); + else + track_index = get_track_index(drive, side, dev->cur_track); + + track_size = get_raw_size(drive, side); + track_bytes = track_size >> 3; + if (track_size & 0x07) + track_bytes++; + + if (track_index == -1) + memset(dev->track_data[side], 0x00, track_bytes); + else { + if (dev->hdr.if_type & 0x80) + fseek(dev->f, dev->adv_tracks[track_index].track_offset, SEEK_SET); + else + fseek(dev->f, dev->tracks[track_index].track_offset, SEEK_SET); + fread(dev->track_data[side], 1, track_bytes, dev->f); + } + + mfm_log("drive = %i, side = %i, dev->cur_track = %i, track_index = %i, track_size = %i\n", + drive, side, dev->cur_track, track_index, track_size); +} + + +void +mfm_seek(int drive, int track) +{ + mfm_t *dev = mfm[drive]; + + mfm_log("mfm_seek(%i, %i)\n", drive, track); + + if (fdd_doublestep_40(drive)) { + if (dev->hdr.tracks_no <= 43) + track /= 2; + } + + dev->cur_track = track; + d86f_set_cur_track(drive, track); + + if (dev->f == NULL) + return; + + if (track < 0) + track = 0; + + mfm_read_side(drive, 0); + mfm_read_side(drive, 1); + + set_side_flags(drive, 0); + set_side_flags(drive, 1); +} + + +void +mfm_load(int drive, wchar_t *fn) +{ + mfm_t *dev; + double dbr; + int i; + + writeprot[drive] = fwriteprot[drive] = 1; + + /* Allocate a drive block. */ + dev = (mfm_t *)malloc(sizeof(mfm_t)); + memset(dev, 0x00, sizeof(mfm_t)); + + dev->f = plat_fopen(fn, L"rb"); + if (dev->f == NULL) { + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + + d86f_unregister(drive); + + /* Read the header. */ + fread(&dev->hdr, 1, sizeof(mfm_header_t), dev->f); + + /* Calculate tracks * sides, allocate the tracks array, and read it. */ + dev->total_tracks = dev->hdr.tracks_no * dev->hdr.sides_no; + if (dev->hdr.if_type & 0x80) { + dev->adv_tracks = (mfm_adv_track_t *) malloc(dev->total_tracks * sizeof(mfm_adv_track_t)); + fread(dev->adv_tracks, 1, dev->total_tracks * sizeof(mfm_adv_track_t), dev->f); + } else { + dev->tracks = (mfm_track_t *) malloc(dev->total_tracks * sizeof(mfm_track_t)); + fread(dev->tracks, 1, dev->total_tracks * sizeof(mfm_track_t), dev->f); + } + + /* The chances of finding a HxC MFM image of a single-sided thin track + disk are much smaller than the chances of finding a HxC MFM image + incorrectly converted from a SCP image, erroneously indicating 1 + side and 80+ tracks instead of 2 sides and <= 43 tracks, so if we + have detected such an image, convert the track numbers. */ + if ((dev->hdr.tracks_no > 43) && (dev->hdr.sides_no == 1)) { + dev->hdr.tracks_no >>= 1; + dev->hdr.sides_no <<= 1; + + for (i = 0; i < dev->total_tracks; i++) { + if (dev->hdr.if_type & 0x80) { + dev->adv_tracks[i].side_no <<= 1; + dev->adv_tracks[i].side_no |= (dev->adv_tracks[i].track_no & 1); + dev->adv_tracks[i].track_no >>= 1; + } else { + dev->tracks[i].side_no <<= 1; + dev->tracks[i].side_no |= (dev->tracks[i].track_no & 1); + dev->tracks[i].track_no >>= 1; + } + } + } + + if (!(dev->hdr.if_type & 0x80)) { + dbr = round(((double) dev->hdr.bit_rate) / 50.0) * 50.0; + dev->br_rounded = (int) dbr; + mfm_log("Rounded bit rate: %i kbps\n", dev->br_rounded); + + dbr = round(((double) dev->hdr.rpm) / 60.0) * 60.0; + dev->rpm_rounded = (int) dbr; + mfm_log("Rounded RPM: %i kbps\n", dev->rpm_rounded); + } + + /* Set up the drive unit. */ + mfm[drive] = dev; + + set_disk_flags(drive); + + /* Attach this format to the D86F engine. */ + d86f_handler[drive].disk_flags = disk_flags; + d86f_handler[drive].side_flags = side_flags; + d86f_handler[drive].writeback = null_writeback; + d86f_handler[drive].set_sector = null_set_sector; + d86f_handler[drive].write_data = null_write_data; + d86f_handler[drive].format_conditions = null_format_conditions; + d86f_handler[drive].extra_bit_cells = extra_bit_cells; + d86f_handler[drive].encoded_data = encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = null_index_hole_pos; + d86f_handler[drive].get_raw_size = get_raw_size; + d86f_handler[drive].check_crc = 1; + d86f_set_version(drive, D86FVER); + + d86f_common_handlers(drive); + + drives[drive].seek = mfm_seek; + + mfm_log("Loaded as MFM\n"); +} + + +void +mfm_close(int drive) +{ + mfm_t *dev = mfm[drive]; + + if (dev == NULL) return; + + d86f_unregister(drive); + + drives[drive].seek = NULL; + + if (dev->tracks) + free(dev->tracks); + + if (dev->adv_tracks) + free(dev->adv_tracks); + + if (dev->f) + fclose(dev->f); + + /* Release the memory. */ + free(dev); + mfm[drive] = NULL; +} + + +void +mfm_set_fdc(void *fdc) +{ + mfm_fdc = (fdc_t *)fdc; +} diff --git a/src/floppy/fdd_mfm.h b/src/floppy/fdd_mfm.h new file mode 100644 index 000000000..2aba3fb47 --- /dev/null +++ b/src/floppy/fdd_mfm.h @@ -0,0 +1,26 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the HxC MFM image format. + * + * Version: @(#)fdd_mfm.h 1.0.0 2018/11/12 + * + * Authors: Miran Grca, + * + * Copyright 2018 Miran Grca. + */ +#ifndef EMU_FLOPPY_MFM_H +# define EMU_FLOPPY_MFM_H + + +extern void mfm_seek(int drive, int track); +extern void mfm_load(int drive, wchar_t *fn); +extern void mfm_close(int drive); + + +#endif /*EMU_FLOPPY_MFM_H*/ diff --git a/src/floppy/fdd_td0.c b/src/floppy/fdd_td0.c index f956e9421..fd4d4419f 100644 --- a/src/floppy/fdd_td0.c +++ b/src/floppy/fdd_td0.c @@ -1,50 +1,32 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the Teledisk floppy image format. * - * Version: @(#)fdd_td0.c 1.0.6 2018/04/29 + * Version: @(#)fdd_td0.c 1.0.10 2019/12/06 * - * Authors: Fred N. van Kempen, - * Miran Grca, - * Milodrag Milanovic, + * Authors: Milodrag Milanovic, * Haruhiko OKUMURA, * Haruyasu YOSHIZAKI, * Kenji RIKITAKE, + * Miran Grca, + * Fred N. van Kempen, * * Based on Japanese version 29-NOV-1988 * LZSS coded by Haruhiko OKUMURA * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI * Edited and translated to English by Kenji RIKITAKE * - * Copyright 2016-2018 Miran Grca. - * Copyright 2013-2018 Milodrag Milanovic. - * Copyright 1988-2018 Haruhiko OKUMURA. - * Copyright 1988-2018 Haruyasu YOSHIZAKI. - * Copyright 1988-2018 Kenji RIKITAKE. - * - * 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. + * Copyright 2013-2019 Milodrag Milanovic. + * Copyright 1988-2019 Haruhiko OKUMURA. + * Copyright 1988-2019 Haruyasu YOSHIZAKI. + * Copyright 1988-2019 Kenji RIKITAKE. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -54,8 +36,10 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../plat.h" #include "fdd.h" +#include "fdd_86f.h" #include "fdd_td0.h" #include "fdc.h" @@ -112,8 +96,8 @@ typedef struct { uint8_t head; uint8_t sector; uint8_t size; - uint8_t deleted; - uint8_t bad_crc; + uint8_t flags; + uint8_t fm; uint8_t *data; } td0_sector_t; @@ -126,6 +110,7 @@ typedef struct { uint16_t disk_flags; uint16_t default_track_flags; uint16_t side_flags[256][2]; + uint8_t max_sector_size; uint8_t track_in_file[256][2]; td0_sector_t sects[256][2][256]; uint8_t track_spt[256][2]; @@ -222,13 +207,11 @@ static td0_t *td0[FDD_NUM]; #ifdef ENABLE_TD0_LOG int td0_do_log = ENABLE_TD0_LOG; -#endif static void td0_log(const char *fmt, ...) { -#ifdef ENABLE_TD0_LOG va_list ap; if (td0_do_log) @@ -237,8 +220,10 @@ td0_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define td0_log(fmt, ...) +#endif static void @@ -387,9 +372,11 @@ state_reconst(td0dsk_t *state) k++; l = (j - k) * 2; - memcpy(&state->freq[k + 1], &state->freq[k], l); + /* These *HAVE* to be memmove's as destination and source + can overlap, which memcpy can't handle. */ + memmove(&state->freq[k + 1], &state->freq[k], l); state->freq[k] = f; - memcpy(&state->son[k + 1], &state->son[k], l); + memmove(&state->son[k + 1], &state->son[k], l); state->son[k] = i; } @@ -615,7 +602,7 @@ td0_initialize(int drive) int fm, head, track; int track_count = 0; int head_count = 0; - int track_spt; + int track_spt, track_spt_adjusted; int offset = 0; int density = 0; int temp_rate = 0; @@ -626,12 +613,14 @@ td0_initialize(int drive) uint16_t size; uint8_t *dbuf = dev->processed_buf; uint32_t total_size = 0; + uint32_t id_field = 0; uint32_t pre_sector = 0; - uint32_t track_size = 0; - uint32_t raw_tsize = 0; + int32_t track_size = 0; + int32_t raw_tsize = 0; uint32_t minimum_gap3 = 0; uint32_t minimum_gap4 = 0; int i, j, k; + int size_diff, gap_sum; if (dev->f == NULL) { td0_log("TD0: Attempted to initialize without loading a file first\n"); @@ -696,19 +685,23 @@ td0_initialize(int drive) case 2: /* 5.25" 1.2M 360 rpm */ case 5: /* 8"/5.25"/3.5" 1.25M 360 rpm */ dev->default_track_flags = (density == 1) ? 0x20 : 0x21; + dev->max_sector_size = (density == 1) ? 6 : 5; /* 8192 or 4096 bytes. */ break; case 1: /* 5.25" 360k: 300 rpm */ case 3: /* 3.5" 720k: 300 rpm */ dev->default_track_flags = 0x02; + dev->max_sector_size = 5; /* 4096 bytes. */ break; case 4: /* 3.5" 1.44M: 300 rpm */ dev->default_track_flags = (density == 1) ? 0x00 : 0x02; + dev->max_sector_size = (density == 1) ? 6 : 5; /* 8192 or 4096 bytes. */ break; case 6: /* 3.5" 2.88M: 300 rpm */ dev->default_track_flags = (density == 1) ? 0x00 : ((density == 2) ? 0x03 : 0x02); + dev->max_sector_size = (density == 1) ? 6 : ((density == 2) ? 7 : 5); /* 16384, 8192, or 4096 bytes. */ break; } @@ -725,6 +718,8 @@ td0_initialize(int drive) } while (track_spt != 255) { + track_spt_adjusted = track_spt; + track = dev->imagebuf[offset + 1]; head = dev->imagebuf[offset + 2] & 1; fm = (header[5] & 0x80) || (dev->imagebuf[offset + 2] & 0x80); /* ? */ @@ -732,7 +727,11 @@ td0_initialize(int drive) dev->track_in_file[track][head] = 1; offset += 4; track_size = fm ? 73 : 146; - pre_sector = fm ? 42 : 60; + if (density == 2) + id_field = fm ? 54 : 63; + else + id_field = fm ? 35 : 44; + pre_sector = id_field + (fm ? 7 : 16); for (i = 0; i < track_spt; i++) { hs = &dev->imagebuf[offset]; @@ -742,8 +741,8 @@ td0_initialize(int drive) dev->sects[track][head][i].head = hs[1]; dev->sects[track][head][i].sector = hs[2]; dev->sects[track][head][i].size = hs[3]; - dev->sects[track][head][i].deleted = (hs[4] & 4) == 4; - dev->sects[track][head][i].bad_crc = (hs[4] & 2) == 2; + dev->sects[track][head][i].flags = hs[4]; + dev->sects[track][head][i].fm = !!fm; dev->sects[track][head][i].data = dbuf; size = 128 << hs[3]; @@ -752,13 +751,13 @@ td0_initialize(int drive) return(0); } - if (hs[4] & 0x30) { - memset(dbuf, 0, size); - } else { + if (hs[4] & 0x30) + memset(dbuf, (hs[4] & 0x10) ? 0xf6 : 0x00, size); + else { offset += 3; switch (hs[8]) { default: - td0_log("TD0: Image uses an unsupported sector data encoding\n"); + td0_log("TD0: Image uses an unsupported sector data encoding: %i\n", hs[8]); return(0); case 0: @@ -804,7 +803,18 @@ td0_initialize(int drive) dbuf += size; total_size += size; - track_size += (pre_sector + size + 2); + + if (hs[4] & 0x20) { + track_size += id_field; + track_spt_adjusted--; + } else if (hs[4] & 0x40) + track_size += (pre_sector - id_field + 3); + else { + if ((hs[4] & 0x02) || (hs[3] > (dev->max_sector_size - fm))) + track_size += (pre_sector + 3); + else + track_size += (pre_sector + size + 2); + } } if (track > track_count) @@ -813,24 +823,26 @@ td0_initialize(int drive) if (track_spt != 255) { dev->track_spt[track][head] = track_spt; - if ((dev->track_spt[track][head] == 8) && (dev->sects[track][head][0].size == 3)) { - dev->side_flags[track][head] |= 0x20; - } + if ((dev->track_spt[track][head] == 8) && (dev->sects[track][head][0].size == 3)) + dev->side_flags[track][head] = (dev->side_flags[track][head] & ~0x67) | 0x20; raw_tsize = get_raw_tsize(dev->side_flags[track][head], 0); - minimum_gap3 = 12 * track_spt; - if ((raw_tsize - track_size + (fm ? 73 : 146)) < (minimum_gap3 + minimum_gap4)) { + minimum_gap3 = 12 * track_spt_adjusted; + size_diff = raw_tsize - track_size; + gap_sum = minimum_gap3 + minimum_gap4; + if (size_diff < gap_sum) { /* If we can't fit the sectors with a reasonable minimum gap at perfect RPM, let's try 2% slower. */ raw_tsize = get_raw_tsize(dev->side_flags[track][head], 1); /* Set disk flags so that rotation speed is 2% slower. */ dev->disk_flags |= (3 << 5); - if ((raw_tsize - track_size + (fm ? 73 : 146)) < (minimum_gap3 + minimum_gap4)) { + size_diff = raw_tsize - track_size; + if ((size_diff < gap_sum) && !fdd_get_turbo(drive)) { /* If we can't fit the sectors with a reasonable minimum gap even at 2% slower RPM, abort. */ - td0_log("TD0: Unable to fit the %i sectors in a track\n", track_spt); + td0_log("TD0: Unable to fit the %i sectors into drive %i, track %i, side %i\n", track_spt_adjusted, drive, track, head); return 0; } } - dev->calculated_gap3_lengths[track][head] = (raw_tsize - track_size - minimum_gap4 + (fm ? 73 : 146)) / track_spt; + dev->calculated_gap3_lengths[track][head] = (size_diff - minimum_gap4) / track_spt_adjusted; track_spt = dev->imagebuf[offset]; } @@ -1043,6 +1055,7 @@ td0_seek(int drive, int track) int ordered_pos = 0; int real_sector = 0; int actual_sector = 0; + int fm, sector_adjusted; if (dev->f == NULL) return; @@ -1070,8 +1083,11 @@ td0_seek(int drive, int track) for (side = 0; side < dev->sides; side++) { track_rate = dev->current_side_flags[side] & 7; + /* Make sure 300 kbps @ 360 rpm is treated the same as 250 kbps @ 300 rpm. */ if (!track_rate && (dev->current_side_flags[side] & 0x20)) track_rate = 4; + if ((dev->current_side_flags[side] & 0x27) == 0x21) + track_rate = 2; track_gap3 = gap3_sizes[track_rate][dev->sects[track][side][0].size][dev->track_spt[track][side]]; if (! track_gap3) track_gap3 = dev->calculated_gap3_lengths[track][side]; @@ -1083,6 +1099,7 @@ td0_seek(int drive, int track) interleave_type = track_is_interleave(drive, side, track); current_pos = d86f_prepare_pretrack(drive, side, 0); + sector_adjusted = 0; if (! xdf_type) { for (sector = 0; sector < dev->track_spt[track][side]; sector++) { @@ -1098,11 +1115,18 @@ td0_seek(int drive, int track) id[1] = dev->sects[track][side][actual_sector].head; id[2] = real_sector; id[3] = dev->sects[track][side][actual_sector].size; - ssize = 128 << ((uint32_t) dev->sects[track][side][actual_sector].size); - current_pos = d86f_prepare_sector(drive, side, current_pos, id, dev->sects[track][side][actual_sector].data, ssize, track_gap2, track_gap3, dev->sects[track][side][actual_sector].deleted, dev->sects[track][side][actual_sector].bad_crc); + fm = dev->sects[track][side][actual_sector].fm; + if (((dev->sects[track][side][actual_sector].flags & 0x42) || (id[3] > (dev->max_sector_size - fm))) && !fdd_get_turbo(drive)) + ssize = 3; + else + ssize = 128 << ((uint32_t) id[3]); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, dev->sects[track][side][actual_sector].data, ssize, track_gap2, track_gap3, dev->sects[track][side][actual_sector].flags); - if (sector == 0) + if (sector_adjusted == 0) d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]); + + if (!(dev->sects[track][side][actual_sector].flags & 0x40)) + sector_adjusted++; } } else { xdf_type--; @@ -1113,16 +1137,22 @@ td0_seek(int drive, int track) id[1] = side; id[2] = xdf_disk_layout[xdf_type][is_trackx][xdf_sector].id.r; id[3] = is_trackx ? (id[2] & 7) : 2; - ssize = 128 << ((uint32_t) id[3]); ordered_pos = dev->xdf_ordered_pos[id[2]][side]; - if (is_trackx) { - current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[xdf_type][xdf_sector], id, dev->sects[track][side][ordered_pos].data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], dev->sects[track][side][ordered_pos].deleted, dev->sects[track][side][ordered_pos].bad_crc); - } else { - current_pos = d86f_prepare_sector(drive, side, current_pos, id, dev->sects[track][side][ordered_pos].data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], dev->sects[track][side][ordered_pos].deleted, dev->sects[track][side][ordered_pos].bad_crc); - } + fm = dev->sects[track][side][ordered_pos].fm; + if (((dev->sects[track][side][ordered_pos].flags & 0x42) || (id[3] > (dev->max_sector_size - fm))) && !fdd_get_turbo(drive)) + ssize = 3; + else + ssize = 128 << ((uint32_t) id[3]); + if (is_trackx) + current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[xdf_type][xdf_sector], id, dev->sects[track][side][ordered_pos].data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], dev->sects[track][side][ordered_pos].flags); + else + current_pos = d86f_prepare_sector(drive, side, current_pos, id, dev->sects[track][side][ordered_pos].data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], dev->sects[track][side][ordered_pos].flags); - if (sector == 0) + if (sector_adjusted == 0) d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]); + + if (!(dev->sects[track][side][ordered_pos].flags & 0x40)) + sector_adjusted++; } } } @@ -1136,6 +1166,23 @@ td0_init(void) } +void +td0_abort(int drive) +{ + td0_t *dev = td0[drive]; + + if (dev->imagebuf) + free(dev->imagebuf); + if (dev->processed_buf) + free(dev->processed_buf); + if (dev->f) + fclose(dev->f); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + td0[drive] = NULL; +} + + void td0_load(int drive, wchar_t *fn) { @@ -1160,9 +1207,7 @@ td0_load(int drive, wchar_t *fn) if (! dsk_identify(drive)) { td0_log("TD0: Not a valid Teledisk image\n"); - fclose(dev->f); - dev->f = NULL; - memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + td0_abort(drive); return; } else { td0_log("TD0: Valid Teledisk image\n"); @@ -1177,10 +1222,7 @@ td0_load(int drive, wchar_t *fn) if (! td0_initialize(drive)) { td0_log("TD0: Failed to initialize\n"); - fclose(dev->f); - free(dev->imagebuf); - free(dev->processed_buf); - memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + td0_abort(drive); return; } else { td0_log("TD0: Initialized successfully\n"); @@ -1218,8 +1260,10 @@ td0_close(int drive) d86f_unregister(drive); - free(dev->imagebuf); - free(dev->processed_buf); + if (dev->imagebuf) + free(dev->imagebuf); + if (dev->processed_buf) + free(dev->processed_buf); for (i = 0; i < 256; i++) { for (j = 0; j < 2; j++) { diff --git a/src/floppy/fdd_td0.h b/src/floppy/fdd_td0.h index 8c3593241..e5a3525b9 100644 --- a/src/floppy/fdd_td0.h +++ b/src/floppy/fdd_td0.h @@ -1,38 +1,20 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Definitions for the Teledisk floppy image format. * * Version: @(#)floppy_td0.h 1.0.2 2018/03/17 * - * Authors: Fred N. van Kempen, - * Miran Grca, + * Authors: Miran Grca, + * Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. * Copyright 2016-2018 Miran Grca. - * - * 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. + * Copyright 2017,2018 Fred N. van Kempen. */ #ifndef EMU_FLOPPY_TD0_H # define EMU_FLOPPY_TD0_H diff --git a/src/floppy/fdi2raw.c b/src/floppy/fdi2raw.c index dee8dbfdf..b42ca2f1d 100644 --- a/src/floppy/fdi2raw.c +++ b/src/floppy/fdi2raw.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * FDI to raw bit stream converter * FDI format created by Vincent "ApH" Joguin @@ -12,7 +12,7 @@ * addition of get_last_head and C++ callability by Thomas * Harte. * - * Version: @(#)fdi2raw.c 1.0.3 2018/04/29 + * Version: @(#)fdi2raw.c 1.0.4 2018/10/18 * * Authors: Toni Wilen, * and Vincent Joguin, @@ -21,24 +21,6 @@ * Copyright 2001-2004 Toni Wilen. * Copyright 2001-2004 Vincent Joguin. * Copyright 2001 Thomas Harte. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. */ #define STATIC_INLINE #include @@ -66,13 +48,11 @@ #ifdef ENABLE_FDI2RAW_LOG int fdi2raw_do_log = ENABLE_FDI2RAW_LOG; -#endif static void fdi2raw_log(const char *fmt, ...) { -#ifdef ENABLE_FDI2RAW_LOG va_list ap; if (fdi2raw_do_log) @@ -81,10 +61,13 @@ fdi2raw_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define fdi2raw_log(fmt, ...) +#endif +#ifdef ENABLE_FDI2RAW_LOG #ifdef DEBUG static char *datalog(uae_u8 *src, int len) { @@ -110,6 +93,8 @@ static char *datalog(uae_u8 *src, int len) { return ""; } #endif static int fdi_allocated; +#endif + #ifdef DEBUG static void fdi_free (void *p) { @@ -1329,8 +1314,10 @@ static void fix_mfm_sync (FDI *fdi) static int handle_sectors_described_track (FDI *fdi) { +#ifdef ENABLE_FDI2RAW_LOG int oldout; uae_u8 *start_src = fdi->track_src ; +#endif fdi->encoding_type = *fdi->track_src++; fdi->index_offset = get_u32(fdi->track_src); fdi->index_offset >>= 8; @@ -1340,10 +1327,14 @@ static int handle_sectors_described_track (FDI *fdi) do { fdi->track_type = *fdi->track_src++; fdi2raw_log("%06.6X %06.6X %02.2X:",fdi->track_src - start_src + 0x200, fdi->out/8, fdi->track_type); +#ifdef ENABLE_FDI2RAW_LOG oldout = fdi->out; +#endif decode_sectors_described_track[fdi->track_type](fdi); fdi2raw_log(" %d\n", fdi->out - oldout); +#ifdef ENABLE_FDI2RAW_LOG oldout = fdi->out; +#endif if (fdi->out < 0 || fdi->err) { fdi2raw_log("\nin %d bytes, out %d bits\n", fdi->track_src - fdi->track_src_buffer, fdi->out); return -1; diff --git a/src/floppy/fdi2raw.h b/src/floppy/fdi2raw.h index 3c93ae2df..b00dfd5de 100644 --- a/src/floppy/fdi2raw.h +++ b/src/floppy/fdi2raw.h @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Definitions for the FDI floppy file format. * @@ -17,24 +17,6 @@ * Copyright 2001-2004 Toni Wilen. * Copyright 2001-2004 Vincent Joguin. * Copyright 2001 Thomas Harte. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. */ #ifndef __FDI2RAW_H #define __FDI2RAW_H diff --git a/src/game/gameport.c b/src/game/gameport.c index 53b9dac52..eb3eaf893 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -53,7 +53,7 @@ typedef struct { - int64_t count; + pc_timer_t timer; int axis_nr; struct _gameport_ *gameport; } g_axis_t; @@ -157,16 +157,17 @@ joystick_get_pov_name(int js, int id) } -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*/ + if (axis == AXIS_NOT_PRESENT) + 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*/ + } } @@ -175,17 +176,16 @@ gameport_write(uint16_t addr, uint8_t val, void *priv) { gameport_t *p = (gameport_t *)priv; - timer_clock(); p->state |= 0x0f; - p->axis[0].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 0)); - p->axis[1].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 1)); - p->axis[2].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 2)); - p->axis[3].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 3)); - + gameport_time(p, 0, p->joystick->read_axis(p->joystick_dat, 0)); + gameport_time(p, 1, p->joystick->read_axis(p->joystick_dat, 1)); + gameport_time(p, 2, p->joystick->read_axis(p->joystick_dat, 2)); + gameport_time(p, 3, p->joystick->read_axis(p->joystick_dat, 3)); + p->joystick->write(p->joystick_dat); - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); } @@ -195,10 +195,9 @@ gameport_read(uint16_t addr, void *priv) gameport_t *p = (gameport_t *)priv; uint8_t ret; - timer_clock(); ret = p->state | p->joystick->read(p->joystick_dat); - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); return(ret); } @@ -211,7 +210,6 @@ timer_over(void *priv) gameport_t *p = axis->gameport; p->state &= ~(1 << axis->axis_nr); - axis->count = 0; if (axis == &p->axis[0]) p->joystick->a0_over(p->joystick_dat); @@ -235,10 +233,10 @@ init_common(void) p->axis[2].axis_nr = 2; p->axis[3].axis_nr = 3; - timer_add(timer_over, &p->axis[0].count, &p->axis[0].count, &p->axis[0]); - timer_add(timer_over, &p->axis[1].count, &p->axis[1].count, &p->axis[1]); - timer_add(timer_over, &p->axis[2].count, &p->axis[2].count, &p->axis[2]); - timer_add(timer_over, &p->axis[3].count, &p->axis[3].count, &p->axis[3]); + timer_add(&p->axis[0].timer, timer_over, &p->axis[0], 0); + timer_add(&p->axis[1].timer, timer_over, &p->axis[1], 0); + timer_add(&p->axis[2].timer, timer_over, &p->axis[2], 0); + timer_add(&p->axis[3].timer, timer_over, &p->axis[3], 0); p->joystick = joystick_list[joystick_type]; p->joystick_dat = p->joystick->init(); diff --git a/src/game/gameport.h b/src/game/gameport.h index 3db999646..e1fec8fb8 100644 --- a/src/game/gameport.h +++ b/src/game/gameport.h @@ -10,7 +10,7 @@ * * NOTE: This module needs a good cleanup someday. * - * Version: @(#)gameport.h 1.0.3 2018/03/15 + * Version: @(#)gameport.h 1.0.4 2018/11/11 * * Authors: Miran Grca, * Sarah Walker, @@ -52,24 +52,24 @@ typedef struct { - char name[64]; + char name[260]; int a[8]; int b[32]; int p[4]; struct { - char name[32]; + char name[260]; int id; } axis[8]; struct { - char name[32]; + char name[260]; int id; } button[32]; struct { - char name[32]; + char name[260]; int id; } pov[4]; diff --git a/src/game/joystick_sw_pad.c b/src/game/joystick_sw_pad.c index feec60593..09030d8ad 100644 --- a/src/game/joystick_sw_pad.c +++ b/src/game/joystick_sw_pad.c @@ -69,47 +69,41 @@ typedef struct { - int64_t poll_time; - int64_t poll_left; - int64_t poll_clock; + pc_timer_t poll_timer; + int poll_left; + int poll_clock; uint64_t poll_data; - int64_t poll_mode; + int poll_mode; - int64_t trigger_time; - int64_t data_mode; + pc_timer_t trigger_timer; + int data_mode; } sw_data; static void sw_timer_over(void *p) { sw_data *sw = (sw_data *)p; - while (sw->poll_time <= 0 && sw->poll_left) - { - sw->poll_clock = !sw->poll_clock; - - if (sw->poll_clock) - { - sw->poll_data >>= (sw->poll_mode ? 3 : 1); - sw->poll_left--; - } + sw->poll_clock = !sw->poll_clock; - if (sw->poll_left == 1 && !sw->poll_clock) - sw->poll_time += TIMER_USEC * 160LL; - else if (sw->poll_left) - sw->poll_time += TIMER_USEC * 5; - else - sw->poll_time = 0; - } - - if (!sw->poll_left) - sw->poll_time = 0; + if (sw->poll_clock) + { + sw->poll_data >>= (sw->poll_mode ? 3 : 1); + sw->poll_left--; + } + + if (sw->poll_left == 1 && !sw->poll_clock) + timer_advance_u64(&sw->poll_timer, TIMER_USEC * 160); + else if (sw->poll_left) + timer_advance_u64(&sw->poll_timer, TIMER_USEC * 5); + else + timer_disable(&sw->poll_timer); } static void sw_trigger_timer_over(void *p) { sw_data *sw = (sw_data *)p; - sw->trigger_time = 0; + timer_disable(&sw->trigger_timer); } static int sw_parity(uint16_t data) @@ -130,9 +124,9 @@ static void *sw_init(void) 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; } @@ -151,7 +145,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; @@ -174,7 +168,7 @@ static uint8_t sw_read(void *p) static void sw_write(void *p) { sw_data *sw = (sw_data *)p; - int64_t time_since_last = sw->trigger_time / TIMER_USEC; + int64_t time_since_last = timer_get_remaining_us(&sw->trigger_timer); if (!JOYSTICK_PRESENT(0)) return; @@ -184,7 +178,7 @@ static void sw_write(void *p) if (!sw->poll_left) { sw->poll_clock = 1; - sw->poll_time = TIMER_USEC * 50; + timer_set_delay_u64(&sw->poll_timer, TIMER_USEC * 50); if (time_since_last > 9900 && time_since_last < 9940) { @@ -250,9 +244,7 @@ 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) @@ -260,14 +252,14 @@ static int sw_read_axis(void *p, int axis) if (!JOYSTICK_PRESENT(0)) return AXIS_NOT_PRESENT; - return 0LL; /*No analogue support on Sidewinder game pad*/ + return 0; /*No analogue support on Sidewinder game pad*/ } static void sw_a0_over(void *p) { sw_data *sw = (sw_data *)p; - sw->trigger_time = TIMER_USEC * 10000; + timer_set_delay_u64(&sw->trigger_timer, TIMER_USEC * 10000); } const joystick_if_t joystick_sw_pad = diff --git a/src/i82335.c b/src/i82335.c index b0043a1a5..37cf60306 100644 --- a/src/i82335.c +++ b/src/i82335.c @@ -42,7 +42,7 @@ void i82335_write(uint16_t addr, uint8_t val, void *priv) { for (i = 0; i < 8; i++) { - mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); shadowbios = 0; } } @@ -69,7 +69,7 @@ void i82335_write(uint16_t addr, uint8_t val, void *priv) { for (i = 0; i < 8; i++) { - mem_set_mem_state(0xc0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0xc0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); shadowbios = 0; } } @@ -90,8 +90,8 @@ void i82335_write(uint16_t addr, uint8_t val, void *priv) { for (i = 0; i < 8; i++) { - mem_write = (val & 8) ? MEM_WRITE_DISABLED : MEM_WRITE_EXTERNAL; - mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | mem_write); + mem_write = (val & 8) ? MEM_WRITE_DISABLED : MEM_WRITE_EXTANY; + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTANY | mem_write); shadowbios = 0; } } diff --git a/src/ibm_5161.c b/src/ibm_5161.c new file mode 100644 index 000000000..7cf6fed64 --- /dev/null +++ b/src/ibm_5161.c @@ -0,0 +1,114 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the IBM Expansion Unit (5161). + * + * Version: @(#)ibm_5161.c 1.0.0 2019/06/28 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "device.h" +#include "io.h" +#include "apm.h" +#include "dma.h" +#include "mem.h" +#include "pci.h" +#include "timer.h" +#include "pit.h" +#include "port_92.h" +#include "machine/machine.h" +#include "intel_sio.h" + + +typedef struct +{ + uint8_t regs[8]; +} ibm_5161_t; + + +static void +ibm_5161_out(uint16_t port, uint8_t val, void *priv) +{ + ibm_5161_t *dev = (ibm_5161_t *) priv; + + dev->regs[port & 0x0007] = val; +} + + +static uint8_t +ibm_5161_in(uint16_t port, void *priv) +{ + ibm_5161_t *dev = (ibm_5161_t *) priv; + uint8_t ret = 0xff; + + ret = dev->regs[port & 0x0007]; + + switch (port) { + case 0x211: + case 0x215: + ret = (get_last_addr() >> 8) & 0xff; + break; + case 0x212: + case 0x216: + ret = get_last_addr() & 0xff; + break; + case 0x213: + ret = dev->regs[3] & 0x01; + break; + } + + return ret; +} + + +static void +ibm_5161_close(void *p) +{ + ibm_5161_t *dev = (ibm_5161_t *) p; + + free(dev); +} + + +static void * +ibm_5161_init(const device_t *info) +{ + ibm_5161_t *dev = (ibm_5161_t *) malloc(sizeof(ibm_5161_t)); + memset(dev, 0, sizeof(ibm_5161_t)); + + /* Extender Card Registers */ + io_sethandler(0x0210, 0x0004, + ibm_5161_in, NULL, NULL, ibm_5161_out, NULL, NULL, dev); + + /* Receiver Card Registers */ + io_sethandler(0x0214, 0x0003, + ibm_5161_in, NULL, NULL, ibm_5161_out, NULL, NULL, dev); + + return dev; +} + + +const device_t ibm_5161_device = +{ + "IBM Expansion Unit (5161)", + 0, + 0, + ibm_5161_init, + ibm_5161_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/ibm_5161.h b/src/ibm_5161.h new file mode 100644 index 000000000..7ae1913d3 --- /dev/null +++ b/src/ibm_5161.h @@ -0,0 +1,15 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the IBM Expansion Unit (5161). + * + * Version: @(#)ibm_5161.h 1.0.0 2019/06/218 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ + +extern const device_t ibm_5161_device; diff --git a/src/intel.c b/src/intel.c deleted file mode 100644 index 327052780..000000000 --- a/src/intel.c +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include -#include -#include "cpu/cpu.h" -#include "machine/machine.h" -#include "io.h" -#include "mem.h" -#include "pit.h" -#include "timer.h" -#include "intel.h" - - -uint8_t batman_brdconfig(uint16_t port, void *p) -{ - switch (port) - { - case 0x73: - return 0xff; - case 0x75: - return 0xdf; - } - return 0; -} - -static uint16_t batman_timer_latch; -static int64_t batman_timer = 0; -static void batman_timer_over(void *p) -{ - batman_timer = 0; -} - -static void batman_timer_write(uint16_t addr, uint8_t val, void *p) -{ - if (addr & 1) - batman_timer_latch = (batman_timer_latch & 0xff) | (val << 8); - else - batman_timer_latch = (batman_timer_latch & 0xff00) | val; - batman_timer = batman_timer_latch * TIMER_USEC; -} - -static uint8_t batman_timer_read(uint16_t addr, void *p) -{ - uint16_t batman_timer_latch; - - cycles -= (int)PITCONST; - - timer_clock(); - - if (batman_timer < 0) - return 0; - - batman_timer_latch = batman_timer / TIMER_USEC; - - if (addr & 1) - return batman_timer_latch >> 8; - return batman_timer_latch & 0xff; -} - -void intel_batman_init() -{ - io_sethandler(0x0073, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); - io_sethandler(0x0075, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); - - io_sethandler(0x0078, 0x0002, batman_timer_read, NULL, NULL, batman_timer_write, NULL, NULL, NULL); - timer_add(batman_timer_over, &batman_timer, &batman_timer, NULL); -} diff --git a/src/intel.h b/src/intel.h deleted file mode 100644 index d2603bcbd..000000000 --- a/src/intel.h +++ /dev/null @@ -1,5 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -extern void intel_batman_init(void); -extern void intel_endeavor_init(void); diff --git a/src/intel_flash.c b/src/intel_flash.c index a619212ac..4dd041a48 100644 --- a/src/intel_flash.c +++ b/src/intel_flash.c @@ -6,15 +6,16 @@ * * This file is part of the 86Box distribution. * - * Implementation of the Intel 1 Mbit 8-bit flash devices. + * Implementation of the Intel 1 Mbit and 2 Mbit, 8-bit and + * 16-bit flash devices. * - * Version: @(#)intel_flash.c 1.0.16 2018/04/29 + * Version: @(#)intel_flash.c 1.0.19 2019/06/25 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -22,306 +23,478 @@ #include #include #include "86box.h" -#include "cpu/cpu.h" #include "device.h" #include "mem.h" #include "machine/machine.h" +#include "timer.h" #include "nvr.h" #include "plat.h" -#define FLASH_IS_BXB 2 -#define FLASH_INVERT 1 +#define FLAG_WORD 4 +#define FLAG_BXB 2 +#define FLAG_INV_A16 1 -#define BLOCK_MAIN 0 -#define BLOCK_DATA1 1 -#define BLOCK_DATA2 2 -#define BLOCK_BOOT 3 enum { - CMD_READ_ARRAY = 0xff, - CMD_IID = 0x90, - CMD_READ_STATUS = 0x70, - CMD_CLEAR_STATUS = 0x50, - CMD_ERASE_SETUP = 0x20, - CMD_ERASE_CONFIRM = 0xd0, - CMD_ERASE_SUSPEND = 0xb0, - CMD_PROGRAM_SETUP = 0x40, - CMD_PROGRAM_SETUP_ALT = 0x10 + BLOCK_MAIN1, + BLOCK_MAIN2, + BLOCK_DATA1, + BLOCK_DATA2, + BLOCK_BOOT, + BLOCKS_NUM }; +enum +{ + CMD_READ_ARRAY = 0xff, + CMD_IID = 0x90, + CMD_READ_STATUS = 0x70, + CMD_CLEAR_STATUS = 0x50, + CMD_ERASE_SETUP = 0x20, + CMD_ERASE_CONFIRM = 0xd0, + CMD_ERASE_SUSPEND = 0xb0, + CMD_PROGRAM_SETUP = 0x40, + CMD_PROGRAM_SETUP_ALT = 0x10 +}; + + typedef struct flash_t { - uint8_t command, status; - uint8_t flash_id; - 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]; + uint8_t command, status, + pad, flags, + *array; + + uint16_t flash_id, pad16; + + uint32_t program_addr, + block_start[BLOCKS_NUM], block_end[BLOCKS_NUM], + block_len[BLOCKS_NUM]; + + mem_mapping_t mapping[4], mapping_h[8]; } flash_t; -static wchar_t flash_path[1024]; -static uint8_t flash_read(uint32_t addr, void *p) +static wchar_t flash_path[1024]; + + +static uint8_t +flash_read(uint32_t addr, void *p) { - flash_t *flash = (flash_t *)p; - if (flash->invert_high_pin) - addr ^= 0x10000; - addr &= 0x1ffff; - switch (flash->command) { - case CMD_READ_ARRAY: - default: - return flash->array[addr]; + flash_t *dev = (flash_t *) p; + uint8_t ret = 0xff; - case CMD_IID: - if (addr & 1) - return flash->flash_id; - return 0x89; + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; - case CMD_READ_STATUS: - return flash->status; - } + switch (dev->command) { + case CMD_READ_ARRAY: + default: + ret = dev->array[addr]; + break; + + case CMD_IID: + if (addr & 1) + ret = dev->flash_id & 0xff; + else + ret = 0x89; + break; + + case CMD_READ_STATUS: + ret = dev->status; + break; + } + + return ret; } -static uint16_t flash_readw(uint32_t addr, void *p) + +static uint16_t +flash_readw(uint32_t addr, void *p) { - flash_t *flash = (flash_t *)p; - uint16_t *q; - addr &= 0x1ffff; - if (flash->invert_high_pin) addr ^= 0x10000; - q = (uint16_t *)&(flash->array[addr]); - return *q; + flash_t *dev = (flash_t *) p; + uint16_t *q; + uint16_t ret = 0xffff; + + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; + + if (dev->flags & FLAG_WORD) + addr &= 0xfffffffe; + + q = (uint16_t *)&(dev->array[addr]); + ret = *q; + + if (dev->flags & FLAG_WORD) switch (dev->command) { + case CMD_READ_ARRAY: + default: + break; + + case CMD_IID: + if (addr & 2) + ret = dev->flash_id; + else + ret = 0x0089; + break; + + case CMD_READ_STATUS: + ret = dev->status; + break; + } + + return ret; } -static uint32_t flash_readl(uint32_t addr, void *p) + +static uint32_t +flash_readl(uint32_t addr, void *p) { - flash_t *flash = (flash_t *)p; - uint32_t *q; - addr &= 0x1ffff; - if (flash->invert_high_pin) addr ^= 0x10000; - q = (uint32_t *)&(flash->array[addr]); - return *q; + flash_t *dev = (flash_t *)p; + uint32_t *q; + + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; + + q = (uint32_t *)&(dev->array[addr]); + + return *q; } -static void flash_write(uint32_t addr, uint8_t val, void *p) + +static void +flash_write(uint32_t addr, uint8_t val, void *p) { - flash_t *flash = (flash_t *)p; - int i; + flash_t *dev = (flash_t *) p; + int i; + uint32_t bb_mask = biosmask & 0xffffe000; + if (biosmask == 0x3ffff) + bb_mask &= 0xffffc000; - if (flash->invert_high_pin) - addr ^= 0x10000; - addr &= 0x1ffff; + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; - switch (flash->command) { - case CMD_ERASE_SETUP: - if (val == CMD_ERASE_CONFIRM) { + switch (dev->command) { + case CMD_ERASE_SETUP: + if (val == CMD_ERASE_CONFIRM) { for (i = 0; i < 3; i++) { - if ((addr >= flash->block_start[i]) && (addr <= flash->block_end[i])) - memset(&(flash->array[flash->block_start[i]]), 0xff, flash->block_len[i]); + if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) + memset(&(dev->array[dev->block_start[i]]), 0xff, dev->block_len[i]); } - flash->status = 0x80; - } - flash->command = CMD_READ_STATUS; - break; - - case CMD_PROGRAM_SETUP: - case CMD_PROGRAM_SETUP_ALT: - if ((addr & 0x1e000) != (flash->block_start[3] & 0x1e000)) - flash->array[addr] = val; - flash->command = CMD_READ_STATUS; - flash->status = 0x80; - break; - - default: - flash->command = val; - switch (val) { - case CMD_CLEAR_STATUS: - flash->status = 0; - break; - } - } + dev->status = 0x80; + } + dev->command = CMD_READ_STATUS; + break; + + case CMD_PROGRAM_SETUP: + case CMD_PROGRAM_SETUP_ALT: + if (((addr & bb_mask) != (dev->block_start[4] & bb_mask)) && (addr == dev->program_addr)) + dev->array[addr] = val; + dev->command = CMD_READ_STATUS; + dev->status = 0x80; + break; + + default: + dev->command = val; + switch (val) { + case CMD_CLEAR_STATUS: + dev->status = 0; + break; + case CMD_PROGRAM_SETUP: + case CMD_PROGRAM_SETUP_ALT: + dev->program_addr = addr; + break; + } + } } -static void intel_flash_add_mappings(flash_t *flash) -{ - int i = 0; - 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); +static void +flash_writew(uint32_t addr, uint16_t val, void *p) +{ + flash_t *dev = (flash_t *) p; + int i; + uint32_t bb_mask = biosmask & 0xffffe000; + if (biosmask == 0x3ffff) + bb_mask &= 0xffffc000; + + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; + + if (dev->flags & FLAG_WORD) switch (dev->command) { + case CMD_ERASE_SETUP: + if (val == CMD_ERASE_CONFIRM) { + for (i = 0; i < 3; i++) { + if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) + memset(&(dev->array[dev->block_start[i]]), 0xff, dev->block_len[i]); + } + + dev->status = 0x80; + } + dev->command = CMD_READ_STATUS; + break; + + case CMD_PROGRAM_SETUP: + case CMD_PROGRAM_SETUP_ALT: + if (((addr & bb_mask) != (dev->block_start[4] & bb_mask)) && (addr == dev->program_addr)) + *(uint16_t *) (&dev->array[addr]) = val; + dev->command = CMD_READ_STATUS; + dev->status = 0x80; + break; + + default: + dev->command = val & 0xff; + switch (val) { + case CMD_CLEAR_STATUS: + dev->status = 0; + break; + case CMD_PROGRAM_SETUP: + case CMD_PROGRAM_SETUP_ALT: + dev->program_addr = addr; + break; + } + } +} + + +static void +flash_writel(uint32_t addr, uint32_t val, void *p) +{ +#if 0 + flash_writew(addr, val & 0xffff, p); + flash_writew(addr + 2, (val >> 16) & 0xffff, p); +#endif +} + + +static void +intel_flash_add_mappings(flash_t *dev) +{ + int max = 2, i = 0; + uint32_t base, fbase; + + if (biosmask == 0x3ffff) + max = 4; + + for (i = 0; i < max; i++) { + if (biosmask == 0x3ffff) + base = 0xc0000 + (i << 16); + else + base = 0xe0000 + (i << 16); + fbase = base & biosmask; + if (dev->flags & FLAG_INV_A16) + fbase ^= 0x10000; + + memcpy(&dev->array[fbase], &rom[base & biosmask], 0x10000); + + if ((max == 2) || (i >= 2)) { + mem_mapping_add(&(dev->mapping[i]), base, 0x10000, + flash_read, flash_readw, flash_readl, + flash_write, flash_writew, flash_writel, + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); } + mem_mapping_add(&(dev->mapping_h[i]), (base | 0xfff00000) - 0x40000, 0x10000, + flash_read, flash_readw, flash_readl, + flash_write, flash_writew, flash_writel, + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); + mem_mapping_add(&(dev->mapping_h[i + 4]), (base | 0xfff00000), 0x10000, + flash_read, flash_readw, flash_readl, + flash_write, flash_writew, flash_writel, + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); + } } -/* 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. */ -static void intel_flash_add_mappings_inverted(flash_t *flash) + +static void * +intel_flash_init(const device_t *info) { - int i = 0; + FILE *f; + int l; + flash_t *dev; + wchar_t *machine_name, *flash_name; + uint8_t type = info->local & 0xff; - 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); - } -} + dev = malloc(sizeof(flash_t)); + memset(dev, 0, sizeof(flash_t)); -void *intel_flash_init(uint8_t type) -{ - FILE *f; - int i, l; - flash_t *flash; - wchar_t *machine_name; - wchar_t *flash_name; + l = strlen(machine_get_internal_name_ex(machine))+1; + machine_name = (wchar_t *) malloc(l * sizeof(wchar_t)); + mbstowcs(machine_name, machine_get_internal_name_ex(machine), l); + l = wcslen(machine_name)+5; + flash_name = (wchar_t *)malloc(l*sizeof(wchar_t)); + swprintf(flash_name, l, L"%ls.bin", machine_name); - flash = malloc(sizeof(flash_t)); - memset(flash, 0, sizeof(flash_t)); + wcscpy(flash_path, flash_name); - l = strlen(machine_get_internal_name_ex(machine))+1; - machine_name = (wchar_t *) malloc(l * sizeof(wchar_t)); - mbstowcs(machine_name, machine_get_internal_name_ex(machine), l); - l = wcslen(machine_name)+5; - flash_name = (wchar_t *)malloc(l*sizeof(wchar_t)); - swprintf(flash_name, l, L"%ls.bin", machine_name); + dev->flags = info->local & 0xff; - wcscpy(flash_path, flash_name); + mem_mapping_disable(&bios_mapping); + mem_mapping_disable(&bios_high_mapping); - flash->flash_id = (type & FLASH_IS_BXB) ? 0x95 : 0x94; - flash->invert_high_pin = (type & FLASH_INVERT); + dev->array = (uint8_t *) malloc(biosmask + 1); + memset(dev->array, 0xff, biosmask + 1); + + if (biosmask == 0x3ffff) { + if (dev->flags & FLAG_WORD) + dev->flash_id = (dev->flags & FLAG_BXB) ? 0x2275 : 0x2274; + else + dev->flash_id = (dev->flags & FLAG_BXB) ? 0x7D : 0x7C; /* 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; + dev->block_len[BLOCK_MAIN1] = 0x20000; + dev->block_len[BLOCK_MAIN2] = 0x18000; + dev->block_len[BLOCK_DATA1] = 0x02000; + dev->block_len[BLOCK_DATA2] = 0x02000; + dev->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 (dev->flags & FLAG_BXB) { /* 28F002BX-B/28F200BX-B */ + dev->block_start[BLOCK_MAIN1] = 0x20000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x3ffff; + dev->block_start[BLOCK_MAIN2] = 0x08000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0x1ffff; + dev->block_start[BLOCK_DATA1] = 0x06000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x07fff; + dev->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x05fff; + dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x03fff; + } else { /* 28F002BX-T/28F200BX-T */ + dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1ffff; + dev->block_start[BLOCK_MAIN2] = 0x20000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0x37fff; + dev->block_start[BLOCK_DATA1] = 0x38000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x39fff; + dev->block_start[BLOCK_DATA2] = 0x3a000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x3bfff; + dev->block_start[BLOCK_BOOT] = 0x3c000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x3ffff; } + } else { + dev->flash_id = (type & FLAG_BXB) ? 0x95 : 0x94; - for (i = 0; i < 8; i++) { - mem_mapping_disable(&bios_mapping[i]); - mem_mapping_disable(&bios_high_mapping[i]); + /* The block lengths are the same both flash types. */ + dev->block_len[BLOCK_MAIN1] = 0x1c000; + dev->block_len[BLOCK_MAIN2] = 0x00000; + dev->block_len[BLOCK_DATA1] = 0x01000; + dev->block_len[BLOCK_DATA2] = 0x01000; + dev->block_len[BLOCK_BOOT] = 0x02000; + + if (dev->flags & FLAG_BXB) { /* 28F001BX-B/28F100BX-B */ + dev->block_start[BLOCK_MAIN1] = 0x04000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1ffff; + dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x02000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x02fff; + dev->block_start[BLOCK_DATA2] = 0x03000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x03fff; + dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x01fff; + } else { /* 28F001BX-T/28F100BX-T */ + dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1bfff; + dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x1cfff; + dev->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x1dfff; + dev->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x1ffff; } + } - if (flash->invert_high_pin) { - memcpy(flash->array, rom + 65536, 65536); - memcpy(flash->array + 65536, rom, 65536); - } - else - memcpy(flash->array, rom, 131072); + intel_flash_add_mappings(dev); - if (flash->invert_high_pin) - intel_flash_add_mappings_inverted(flash); - else - intel_flash_add_mappings(flash); + dev->command = CMD_READ_ARRAY; + dev->status = 0; - flash->command = CMD_READ_ARRAY; - flash->status = 0; + f = nvr_fopen(flash_path, L"rb"); + if (f) { + fread(&(dev->array[dev->block_start[BLOCK_MAIN1]]), dev->block_len[BLOCK_MAIN1], 1, f); + if (dev->block_len[BLOCK_MAIN2]) + fread(&(dev->array[dev->block_start[BLOCK_MAIN2]]), dev->block_len[BLOCK_MAIN2], 1, f); + fread(&(dev->array[dev->block_start[BLOCK_DATA1]]), dev->block_len[BLOCK_DATA1], 1, f); + fread(&(dev->array[dev->block_start[BLOCK_DATA2]]), dev->block_len[BLOCK_DATA2], 1, f); + fclose(f); + } - f = nvr_fopen(flash_path, L"rb"); - 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); - fread(&(flash->array[flash->block_start[BLOCK_DATA2]]), flash->block_len[BLOCK_DATA2], 1, f); - fclose(f); - } + free(flash_name); + free(machine_name); - free(flash_name); - free(machine_name); - - return flash; + return dev; } -void *intel_flash_bxb_ami_init() + +static void +intel_flash_close(void *p) { - return intel_flash_init(FLASH_IS_BXB | FLASH_INVERT); -} + FILE *f; + flash_t *dev = (flash_t *)p; -/* For AMI BIOS'es - Intel 28F001BXT with high address pin inverted. */ -void *intel_flash_bxt_ami_init() -{ - return intel_flash_init(FLASH_INVERT); -} + f = nvr_fopen(flash_path, L"wb"); + fwrite(&(dev->array[dev->block_start[BLOCK_MAIN1]]), dev->block_len[BLOCK_MAIN1], 1, f); + if (dev->block_len[BLOCK_MAIN2]) + fwrite(&(dev->array[dev->block_start[BLOCK_MAIN2]]), dev->block_len[BLOCK_MAIN2], 1, f); + fwrite(&(dev->array[dev->block_start[BLOCK_DATA1]]), dev->block_len[BLOCK_DATA1], 1, f); + fwrite(&(dev->array[dev->block_start[BLOCK_DATA2]]), dev->block_len[BLOCK_DATA2], 1, f); + fclose(f); -/* For Award BIOS'es - Intel 28F001BXT with high address pin not inverted. */ -void *intel_flash_bxt_init() -{ - return intel_flash_init(0); -} - -/* For Acer BIOS'es - Intel 28F001BXB. */ -void *intel_flash_bxb_init() -{ - return intel_flash_init(FLASH_IS_BXB); -} - -void intel_flash_close(void *p) -{ - FILE *f; - flash_t *flash = (flash_t *)p; - - f = nvr_fopen(flash_path, L"wb"); - fwrite(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 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); - - free(flash); + free(dev); } +/* For AMI BIOS'es - Intel 28F001BXT with A16 pin inverted. */ const device_t intel_flash_bxt_ami_device = { - "Intel 28F001BXT Flash BIOS", - 0, 0, - intel_flash_bxt_ami_init, - intel_flash_close, - NULL, - NULL, NULL, NULL, NULL + "Intel 28F001BXT/28F002BXT Flash BIOS", + 0, + FLAG_INV_A16, + intel_flash_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL }; -const device_t intel_flash_bxb_ami_device = + +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +const device_t intel_flash_bxtw_ami_device = { - "Intel 28F001BXB Flash BIOS", - 0, 0, - intel_flash_bxb_ami_init, - intel_flash_close, - NULL, - NULL, NULL, NULL, NULL + "Intel 28F100BXT/28F200BXT Flash BIOS", + 0, + FLAG_INV_A16 | FLAG_WORD, + intel_flash_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL }; +#endif + const device_t intel_flash_bxt_device = { - "Intel 28F001BXT Flash BIOS", - 0, 0, - intel_flash_bxt_init, - intel_flash_close, - NULL, - NULL, NULL, NULL, NULL + "Intel 28F001BXT/28F002BXT Flash BIOS", + 0, 0, + intel_flash_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL }; + const device_t intel_flash_bxb_device = { - "Intel 28F001BXB Flash BIOS", - 0, 0, - intel_flash_bxb_init, - intel_flash_close, - NULL, - NULL, NULL, NULL, NULL + "Intel 28F001BXB/28F002BXB Flash BIOS", + 0, FLAG_BXB, + intel_flash_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL }; diff --git a/src/intel_flash.h b/src/intel_flash.h index 241a07c02..3c76ec52a 100644 --- a/src/intel_flash.h +++ b/src/intel_flash.h @@ -8,15 +8,17 @@ * * Implementation of the Intel 1 Mbit 8-bit flash devices. * - * Version: @(#)intel_flash.h 1.0.1 2018/03/14 + * Version: @(#)intel_flash.h 1.0.2 2019/06/25 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016-2017 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ extern const device_t intel_flash_bxt_ami_device; -extern const device_t intel_flash_bxb_ami_device; +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +extern const device_t intel_flash_bxtw_ami_device; +#endif extern const device_t intel_flash_bxt_device; extern const device_t intel_flash_bxb_device; diff --git a/src/intel_piix.c b/src/intel_piix.c index 43f8dd17b..d5fdfc36f 100644 --- a/src/intel_piix.c +++ b/src/intel_piix.c @@ -10,7 +10,7 @@ * word 0 - base address * word 1 - bits 1-15 = byte count, bit 31 = end of transfer * - * Version: @(#)intel_piix.c 1.0.17 2018/06/02 + * Version: @(#)intel_piix.c 1.0.22 2018/10/31 * * Authors: Sarah Walker, * Miran Grca, @@ -26,64 +26,55 @@ #include #define HAVE_STDARG_H #include "86box.h" -#include "scsi/scsi.h" #include "cdrom/cdrom.h" +#include "cpu/cpu.h" +#include "scsi/scsi_device.h" +#include "scsi/scsi_cdrom.h" #include "dma.h" #include "io.h" #include "device.h" +#include "apm.h" #include "keyboard.h" #include "mem.h" #include "pci.h" #include "pic.h" +#include "port_92.h" #include "disk/hdc.h" #include "disk/hdc_ide.h" +#include "disk/hdc_ide_sff8038i.h" #include "disk/zip.h" +#include "machine/machine.h" #include "piix.h" -typedef struct -{ - uint8_t command, status, - ptr0; - uint32_t ptr, ptr_cur, - addr; - int count, eot; -} piix_busmaster_t; - typedef struct { int type; - uint8_t regs[256], regs_ide[256]; - piix_busmaster_t bm[2]; + uint8_t cur_readout_reg, + readout_regs[256], + regs[256], regs_ide[256]; + sff8038i_t *bm[2]; } piix_t; -static uint8_t piix_bus_master_read(uint16_t port, void *priv); -static uint16_t piix_bus_master_readw(uint16_t port, void *priv); -static uint32_t piix_bus_master_readl(uint16_t port, void *priv); -static void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); -static void piix_bus_master_writew(uint16_t port, uint16_t val, void *priv); -static void piix_bus_master_writel(uint16_t port, uint32_t val, void *priv); - - #ifdef ENABLE_PIIX_LOG int piix_do_log = ENABLE_PIIX_LOG; -#endif static void -piix_log(const char *format, ...) +piix_log(const char *fmt, ...) { -#ifdef ENABLE_PIIX_LOG va_list ap; if (piix_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define piix_log(fmt, ...) +#endif static void @@ -92,25 +83,9 @@ piix_bus_master_handlers(piix_t *dev, uint16_t old_base) uint16_t base; base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); - io_removehandler(old_base, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[0]); - io_removehandler(old_base + 8, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[1]); - if ((dev->regs_ide[0x04] & 1) && base) { - io_sethandler(base, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[0]); - io_sethandler(base + 8, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[1]); - } + sff_bus_master_handlers(dev->bm[0], old_base, base, (dev->regs_ide[0x04] & 1)); + sff_bus_master_handlers(dev->bm[1], old_base + 8, base + 8, (dev->regs_ide[0x04] & 1)); } @@ -119,11 +94,16 @@ piix_write(int func, int addr, uint8_t val, void *priv) { piix_t *dev = (piix_t *) priv; uint8_t valxor; + uint16_t old_base; + + if ((func == 1) && (dev->type & 0x100)) /* PB640's PIIX has no IDE part. */ + return; - uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); if (func > 1) return; + old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + if (func == 1) { /*IDE*/ piix_log("PIIX IDE write: %02X %02X\n", addr, val); valxor = val ^ dev->regs_ide[addr]; @@ -203,12 +183,11 @@ piix_write(int func, int addr, uint8_t val, void *priv) case 0x4c: if (valxor) { - if (val & 0x80) { - if (dev->type == 3) - dma_alias_remove(); - else - dma_alias_remove_piix(); - } else + if (dev->type == 3) + dma_alias_remove(); + else + dma_alias_remove_piix(); + if (!(val & 0x80)) dma_alias_set(); } break; @@ -408,337 +387,43 @@ piix_read(int func, int addr, void *priv) static void -piix_bus_master_next_addr(piix_busmaster_t *dev) +board_write(uint16_t port, uint8_t val, void *priv) { - DMAPageRead(dev->ptr_cur, (uint8_t *)&(dev->addr), 4); - DMAPageRead(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4); - piix_log("PIIX Bus master DWORDs: %08X %08X\n", dev->addr, dev->count); - dev->eot = dev->count >> 31; - dev->count &= 0xfffe; - if (!dev->count) - dev->count = 65536; - dev->addr &= 0xfffffffe; - dev->ptr_cur += 8; -} + piix_t *dev = (piix_t *) priv; - -static void -piix_bus_master_write(uint16_t port, uint8_t val, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - int channel = (port & 8) ? 1 : 0; - - piix_log("PIIX Bus master BYTE write: %04X %02X\n", port, val); - - switch (port & 7) { - case 0: - piix_log("PIIX Cmd : val = %02X, old = %02X\n", val, dev->command); - if ((val & 1) && !(dev->command & 1)) { /*Start*/ - piix_log("PIIX Bus Master start on channel %i\n", channel); - dev->ptr_cur = dev->ptr; - piix_bus_master_next_addr(dev); - dev->status |= 1; - } - if (!(val & 1) && (dev->command & 1)) { /*Stop*/ - piix_log("PIIX Bus Master stop on channel %i\n", channel); - dev->status &= ~1; - } - - dev->command = val; - break; - case 2: - piix_log("PIIX Status: val = %02X, old = %02X\n", val, dev->status); - dev->status &= 0x07; - dev->status |= (val & 0x60); - if (val & 0x04) - dev->status &= ~0x04; - if (val & 0x02) - dev->status &= ~0x02; - break; - case 4: - dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc); - dev->ptr %= (mem_size * 1024); - dev->ptr0 = val; - break; - case 5: - dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8); - dev->ptr %= (mem_size * 1024); - break; - case 6: - dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16); - dev->ptr %= (mem_size * 1024); - break; - case 7: - dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24); - dev->ptr %= (mem_size * 1024); - break; - } -} - - -static void -piix_bus_master_writew(uint16_t port, uint16_t val, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - - piix_log("PIIX Bus master WORD write: %04X %04X\n", port, val); - - switch (port & 7) { - case 0: - case 2: - piix_bus_master_write(port, val & 0xff, priv); - break; - case 4: - dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc); - dev->ptr %= (mem_size * 1024); - dev->ptr0 = val & 0xff; - break; - case 6: - dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16); - dev->ptr %= (mem_size * 1024); - break; - } -} - - -static void -piix_bus_master_writel(uint16_t port, uint32_t val, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - - piix_log("PIIX Bus master DWORD write: %04X %08X\n", port, val); - - switch (port & 7) { - case 0: - case 2: - piix_bus_master_write(port, val & 0xff, priv); - break; - case 4: - dev->ptr = (val & 0xfffffffc); - dev->ptr %= (mem_size * 1024); - dev->ptr0 = val & 0xff; - break; - } + if (port == 0x00e0) + dev->cur_readout_reg = val; + else if (port == 0x00e1) + dev->readout_regs[dev->cur_readout_reg] = val; } static uint8_t -piix_bus_master_read(uint16_t port, void *priv) +board_read(uint16_t port, void *priv) { - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - + piix_t *dev = (piix_t *) priv; uint8_t ret = 0xff; - switch (port & 7) { - case 0: - ret = dev->command; - break; - case 2: - ret = dev->status & 0x67; - break; - case 4: - ret = dev->ptr0; - break; - case 5: - ret = dev->ptr >> 8; - break; - case 6: - ret = dev->ptr >> 16; - break; - case 7: - ret = dev->ptr >> 24; - break; - } - - piix_log("PIIX Bus master BYTE read : %04X %02X\n", port, ret); + if (port == 0x00e0) + ret = dev->cur_readout_reg; + else if (port == 0x00e1) + ret = dev->readout_regs[dev->cur_readout_reg]; return ret; } -static uint16_t -piix_bus_master_readw(uint16_t port, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - - uint16_t ret = 0xffff; - - switch (port & 7) { - case 0: - case 2: - ret = (uint16_t) piix_bus_master_read(port, priv); - break; - case 4: - ret = dev->ptr0 | (dev->ptr & 0xff00); - break; - case 6: - ret = dev->ptr >> 16; - break; - } - - piix_log("PIIX Bus master WORD read : %04X %04X\n", port, ret); - - return ret; -} - - -static uint32_t -piix_bus_master_readl(uint16_t port, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - - uint32_t ret = 0xffffffff; - - switch (port & 7) { - case 0: - case 2: - ret = (uint32_t) piix_bus_master_read(port, priv); - break; - case 4: - ret = dev->ptr0 | (dev->ptr & 0xffffff00); - break; - } - - piix_log("PIIX Bus master DWORD read : %04X %08X\n", port, ret); - - return ret; -} - - -static int -piix_bus_master_dma_op(int channel, uint8_t *data, int transfer_length, int out, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - char *sop; - - int force_end = 0, buffer_pos = 0; - - sop = out ? "Writ" : "Read"; - - if (!(dev->status & 1)) - return 2; /*DMA disabled*/ - - piix_log("PIIX Bus master %s: %i bytes\n", out ? "read" : "write", transfer_length); - - while (1) { - if (dev->count <= transfer_length) { - piix_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr); - if (out) - DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); - else - DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); - transfer_length -= dev->count; - buffer_pos += dev->count; - } else { - piix_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr); - if (out) - DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); - else - DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); - /* Increase addr and decrease count so that resumed transfers do not mess up. */ - dev->addr += transfer_length; - dev->count -= transfer_length; - transfer_length = 0; - force_end = 1; - } - - if (force_end) { - piix_log("Total transfer length smaller than sum of all blocks, partial block\n"); - dev->status &= ~2; - return 0; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ - } else { - if (!transfer_length && !dev->eot) { - piix_log("Total transfer length smaller than sum of all blocks, full block\n"); - dev->status &= ~2; - return 0; /* We have exhausted the data to transfer but there's more blocks left, break. */ - } else if (transfer_length && dev->eot) { - piix_log("Total transfer length greater than sum of all blocks\n"); - dev->status |= 2; - return 1; /* There is data left to transfer but we have reached EOT - return with error. */ - } else if (dev->eot) { - piix_log("Regular EOT\n"); - dev->status &= ~3; - return 0; /* We have regularly reached EOT - clear status and break. */ - } else { - /* We have more to transfer and there are blocks left, get next block. */ - piix_bus_master_next_addr(dev); - } - } - } - return 0; -} - - -int -piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv) -{ - return piix_bus_master_dma_op(channel, data, transfer_length, 1, priv); -} - - -int -piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv) -{ - return piix_bus_master_dma_op(channel, data, transfer_length, 0, priv); -} - - -void -piix_bus_master_set_irq(int channel, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - dev->status &= ~4; - dev->status |= (channel >> 4); - - channel &= 0x01; - if (dev->status & 0x04) { - if (channel && pci_use_mirq(0)) - pci_set_mirq(0); - else - picint(1 << (14 + channel)); - } else { - if ((channel & 1) && pci_use_mirq(0)) - pci_clear_mirq(0); - else - picintc(1 << (14 + channel)); - } -} - - -static void -piix_bus_master_reset(piix_t *dev) -{ - uint8_t i; - - uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); - if (old_base) { - io_removehandler(old_base, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[0]); - io_removehandler(old_base + 8, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[1]); - } - - for (i = 0; i < 2; i++) { - dev->bm[i].command = 0x00; - dev->bm[i].status = 0x00; - dev->bm[i].ptr = dev->bm[i].ptr_cur = 0x00000000; - dev->bm[i].addr = 0x00000000; - dev->bm[i].ptr0 = 0x00; - dev->bm[i].count = dev->bm[i].eot = 0x00000000; - } -} - - static void piix_reset_hard(void *priv) { piix_t *piix = (piix_t *) priv; - piix_bus_master_reset(piix); + uint16_t old_base = (piix->regs_ide[0x20] & 0xf0) | (piix->regs_ide[0x21] << 8); + + if (!(piix->type & 0x100)) { /* PB640's PIIX has no IDE part. */ + sff_bus_master_reset(piix->bm[0], old_base); + sff_bus_master_reset(piix->bm[1], old_base + 8); + } memset(piix->regs, 0, 256); memset(piix->regs_ide, 0, 256); @@ -812,25 +497,6 @@ piix_reset_hard(void *priv) pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); if (piix->type != 3) pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); - - ide_pri_disable(); - ide_sec_disable(); -} - - -static void -piix_reset(void *p) -{ - int i = 0; - - for (i = 0; i < CDROM_NUM; i++) { - if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) - cdrom_reset(cdrom[i]); - } - for (i = 0; i < ZIP_NUM; i++) { - if (zip_drives[i].bus_type == ZIP_BUS_ATAPI) - zip_reset(zip[i]); - } } @@ -849,26 +515,96 @@ static void piix_t *piix = (piix_t *) malloc(sizeof(piix_t)); memset(piix, 0, sizeof(piix_t)); - device_add(&ide_pci_2ch_device); - pci_add_card(7, piix_read, piix_write, piix); piix->type = info->local; + + device_add(&apm_device); + + if (!(piix->type & 0x100)) { /* PB640's PIIX has no IDE part. */ + piix->bm[0] = device_add_inst(&sff8038i_device, 1); + piix->bm[1] = device_add_inst(&sff8038i_device, 2); + } + piix_reset_hard(piix); - ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, - piix_bus_master_set_irq, - &piix->bm[0], &piix->bm[1]); - - port_92_reset(); - - port_92_add(); + device_add(&port_92_pci_device); dma_alias_set(); pci_enable_mirq(0); pci_enable_mirq(1); + piix->readout_regs[1] = 0x40; + + /* Port E1 register 01 (TODO: Find how multipliers > 3.0 are defined): + + Bit 6: 1 = can boot, 0 = no; + Bit 7, 1 = multiplier (00 = 2.5, 01 = 2.0, 10 = 3.0, 11 = 1.5); + Bit 5, 4 = bus speed (00 = 50 MHz, 01 = 66 MHz, 10 = 60 MHz, 11 = ????): + Bit 7, 5, 4, 1: 0000 = 125 MHz, 0010 = 166 MHz, 0100 = 150 MHz, 0110 = ??? MHz; + 0001 = 100 MHz, 0011 = 133 MHz, 0101 = 120 MHz, 0111 = ??? MHz; + 1000 = 150 MHz, 1010 = 200 MHz, 1100 = 180 MHz, 1110 = ??? MHz; + 1001 = 75 MHz, 1011 = 100 MHz, 1101 = 90 MHz, 1111 = ??? MHz */ + + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].pci_speed) { + case 20000000: + piix->readout_regs[1] |= 0x30; + break; + case 25000000: + default: + piix->readout_regs[1] |= 0x00; + break; + case 30000000: + piix->readout_regs[1] |= 0x20; + break; + case 33333333: + piix->readout_regs[1] |= 0x10; + break; + } + + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed) { + case 75000000: + piix->readout_regs[1] |= 0x82; /* 50 MHz * 1.5 multiplier */ + break; + case 90000000: + piix->readout_regs[1] |= 0x82; /* 60 MHz * 1.5 multiplier */ + break; + case 100000000: + if ((piix->readout_regs[1] & 0x30) == 0x10) + piix->readout_regs[1] |= 0x82; /* 66 MHz * 1.5 multiplier */ + else + piix->readout_regs[1] |= 0x02; /* 50 MHz * 2.0 multiplier */ + break; + case 12000000: + piix->readout_regs[1] |= 0x02; /* 60 MHz * 2.0 multiplier */ + break; + case 125000000: + piix->readout_regs[1] |= 0x00; /* 50 MHz * 2.5 multiplier */ + break; + case 133333333: + piix->readout_regs[1] |= 0x02; /* 66 MHz * 2.0 multiplier */ + break; + case 150000000: + if ((piix->readout_regs[1] & 0x30) == 0x20) + piix->readout_regs[1] |= 0x00; /* 60 MHz * 2.5 multiplier */ + else + piix->readout_regs[1] |= 0x80; /* 50 MHz * 3.0 multiplier */ + break; + case 166666666: + piix->readout_regs[1] |= 0x00; /* 66 MHz * 2.5 multiplier */ + break; + case 180000000: + piix->readout_regs[1] |= 0x80; /* 60 MHz * 3.0 multiplier */ + break; + case 200000000: + piix->readout_regs[1] |= 0x80; /* 66 MHz * 3.0 multiplier */ + break; + } + + io_sethandler(0x0078, 0x0002, board_read, NULL, NULL, board_write, NULL, NULL, piix); + io_sethandler(0x00e0, 0x0002, board_read, NULL, NULL, board_write, NULL, NULL, piix); + return piix; } @@ -880,7 +616,7 @@ const device_t piix_device = 1, piix_init, piix_close, - piix_reset, + NULL, NULL, NULL, NULL, @@ -894,7 +630,7 @@ const device_t piix_pb640_device = 0x101, piix_init, piix_close, - piix_reset, + NULL, NULL, NULL, NULL, @@ -908,7 +644,7 @@ const device_t piix3_device = 3, piix_init, piix_close, - piix_reset, + NULL, NULL, NULL, NULL, diff --git a/src/intel_piix4.c b/src/intel_piix4.c deleted file mode 100644 index ed4b49335..000000000 --- a/src/intel_piix4.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * Preliminary emulation of the Intel PIIX4 Xcelerator. - * - * PRD format : - * word 0 - base address - * word 1 - bits 1-15 = byte count, bit 31 = end of transfer - * - * Version: @(#)intel_piix4.c 1.0.3 2018/02/14 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include "86box.h" -#include "dma.h" -#include "io.h" -#include "device.h" -#include "keyboard.h" -#include "mem.h" -#include "pci.h" -#include "disk/hdc.h" -#include "disk/hdc_ide.h" -#include "piix.h" - - -static uint8_t card_piix4[256], card_piix4_ide[256]; - - -static void piix4_write(int func, int addr, uint8_t val, void *priv) -{ - uint16_t old_base = (card_piix4_ide[0x20] & 0xf0) | (card_piix4_ide[0x21] << 8); - if (func > 1) - return; - - if (func == 1) /*IDE*/ - { - /* pclog("PIIX IDE write: %02X %02X\n", addr, val); */ - - switch (addr) - { - case 0x04: - card_piix4_ide[0x04] = (val & 5) | 2; - break; - case 0x07: - card_piix4_ide[0x07] = val & 0x3e; - break; - case 0x0d: - card_piix4_ide[0x0d] = val; - break; - - case 0x20: - card_piix4_ide[0x20] = (val & ~0x0f) | 1; - break; - case 0x21: - card_piix4_ide[0x21] = val; - break; - - case 0x40: - card_piix4_ide[0x40] = val; - break; - case 0x41: - if ((val ^ card_piix4_ide[0x41]) & 0x80) - { - ide_pri_disable(); - if (val & 0x80) - ide_pri_enable(); - } - card_piix4_ide[0x41] = val; - break; - case 0x42: - card_piix4_ide[0x42] = val; - break; - case 0x43: - if ((val ^ card_piix4_ide[0x43]) & 0x80) - { - ide_sec_disable(); - if (val & 0x80) - ide_sec_enable(); - } - card_piix4_ide[0x43] = val; - break; - case 0x44: - card_piix4_ide[0x44] = val; - break; - case 0x48: - card_piix4_ide[0x44] = val; - break; - case 0x4A: - card_piix4_ide[0x44] = val; - break; - case 0x4B: - card_piix4_ide[0x44] = val; - break; - } - if (addr == 4 || (addr & ~3) == 0x20) /*Bus master base address*/ - { - uint16_t base = (card_piix4_ide[0x20] & 0xf0) | (card_piix4_ide[0x21] << 8); - io_removehandler(old_base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); - if (card_piix4_ide[0x04] & 1) - { - io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); - } - } - } - else - { - /* pclog("PIIX writing value %02X to register %02X\n", val, addr); */ - 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("Set IRQ routing: INT A -> %02X\n", 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("Set IRQ routing: INT B -> %02X\n", 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("Set IRQ routing: INT C -> %02X\n", 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("Set IRQ routing: INT D -> %02X\n", val); */ - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTD, val & 0xf); - break; - } - if (addr == 0x4C) - { - if (!((val ^ card_piix4[addr]) & 0x80)) - { - card_piix4[addr] = val; - return; - } - - card_piix4[addr] = val; - if (val & 0x80) - { - dma_alias_remove(); - } - else - { - dma_alias_set(); - } - } - else if (addr == 0x4E) - { - keyboard_at_set_mouse_scan((val & 0x10) ? 1 : 0); - card_piix4[addr] = val; - } - else - card_piix4[addr] = val; - } -} - -static uint8_t piix4_read(int func, int addr, void *priv) -{ - if (func > 1) - return 0xff; - - if (func == 1) /*IDE*/ - { - if (addr == 4) - { - return (card_piix4_ide[addr] & 5); - } - else if (addr == 5) - { - return 0; - } - else if (addr == 6) - { - return 0x80; - } - else if (addr == 7) - { - return card_piix4_ide[addr] & 0x3E; - } - else if (addr == 0xD) - { - return card_piix4_ide[addr] & 0xF0; - } - else if (addr == 0x20) - { - return (card_piix4_ide[addr] & 0xF0) | 1; - } - else if (addr == 0x22) - { - return 0; - } - else if (addr == 0x23) - { - return 0; - } - else if (addr == 0x41) - { - return card_piix4_ide[addr] & 0xF3; - } - else if (addr == 0x43) - { - return card_piix4_ide[addr] & 0xF3; - } - else if (addr == 0x48) - { - return card_piix4_ide[addr] & 0x0F; - } - else if (addr == 0x4A) - { - return card_piix4_ide[addr] & 0x33; - } - else if (addr == 0x4B) - { - return card_piix4_ide[addr] & 0x33; - } - else - { - return card_piix4_ide[addr]; - } - } - else - { - if ((addr & 0xFC) == 0x60) - { - return card_piix4[addr] & 0x8F; - } - if (addr == 4) - { - return (card_piix4[addr] & 0x08) | 7; - } - else if (addr == 5) - { - return card_piix4[addr] & 0x01; - } - else if (addr == 6) - { - return 0x80; - } - else if (addr == 7) - { - return (card_piix4[addr] & 0x78) | 0x02; - } - else if (addr == 0x4E) - { - return (card_piix4[addr] & 0xEF) | keyboard_at_get_mouse_scan(); - } - else if (addr == 0x4F) - { - return card_piix4[addr] & 0x06; - } - else if (addr == 0x69) - { - return card_piix4[addr] & 0xFE; - } - else if (addr == 0x6A) - { - return card_piix4[addr] & 0x80; - } - else if (addr == 0x6B) - { - return card_piix4[addr] & 0x80; - } - else if (addr == 0x76) - { - return (card_piix4[addr] & 0x87) | 0x08; - } - else if (addr == 0x77) - { - return (card_piix4[addr] & 0x87) | 0x08; - } - else if (addr == 0x80) - { - return card_piix4[addr] & 0x7F; - } - else if (addr == 0x82) - { - return card_piix4[addr] & 0x0F; - } - else if (addr == 0x91) - { - return card_piix4[addr] & 0xFC; - } - else if (addr == 0x92) - { - return card_piix4[addr] & 0xC0; - } - else if (addr == 0x94) - { - return card_piix4[addr] & 0xC0; - } - else if (addr == 0xB0) - { - return card_piix4[addr] & 0x7F; - } - else if (addr == 0xB1) - { - return card_piix4[addr] & 0xDF; - } - else if (addr == 0xB3) - { - return card_piix4[addr] & 0xFD; - } - else if (addr == 0xCB) - { - return card_piix4[addr] & 0x3D; - } - else - return card_piix4[addr]; - } - - return 0; -} - -void piix4_reset(void) -{ - memset(card_piix4, 0, 256); - memset(card_piix4_ide, 0, 256); - - card_piix4[0x00] = 0x86; card_piix4[0x01] = 0x80; /*Intel*/ - card_piix4[0x02] = 0x10; card_piix4[0x03] = 0x71; /*82371AB (PIIX4)*/ - card_piix4[0x04] = 0x07; card_piix4[0x05] = 0x00; - card_piix4[0x06] = 0x80; card_piix4[0x07] = 0x02; - card_piix4[0x08] = 0x00; /*A0 stepping*/ - card_piix4[0x09] = 0x00; card_piix4[0x0a] = 0x01; card_piix4[0x0b] = 0x06; - card_piix4[0x0e] = 0x80; /*Multi-function device*/ - card_piix4[0x4c] = 0x4d; - card_piix4[0x4e] = 0x03; - card_piix4[0x60] = card_piix4[0x61] = card_piix4[0x62] = card_piix4[0x63] = 0x80; - card_piix4[0x64] = 0x10; - card_piix4[0x69] = 0x02; - card_piix4[0x76] = card_piix4[0x77] = 0x04; - card_piix4[0xcb] = 0x21; - - card_piix4_ide[0x00] = 0x86; card_piix4_ide[0x01] = 0x80; /*Intel*/ - card_piix4_ide[0x02] = 0x11; card_piix4_ide[0x03] = 0x71; /*82371AB (PIIX)*/ - card_piix4_ide[0x04] = 0x07; card_piix4_ide[0x05] = 0x00; - card_piix4_ide[0x06] = 0x80; card_piix4_ide[0x07] = 0x02; - card_piix4_ide[0x08] = 0x00; - card_piix4_ide[0x09] = 0x80; card_piix4_ide[0x0a] = 0x01; card_piix4_ide[0x0b] = 0x01; - card_piix4_ide[0x0d] = 0x00; - card_piix4_ide[0x0e] = 0x00; - card_piix4_ide[0x20] = 0x01; card_piix4_ide[0x21] = card_piix4_ide[0x22] = card_piix4_ide[0x23] = 0x00; /*Bus master interface base address*/ - card_piix4_ide[0x40] = card_piix4_ide[0x42] = 0x00; - card_piix4_ide[0x41] = card_piix4_ide[0x43] = 0x80; -} - -void piix4_init(int card) -{ - device_add(&ide_pci_2ch_device); - - pci_add_card(card, piix4_read, piix4_write, NULL); - - piix4_reset(); - - ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, piix_bus_master_set_irq); - - port_92_reset(); - - port_92_add(); - - dma_alias_set(); - - pci_reset_handler.pci_set_reset = piix4_reset; -} diff --git a/src/intel_sio.c b/src/intel_sio.c index 69c35fa78..b9e3a07d3 100644 --- a/src/intel_sio.c +++ b/src/intel_sio.c @@ -6,7 +6,7 @@ * * Emulation of Intel System I/O PCI chip. * - * Version: @(#)intel_sio.c 1.0.8 2018/04/26 + * Version: @(#)intel_sio.c 1.0.9 2018/10/02 * * Authors: Sarah Walker, * Miran Grca, @@ -19,25 +19,106 @@ #include #include #include +#include "86box.h" #include "device.h" -#include "cpu/cpu.h" #include "io.h" +#include "apm.h" #include "dma.h" #include "mem.h" #include "pci.h" +#include "timer.h" +#include "pit.h" +#include "port_92.h" +#include "machine/machine.h" #include "intel_sio.h" typedef struct { - uint8_t regs[256]; + uint8_t id, + regs[256]; + + uint16_t timer_base, + timer_latch; + + pc_timer_t timer; + + port_92_t * port_92; } sio_t; +static void +sio_timer_write(uint16_t addr, uint8_t val, void *priv) +{ + sio_t *dev = (sio_t *) priv; + + if (!(addr & 0x0002)) { + if (addr & 0x0001) + dev->timer_latch = (dev->timer_latch & 0xff) | (val << 8); + else + dev->timer_latch = (dev->timer_latch & 0xff00) | val; + + timer_set_delay_u64(&dev->timer, ((uint64_t) dev->timer_latch) * TIMER_USEC); + } +} + + +static void +sio_timer_writew(uint16_t addr, uint16_t val, void *priv) +{ + sio_t *dev = (sio_t *) priv; + + if (!(addr & 0x0002)) { + dev->timer_latch = val; + + timer_set_delay_u64(&dev->timer, ((uint64_t) dev->timer_latch) * TIMER_USEC); + } +} + + +static uint8_t +sio_timer_read(uint16_t addr, void *priv) +{ + sio_t *dev = (sio_t *) priv; + uint16_t sio_timer_latch; + uint8_t ret = 0xff; + + if (!(addr & 0x0002)) { + sub_cycles((int)(PITCONST >> 32)); + + sio_timer_latch = timer_get_remaining_us(&dev->timer); + + if (addr & 0x0001) + ret = sio_timer_latch >> 8; + else + ret = sio_timer_latch & 0xff; + } + + return ret; +} + + +static uint16_t +sio_timer_readw(uint16_t addr, void *priv) +{ + sio_t *dev = (sio_t *) priv; + uint16_t ret = 0xffff; + + if (!(addr & 0x0002)) { + sub_cycles((int)(PITCONST >> 32)); + + ret = timer_get_remaining_us(&dev->timer); + } + + return ret; +} + + static void sio_write(int func, int addr, uint8_t val, void *priv) { sio_t *dev = (sio_t *) priv; + uint8_t old; if (func > 0) return; @@ -45,6 +126,13 @@ sio_write(int func, int addr, uint8_t val, void *priv) if (addr >= 0x0f && addr < 0x4c) return; + /* The IB (original) variant of the SIO has no PCI IRQ steering. */ + if ((addr >= 0x60) && (addr <= 0x63) && (dev->id < 0x03)) + return; + + old = dev->regs[addr]; + dev->regs[addr] = val; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: @@ -67,23 +155,22 @@ sio_write(int func, int addr, uint8_t val, void *priv) break; case 0x40: - if (!((val ^ dev->regs[addr]) & 0x40)) + if (!((val ^ old) & 0x40)) return; + dma_alias_remove(); if (val & 0x40) - dma_alias_remove(); - else dma_alias_set(); break; case 0x4f: - if (!((val ^ dev->regs[addr]) & 0x40)) + if (!((val ^ old) & 0x40)) return; + port_92_remove(dev->port_92); if (val & 0x40) - port_92_add(); - else - port_92_remove(); + port_92_add(dev->port_92); + break; case 0x60: if (val & 0x80) @@ -109,8 +196,22 @@ sio_write(int func, int addr, uint8_t val, void *priv) else pci_set_irq_routing(PCI_INTD, val & 0xf); break; + + case 0x80: + case 0x81: + if (dev->timer_base & 0x01) { + io_removehandler(dev->timer_base & 0xfffc, 0x0004, + sio_timer_read, sio_timer_readw, NULL, + sio_timer_write, sio_timer_writew, NULL, dev); + } + dev->timer_base = (dev->regs[0x81] << 8) | (dev->regs[0x80] & 0xfd); + if (dev->timer_base & 0x01) { + io_sethandler(dev->timer_base & 0xfffc, 0x0004, + sio_timer_read, sio_timer_readw, NULL, + sio_timer_write, sio_timer_writew, NULL, dev); + } + break; } - dev->regs[addr] = val; } @@ -129,6 +230,46 @@ sio_read(int func, int addr, void *priv) } +static void +sio_config_write(uint16_t addr, uint8_t val, void *priv) +{ +} + + +static uint8_t +sio_config_read(uint16_t port, void *priv) +{ + uint8_t ret = 0x00; + + switch (port & 0x000f) { + case 3: + ret = 0xff; + break; + case 5: + ret = 0xd3; + + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].pci_speed) { + case 20000000: + ret |= 0x0c; + break; + case 25000000: + default: + ret |= 0x00; + break; + case 30000000: + ret |= 0x08; + break; + case 33333333: + ret |= 0x04; + break; + } + break; + } + + return ret; +} + + static void sio_reset(void *priv) { @@ -140,7 +281,7 @@ sio_reset(void *priv) dev->regs[0x02] = 0x84; dev->regs[0x03] = 0x04; /*82378IB (SIO)*/ dev->regs[0x04] = 0x07; dev->regs[0x05] = 0x00; dev->regs[0x06] = 0x00; dev->regs[0x07] = 0x02; - dev->regs[0x08] = 0x03; /*A0 stepping*/ + dev->regs[0x08] = dev->id; dev->regs[0x40] = 0x20; dev->regs[0x41] = 0x00; dev->regs[0x42] = 0x04; dev->regs[0x43] = 0x00; @@ -160,6 +301,14 @@ sio_reset(void *priv) pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + if (dev->timer_base & 0x0001) { + io_removehandler(dev->timer_base & 0xfffc, 0x0004, + sio_timer_read, sio_timer_readw, NULL, + sio_timer_write, sio_timer_writew, NULL, dev); + } + + dev->timer_base = 0x0078; } @@ -173,21 +322,43 @@ sio_close(void *p) static void -*sio_init(const device_t *info) +sio_speed_changed(void *priv) +{ + sio_t *dev = (sio_t *) priv; + int te; + + te = timer_is_enabled(&dev->timer); + + timer_disable(&dev->timer); + if (te) + timer_set_delay_u64(&dev->timer, ((uint64_t) dev->timer_latch) * TIMER_USEC); +} + + +static void * +sio_init(const device_t *info) { sio_t *sio = (sio_t *) malloc(sizeof(sio_t)); memset(sio, 0, sizeof(sio_t)); pci_add_card(2, sio_read, sio_write, sio); - + + device_add(&apm_device); + + sio->id = info->local; sio_reset(sio); - port_92_reset(); - - port_92_add(); + sio->port_92 = device_add(&port_92_pci_device); dma_alias_set(); + io_sethandler(0x0073, 0x0001, + sio_config_read, NULL, NULL, sio_config_write, NULL, NULL, sio); + io_sethandler(0x0075, 0x0001, + sio_config_read, NULL, NULL, sio_config_write, NULL, NULL, sio); + + timer_add(&sio->timer, NULL, NULL, 0); + return sio; } @@ -196,12 +367,27 @@ const device_t sio_device = { "Intel 82378IB (SIO)", DEVICE_PCI, - 0, - sio_init, - sio_close, - NULL, + 0x00, + sio_init, + sio_close, NULL, NULL, + sio_speed_changed, + NULL, + NULL +}; + + +const device_t sio_zb_device = +{ + "Intel 82378ZB (SIO)", + DEVICE_PCI, + 0x03, + sio_init, + sio_close, + NULL, + NULL, + sio_speed_changed, NULL, NULL }; diff --git a/src/intel_sio.h b/src/intel_sio.h index b1976b9b2..3793c6c58 100644 --- a/src/intel_sio.h +++ b/src/intel_sio.h @@ -15,3 +15,4 @@ */ extern const device_t sio_device; +extern const device_t sio_zb_device; diff --git a/src/io.c b/src/io.c index 8a8b5b6d2..8e1ed59f8 100644 --- a/src/io.c +++ b/src/io.c @@ -8,14 +8,14 @@ * * Implement I/O ports and their operations. * - * Version: @(#)io.c 1.0.4 2018/04/29 + * Version: @(#)io.c 1.0.7 2019/09/23 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -27,6 +27,7 @@ #include "86box.h" #include "io.h" #include "cpu/cpu.h" +#include "machine/m_amstrad.h" #define NPORTS 65536 /* PC/AT supports 64K ports */ @@ -52,23 +53,21 @@ io_t *io[NPORTS], *io_last[NPORTS]; #ifdef ENABLE_IO_LOG int io_do_log = ENABLE_IO_LOG; -#endif -#ifdef ENABLE_IO_LOG static void -io_log(const char *format, ...) +io_log(const char *fmt, ...) { -#ifdef ENABLE_IO_LOG va_list ap; if (io_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define io_log(fmt, ...) #endif @@ -210,6 +209,23 @@ io_removehandler(uint16_t base, int size, } +void +io_handler(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + if (set) + io_sethandler(base, size, inb, inw, inl, outb, outw, outl, priv); + else + io_removehandler(base, size, inb, inw, inl, outb, outw, outl, priv); +} + + #ifdef PC98 void io_sethandler_interleaved(uint16_t base, int size, @@ -290,24 +306,37 @@ io_removehandler_interleaved(uint16_t base, int size, uint8_t inb(uint16_t port) { - uint8_t r = 0xff; + uint8_t ret = 0xff; io_t *p; + int found = 0; p = io[port]; if (p) { while(p) { - if (p->inb) - r &= p->inb(port, p->priv); + if (p->inb) { + ret &= p->inb(port, p->priv); + found++; + } p = p->next; } } + if (port & 0x80) + amstrad_latch = AMSTRAD_NOLATCH; + else if (port & 0x4000) + amstrad_latch = AMSTRAD_SW10; + else + amstrad_latch = AMSTRAD_SW9; + #ifdef ENABLE_IO_LOG if (CS == IO_TRACE) - io_log("IOTRACE(%04X): inb(%04x)=%02x\n", IO_TRACE, port, r); + io_log("IOTRACE(%04X): inb(%04x)=%02x\n", IO_TRACE, port, ret); #endif - return(r); + if (!found) + sub_cycles(io_delay); + + return(ret); } @@ -315,12 +344,15 @@ void outb(uint16_t port, uint8_t val) { io_t *p; + int found = 0; if (io[port]) { p = io[port]; while(p) { - if (p->outb) + if (p->outb) { p->outb(port, val, p->priv); + found++; + } p = p->next; } } @@ -329,6 +361,10 @@ outb(uint16_t port, uint8_t val) if (CS == IO_TRACE) io_log("IOTRACE(%04X): outb(%04x,%02x)\n", IO_TRACE, port, val); #endif + + if (!found) + sub_cycles(io_delay); + return; } @@ -337,17 +373,24 @@ uint16_t inw(uint16_t port) { io_t *p; + uint16_t ret = 0xffff; + int found = 0; p = io[port]; if (p) { while(p) { - if (p->inw) - return p->inw(port, p->priv); + if (p->inw) { + ret = p->inw(port, p->priv); + found = 1; + } p = p->next; } } - return(inb(port) | (inb(port + 1) << 8)); + if (!found) + ret = (inb(port) | (inb(port + 1) << 8)); + + return ret; } @@ -378,17 +421,24 @@ uint32_t inl(uint16_t port) { io_t *p; + uint32_t ret = 0xffffffff; + int found = 0; p = io[port]; if (p) { while(p) { - if (p->inl) - return p->inl(port, p->priv); + if (p->inl) { + ret = p->inl(port, p->priv); + found = 1; + } p = p->next; } } - return(inw(port) | (inw(port + 2) << 16)); + if (!found) + ret = (inw(port) | (inw(port + 2) << 16)); + + return ret; } diff --git a/src/io.h b/src/io.h index 43b23c00d..93bb3be03 100644 --- a/src/io.h +++ b/src/io.h @@ -41,6 +41,15 @@ extern void io_removehandler(uint16_t base, int size, void (*outl)(uint16_t addr, uint32_t val, void *priv), void *priv); +extern void io_handler(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); + #ifdef PC98 extern void io_sethandler_interleaved(uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), diff --git a/src/isamem.c b/src/isamem.c new file mode 100644 index 000000000..a6f29deb5 --- /dev/null +++ b/src/isamem.c @@ -0,0 +1,1084 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of a memory expansion board for the ISA Bus. + * + * Although modern systems use direct-connect local buses to + * connect the CPU with its memory, originally the main system + * bus(es) were used for that. Memory expension cards could add + * memory to the system through the ISA bus, using a variety of + * techniques. + * + * The majority of these boards could provide some (additional) + * conventional (low) memory, extended (high) memory on 80286 + * and higher systems, as well as EMS bank-switched memory. + * + * This implementation uses the LIM 3.2 specifications for EMS. + * + * With the EMS method, the system's standard memory is expanded + * by means of bank-switching. One or more 'frames' in the upper + * memory area (640K-1024K) are used as viewports into an array + * of RAM pages numbered 0 to N. Each page is defined to be 16KB + * in size, so, for a 1024KB board, 64 such pages are available. + * I/O control registers are used to set up the mappings. More + * modern boards even have multiple 'copies' of those registers, + * which can be switched very fast, to allow for multitasking. + * + * TODO: The EV159 is supposed to support 16b EMS transfers, but the + * EMM.sys driver for it doesn't seem to want to do that.. + * + * Version: @(#)isamem.c 1.0.8 2018/10/23 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "machine/machine.h" +#include "io.h" +#include "mem.h" +#include "device.h" +#include "ui.h" +#include "plat.h" +#include "isamem.h" + + +#define ISAMEM_DEBUG 0 + +#define RAM_TOPMEM (640 << 10) /* end of low memory */ +#define RAM_UMAMEM (384 << 10) /* upper memory block */ +#define RAM_EXTMEM (1024 << 10) /* start of high memory */ + +#define EMS_MAXSIZE (2048 << 10) /* max EMS memory size */ +#define EMS_PGSIZE (16 << 10) /* one page is this big */ +#define EMS_MAXPAGE 4 /* number of viewport pages */ + + +typedef struct { + int8_t enabled; /* 1=ENABLED */ + uint8_t page; /* page# in EMS RAM */ + uint8_t frame; /* (varies with board) */ + char pad; + uint8_t *addr; /* start addr in EMS RAM */ + mem_mapping_t mapping; /* mapping entry for page */ +} emsreg_t; + +typedef struct { + const char *name; + uint8_t board : 6, /* board type */ + reserved : 2; + + uint8_t flags; +#define FLAG_CONFIG 0x01 /* card is configured */ +#define FLAG_WIDE 0x10 /* card uses 16b mode */ +#define FLAG_FAST 0x20 /* fast (<= 120ns) chips */ +#define FLAG_EMS 0x40 /* card has EMS mode enabled */ + + uint16_t total_size; /* configured size in KB */ + uint32_t base_addr, /* configured I/O address */ + start_addr, /* configured memory start */ + frame_addr; /* configured frame address */ + + uint16_t ems_size, /* EMS size in KB */ + ems_pages; /* EMS size in pages */ + uint32_t ems_start; /* start of EMS in RAM */ + + uint8_t *ram; /* allocated RAM buffer */ + + mem_mapping_t low_mapping; /* mapping for low mem */ + mem_mapping_t high_mapping; /* mapping for high mem */ + + emsreg_t ems[EMS_MAXPAGE]; /* EMS controller registers */ +} memdev_t; + +#ifdef ENABLE_ISAMEM_LOG +int isamem_do_log = ENABLE_ISAMEM_LOG; + + +static void +isamem_log(const char *fmt, ...) +{ + va_list ap; + + if (isamem_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define isamem_log(fmt, ...) +#endif + + +/* Read one byte from onboard RAM. */ +static uint8_t +ram_readb(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + uint8_t ret = 0xff; + + /* Grab the data. */ + ret = *(uint8_t *)(dev->ram + (addr - map->base)); + + return(ret); +} + + +/* Read one word from onboard RAM. */ +static uint16_t +ram_readw(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + uint16_t ret = 0xffff; + + /* Grab the data. */ + ret = *(uint16_t *)(dev->ram + (addr - map->base)); + + return(ret); +} + + +/* Write one byte to onboard RAM. */ +static void +ram_writeb(uint32_t addr, uint8_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + + /* Write the data. */ + *(uint8_t *)(dev->ram + (addr - map->base)) = val; +} + + +/* Write one word to onboard RAM. */ +static void +ram_writew(uint32_t addr, uint16_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + + /* Write the data. */ + *(uint16_t *)(dev->ram + (addr - map->base)) = val; +} + + +/* Read one byte from onboard paged RAM. */ +static uint8_t +ems_readb(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + uint8_t ret = 0xff; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Grab the data. */ + ret = *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)); +#if ISAMEM_DEBUG + if ((addr % 4096)==0) isamem_log("EMS readb(%06x) = %02x\n",addr-map->base,ret); +#endif + + return(ret); +} + + +/* Read one word from onboard paged RAM. */ +static uint16_t +ems_readw(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + uint16_t ret = 0xffff; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Grab the data. */ + ret = *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)); +#if ISAMEM_DEBUG + if ((addr % 4096)==0) isamem_log("EMS readw(%06x) = %04x\n",addr-map->base,ret); +#endif + + return(ret); +} + + +/* Write one byte to onboard paged RAM. */ +static void +ems_writeb(uint32_t addr, uint8_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Write the data. */ +#if ISAMEM_DEBUG + if ((addr % 4096)==0) isamem_log("EMS writeb(%06x, %02x)\n",addr-map->base,val); +#endif + *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; +} + + +/* Write one word to onboard paged RAM. */ +static void +ems_writew(uint32_t addr, uint16_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Write the data. */ +#if ISAMEM_DEBUG + if ((addr % 4096)==0) isamem_log("EMS writew(%06x, %04x)\n",addr-map->base,val); +#endif + *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +ems_read(uint16_t port, void *priv) +{ + memdev_t *dev = (memdev_t *)priv; + uint8_t ret = 0xff; + int vpage; + + /* Get the viewport page number. */ + vpage = (port / EMS_PGSIZE); + port &= (EMS_PGSIZE - 1); + + switch(port - dev->base_addr) { + case 0x0000: /* page number register */ + ret = dev->ems[vpage].page; + if (dev->ems[vpage].enabled) + ret |= 0x80; + break; + + case 0x0001: /* W/O */ + break; + } + +#if ISAMEM_DEBUG + isamem_log("ISAMEM: read(%04x) = %02x)\n", port, ret); +#endif + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +ems_write(uint16_t port, uint8_t val, void *priv) +{ + memdev_t *dev = (memdev_t *)priv; + int vpage; + + /* Get the viewport page number. */ + vpage = (port / EMS_PGSIZE); + port &= (EMS_PGSIZE - 1); + +#if ISAMEM_DEBUG + isamem_log("ISAMEM: write(%04x, %02x) page=%d\n", port, val, vpage); +#endif + + switch(port - dev->base_addr) { + case 0x0000: /* page mapping registers */ + /* Set the page number. */ + dev->ems[vpage].enabled = (val & 0x80); + dev->ems[vpage].page = (val & 0x7f); + + /* Make sure we can do that.. */ + if (dev->flags & FLAG_CONFIG) { + if (dev->ems[vpage].page < dev->ems_pages) { + /* Pre-calculate the page address in EMS RAM. */ + dev->ems[vpage].addr = dev->ram + dev->ems_start + ((val & 0x7f) * EMS_PGSIZE); + } else { + /* That page does not exist. */ + dev->ems[vpage].enabled = 0; + } + + if (dev->ems[vpage].enabled) { + /* Update the EMS RAM address for this page. */ + mem_mapping_set_exec(&dev->ems[vpage].mapping, + dev->ems[vpage].addr); + + /* Enable this page. */ + mem_mapping_enable(&dev->ems[vpage].mapping); + } else { + /* Disable this page. */ + mem_mapping_disable(&dev->ems[vpage].mapping); + } + } + break; + + case 0x0001: /* page frame registers */ + /* + * The EV-159 EMM driver configures the frame address + * by setting bits in these registers. The information + * in their manual is unclear, but here is what was + * found out by repeatedly changing EMM's config: + * + * 00 04 08 Address + * ----------------- + * 80 c0 e0 C0000 + * 80 c0 e0 C4000 + * 80 c0 e0 C8000 + * 80 c0 e0 CC000 + * 80 c0 e0 D0000 + * 80 c0 e0 D4000 + * 80 c0 e0 D8000 + * 80 c0 e0 DC000 + * 80 c0 e0 E0000 + */ +isamem_log("EMS: write(%02x) to register 1 !\n"); + dev->ems[vpage].frame = val; + if (val) + dev->flags |= FLAG_CONFIG; + break; + } +} + + +/* Initialize the device for use. */ +static void * +isamem_init(const device_t *info) +{ + memdev_t *dev; + uint32_t k, t; + uint32_t addr; + uint32_t tot; + uint8_t *ptr; + int i; + + /* Find our device and create an instance. */ + dev = (memdev_t *)malloc(sizeof(memdev_t)); + memset(dev, 0x00, sizeof(memdev_t)); + dev->name = info->name; + dev->board = info->local; + + /* Do per-board initialization. */ + tot = 0; + switch(dev->board) { + case 0: /* IBM PC/XT Memory Expansion Card */ + case 2: /* Paradise Systems 5-PAK */ + dev->total_size = device_get_config_int("size"); + dev->start_addr = device_get_config_int("start"); + tot = dev->total_size; + break; + + case 1: /* IBM PC/AT Memory Expansion Card */ + dev->total_size = device_get_config_int("size"); + dev->start_addr = device_get_config_int("start"); + tot = dev->total_size; + dev->flags |= FLAG_WIDE; + break; + + case 3: /* Micro Mainframe EMS-5150(T) */ + dev->base_addr = device_get_config_hex16("base"); + dev->total_size = device_get_config_int("size"); + dev->frame_addr = 0xD0000; + dev->flags |= (FLAG_EMS | FLAG_CONFIG); + break; + + case 10: /* Everex EV-159 RAM 3000 */ + dev->base_addr = device_get_config_hex16("base"); + dev->total_size = device_get_config_int("size"); + dev->start_addr = device_get_config_int("start"); + tot = device_get_config_int("length"); + if (!!device_get_config_int("width")) + dev->flags |= FLAG_WIDE; + if (!!device_get_config_int("speed")) + dev->flags |= FLAG_FAST; + if (!!device_get_config_int("ems")) + dev->flags |= FLAG_EMS; +dev->frame_addr = 0xE0000; + break; + + case 11: + dev->base_addr = device_get_config_hex16("base"); + dev->total_size = device_get_config_int("size"); + dev->start_addr = device_get_config_int("start"); + dev->frame_addr = device_get_config_hex20("frame"); + if (!!device_get_config_int("width")) + dev->flags |= FLAG_WIDE; + if (!!device_get_config_int("speed")) + dev->flags |= FLAG_FAST; + break; + } + + /* Fix up the memory start address. */ + dev->start_addr <<= 10; + + /* Say hello! */ + isamem_log("ISAMEM: %s (%iKB", info->name, dev->total_size); + if (tot && (dev->total_size != tot)) + isamem_log(", %iKB for RAM", tot); + if (dev->flags & FLAG_FAST) isamem_log(", FAST"); + if (dev->flags & FLAG_WIDE) isamem_log(", 16BIT"); + isamem_log(")\n"); + + /* Force (back to) 8-bit bus if needed. */ + if ((!AT) && (dev->flags & FLAG_WIDE)) { + isamem_log("ISAMEM: not AT+ system, forcing 8-bit mode!\n"); + dev->flags &= ~FLAG_WIDE; + } + + /* Allocate and initialize our RAM. */ + k = dev->total_size << 10; + dev->ram = (uint8_t *)malloc(k); + memset(dev->ram, 0x00, k); + ptr = dev->ram; + + /* + * The 'Memory Start Address' switch indicates at which address + * we should start adding memory. No memory is added if it is + * set to 0. + */ + tot <<= 10; + addr = dev->start_addr; + if (addr > 0 && tot > 0) { + /* Adjust K for the RAM we will use. */ + k -= tot; + + /* + * First, see if we have to expand the conventional + * (low) memory area. This can extend up to 640KB, + * so check this first. + */ + t = (addr < RAM_TOPMEM) ? RAM_TOPMEM - addr : 0; + if (t > 0) { + /* + * We need T bytes to extend that area. + * + * If the board doesn't have that much, grab + * as much as we can. + */ + if (t > tot) + t = tot; + isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr>>10, t>>10); + + /* Create, initialize and enable the low-memory mapping. */ + mem_mapping_add(&dev->low_mapping, addr, t, + ram_readb, + (dev->flags&FLAG_WIDE) ? ram_readw : NULL, + NULL, + ram_writeb, + (dev->flags&FLAG_WIDE) ? ram_writew : NULL, + NULL, + ptr, MEM_MAPPING_EXTERNAL, &dev->low_mapping); + mem_mapping_set_dev(&dev->low_mapping, dev); + + /* Tell the memory system this is external RAM. */ + mem_set_mem_state(addr, t, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + /* Update pointers. */ + ptr += t; + tot -= t; + addr += t; + } + + /* Skip to high memory if needed. */ + if ((addr == RAM_TOPMEM) && (tot >= RAM_UMAMEM)) { + /* + * We have more RAM available, but we are at the + * top of conventional RAM. So, the next 384K are + * skipped, and placed into different mappings so + * they can be re-mapped later. + */ + t = RAM_UMAMEM; /* 384KB */ + + isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr>>10, t>>10); + + /* Update and enable the remap. */ + mem_mapping_del(&ram_remapped_mapping); + mem_mapping_add(&ram_remapped_mapping, + addr + tot, t, + ram_readb, ram_readw, NULL, + ram_writeb, ram_writew, NULL, + ptr, MEM_MAPPING_EXTERNAL, + &ram_remapped_mapping); + mem_mapping_set_exec(&ram_remapped_mapping, ptr); + mem_mapping_set_dev(&ram_remapped_mapping, dev); + mem_mapping_disable(&ram_remapped_mapping); + + /* Tell the memory system this is external RAM. */ + mem_set_mem_state(addr + tot, t, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + /* Update pointers. */ + ptr += t; + tot -= t; + addr += t; + } + } + + /* + * Next, on systems that support it (80286 and up), we can add + * (some of) our RAM to the system as Extended Memory, that is, + * memory located above 1MB. This memory cannot be addressed in + * real mode (so, not by DOS, for example) but it can be used in + * protected mode. + */ + if (AT && addr > 0 && tot > 0) { + t = tot; + isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr>>10, t>>10); + + /* Create, initialize and enable the high-memory mapping. */ + mem_mapping_add(&dev->high_mapping, addr, t, + ram_readb, ram_readw, NULL, + ram_writeb, ram_writew, NULL, + ptr, MEM_MAPPING_EXTERNAL, &dev->high_mapping); + mem_mapping_set_dev(&dev->high_mapping, dev); + + /* Tell the memory system this is external RAM. */ + mem_set_mem_state(addr, t, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + /* Update pointers. */ + ptr += t; + tot -= t; + addr += t; + } + + /* If EMS is enabled, use the remainder for EMS. */ + if (dev->flags & FLAG_EMS) { + /* EMS 3.2 cannot have more than 2048KB per board. */ + t = k; + if (t > EMS_MAXSIZE) + t = EMS_MAXSIZE; + + /* Set up where EMS begins in local RAM, and how much we have. */ + dev->ems_start = ptr - dev->ram; + dev->ems_size = t >> 10; + dev->ems_pages = t / EMS_PGSIZE; + isamem_log("ISAMEM: EMS enabled, I/O=%04XH, %iKB (%i pages)", + dev->base_addr, dev->ems_size, dev->ems_pages); + if (dev->frame_addr > 0) + isamem_log(", Frame=%05XH", dev->frame_addr); + isamem_log("\n"); + + /* + * For each supported page (we can have a maximum of 4), + * create, initialize and disable the mappings, and set + * up the I/O control handler. + */ + for (i = 0; i < EMS_MAXPAGE; i++) { + /* Create and initialize a page mapping. */ + mem_mapping_add(&dev->ems[i].mapping, + dev->frame_addr + (EMS_PGSIZE*i), EMS_PGSIZE, + ems_readb, + (dev->flags&FLAG_WIDE) ? ems_readw : NULL, + NULL, + ems_writeb, + (dev->flags&FLAG_WIDE) ? ems_writew : NULL, + NULL, + ptr, MEM_MAPPING_EXTERNAL, + &dev->ems[i].mapping); + mem_mapping_set_dev(&dev->ems[i].mapping, dev); + + /* For now, disable it. */ + mem_mapping_disable(&dev->ems[i].mapping); + + /* Set up an I/O port handler. */ + io_sethandler(dev->base_addr + (EMS_PGSIZE*i), 2, + ems_read,NULL,NULL, ems_write,NULL,NULL, dev); + } + } + + /* Let them know our device instance. */ + return((void *) dev); +} + + +/* Remove the device from the system. */ +static void +isamem_close(void *priv) +{ + memdev_t *dev = (memdev_t *)priv; + int i; + + if (dev->flags & FLAG_EMS) { + for (i = 0; i < EMS_MAXPAGE; i++) { + io_removehandler(dev->base_addr + (EMS_PGSIZE*i), 2, + ems_read,NULL,NULL, ems_write,NULL,NULL, dev); + + } + } + + if (dev->ram != NULL) + free(dev->ram); + + free(dev); +} + + +static const device_config_t ibmxt_config[] = +{ + { + "size", "Memory Size", CONFIG_SPINNER, "", 128, + { { 0 } }, + { { 0 } }, + { 0, 512, 16 } + }, + { + "start", "Start Address", CONFIG_SPINNER, "", 256, + { { 0 } }, + { { 0 } }, + { 0, 640-64, 64 } + }, + { + "", "", -1 + } +}; + +static const device_t ibmxt_device = { + "IBM PC/XT Memory Expansion", + DEVICE_ISA, + 0, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + ibmxt_config +}; + + +static const device_config_t ibmat_config[] = +{ + { + "size", "Memory Size", CONFIG_SPINNER, "", 512, + { { 0 } }, + { { 0 } }, + { 0, 4096, 512 } + }, + { + "start", "Start Address", CONFIG_SPINNER, "", 512, + { { 0 } }, + { { 0 } }, + { 0, 16128, 128 } + }, + { + "", "", -1 + } +}; + +static const device_t ibmat_device = { + "IBM PC/AT Memory Expansion", + DEVICE_ISA, + 1, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + ibmat_config +}; + + +static const device_config_t p5pak_config[] = +{ + { + "size", "Memory Size", CONFIG_SPINNER, "", 128, + { { 0 } }, + { { 0 } }, + { 0, 384, 64 } + }, + { + "start", "Start Address", CONFIG_SPINNER, "", 512, + { { 0 } }, + { { 0 } }, + { 64, 576, 64 } + }, + { + "", "", -1 + } +}; + +static const device_t p5pak_device = { + "Paradise Systems 5-PAK", + DEVICE_ISA, + 2, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + p5pak_config +}; + + +static const device_config_t ems5150_config[] = +{ + { + "size", "Memory Size", CONFIG_SPINNER, "", 256, + { { 0 } }, + { { 0 } }, + { 0, 2048, 64 } + }, + { + "base", "Address", CONFIG_HEX16, "", 0, + { + { + "Disabled", 0 + }, + { + "Board 1", 0x0208 + }, + { + "Board 2", 0x020a + }, + { + "Board 3", 0x020c + }, + { + "Board 4", 0x020e + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_t ems5150_device = { + "Micro Mainframe EMS-5150(T)", + DEVICE_ISA, + 3, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + ems5150_config +}; + + +static const device_config_t ev159_config[] = +{ + { + "size", "Memory Size", CONFIG_SPINNER, "", 512, + { { 0 } }, + { { 0 } }, + { 0, 3072, 512 } + }, + { + "start", "Start Address", CONFIG_SPINNER, "", 0, + { { 0 } }, + { { 0 } }, + { 0, 16128, 128 } + }, + { + "length", "Contiguous Size", CONFIG_SPINNER, "", 0, + { { 0 } }, + { { 0 } }, + { 0, 16384, 128 } + }, + { + "width", "I/O Width", CONFIG_SELECTION, "", 0, + { + { + "8-bit", 0 + }, + { + "16-bit", 1 + }, + { + "" + } + }, + }, + { + "speed", "Transfer Speed", CONFIG_SELECTION, "", 0, + { + { + "Standard (150ns)", 0 + }, + { + "High-Speed (120ns)", 1 + }, + { + "" + } + } + }, + { + "ems", "EMS mode", CONFIG_SELECTION, "", 0, + { + { + "Disabled", 0 + }, + { + "Enabled", 1 + }, + { + "" + } + }, + }, + { + "base", "Address", CONFIG_HEX16, "", 0x0258, + { + { + "208H", 0x0208 + }, + { + "218H", 0x0218 + }, + { + "258H", 0x0258 + }, + { + "268H", 0x0268 + }, + { + "2A8H", 0x02A8 + }, + { + "2B8H", 0x02B8 + }, + { + "2E8H", 0x02E8 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_t ev159_device = { + "Everex EV-159 RAM 3000 Deluxe", + DEVICE_ISA, + 10, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + ev159_config +}; + + +#ifdef USE_ISAMEM_RAMPAGE +static const device_config_t rampage_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x0258, + { + { + "208H", 0x0208 + }, + { + "218H", 0x0218 + }, + { + "258H", 0x0258 + }, + { + "268H", 0x0268 + }, + { + "2A8H", 0x02A8 + }, + { + "2B8H", 0x02B8 + }, + { + "2E8H", 0x02E8 + }, + { + "" + } + }, + }, + { + "frame", "Frame Address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0x00000 + }, + { + "C000H", 0xC0000 + }, + { + "D000H", 0xD0000 + }, + { + "E000H", 0xE0000 + }, + { + "" + } + }, + }, + { + "width", "I/O Width", CONFIG_SELECTION, "", 8, + { + { + "8-bit", 8 + }, + { + "16-bit", 16 + }, + { + "" + } + }, + }, + { + "speed", "Transfer Speed", CONFIG_SELECTION, "", 0, + { + { + "Standard", 0 + }, + { + "High-Speed", 1 + }, + { + "" + } + } + }, + { + "size", "Memory Size", CONFIG_SPINNER, "", 128, + { { 0 } }, + { { 0 } }, + { 0, 8192, 128 } + }, + { + "", "", -1 + } +}; + +static const device_t isamem_rampage_device = { + "AST RAMpage/XT", + DEVICE_ISA, + 11, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + rampage_config +}; +#endif + + +static const struct { + const char *internal_name; + const device_t *dev; +} boards[] = { + { "none", NULL }, + { "ibmxt", &ibmxt_device }, + { "ibmat", &ibmat_device }, + { "p5pak", &p5pak_device }, + { "ems5150", &ems5150_device }, + { "ev159", &ev159_device }, +#ifdef USE_ISAMEM_BRAT + { "brat", &brat_device }, +#endif +#ifdef USE_ISAMEM_RAMPAGE + { "rampage", &rampage_device }, +#endif +#ifdef USE_ISAMEM_IAB + { "iab", &iab_device }, +#endif + { NULL, NULL } +}; + + +void +isamem_reset(void) +{ + int k, i; + + for (i = 0; i < ISAMEM_MAX; i++) { + k = isamem_type[i]; + if (k == 0) continue; + + /* Add the instance to the system. */ + device_add_inst(boards[k].dev, i + 1); + } +} + + +const char * +isamem_get_name(int board) +{ + if (boards[board].dev == NULL) return(NULL); + + return(boards[board].dev->name); +} + + +const char * +isamem_get_internal_name(int board) +{ + return(boards[board].internal_name); +} + + + +int +isamem_get_from_internal_name(const char *s) +{ + int c = 0; + + while (boards[c].internal_name != NULL) { + if (! strcmp(boards[c].internal_name, s)) + return(c); + c++; + } + + /* Not found. */ + return(0); +} + + +const device_t * +isamem_get_device(int board) +{ + /* Add the instance to the system. */ + return boards[board].dev; +} diff --git a/src/isamem.h b/src/isamem.h new file mode 100644 index 000000000..a612df500 --- /dev/null +++ b/src/isamem.h @@ -0,0 +1,77 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the ISAMEM cards. + * + * Version: @(#)isamem.h 1.0.1 2018/08/18 + * + * Authors: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + */ +#ifndef ISAMEM_H +# define ISAMEM_H + + +#define ISAMEM_MAX 4 /* max #cards in system */ + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables. */ +extern const device_t isamem_device; +extern const device_t isamem_brat80_device; +extern const device_t isamem_ev159_device; + + +/* Functions. */ +extern void isamem_reset(void); + +extern const char *isamem_get_name(int t); +extern const char *isamem_get_internal_name(int t); +extern int isamem_get_from_internal_name(const char *s); +extern const device_t *isamem_get_device(int t); + +#ifdef __cplusplus +} +#endif + + +#endif /*ISAMEM_H*/ diff --git a/src/isartc.c b/src/isartc.c new file mode 100644 index 000000000..22da01027 --- /dev/null +++ b/src/isartc.c @@ -0,0 +1,760 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of a Clock/RTC Card for the ISA PC/XT. + * + * Systems starting with the PC/XT had, by default, a realtime + * clock and NVR chip on the mainboard. The BIOS stored config + * data in the NVR, and the system could maintain time and date + * using the RTC. + * + * Originally, PC systems did not have this, and they first did + * show up in non-IBM clone systems. Shortly after, expansion + * cards with this function became available for the PC's (ISA) + * bus, and they came in many forms and designs. + * + * This implementation offers some of those boards: + * + * Everex EV-170 (using NatSemi MM58167 chip) + * DTK PII-147 Hexa I/O Plus (using UMC 82C8167 chip) + * + * and more will follow as time permits. + * + * NOTE: The IRQ functionalities have been implemented, but not yet + * tested, as I need to write test software for them first :) + * + * Version: @(#)isartc.c 1.0.7 2018/10/17 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. +*/ +#include +#include +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "timer.h" +#include "machine/machine.h" +#include "io.h" +#include "device.h" +#include "nvr.h" +#include "ui.h" +#include "plat.h" +#include "pic.h" +#include "isartc.h" + + +#define ISARTC_DEBUG 0 + + +typedef struct { + const char *name; /* board name */ + uint8_t board; /* board type */ + + uint8_t flags; /* various flags */ +#define FLAG_YEAR80 0x01 /* YEAR byte is base-80 */ +#define FLAG_YEARBCD 0x02 /* YEAR byte is in BCD */ + + int8_t irq; /* configured IRQ channel */ + int8_t base_addrsz; + uint32_t base_addr; /* configured I/O address */ + + /* Fields for the specific driver. */ + void (*f_wr)(uint16_t, uint8_t, void *); + uint8_t (*f_rd)(uint16_t, void *); + int8_t year; /* register for YEAR value */ + char pad[3]; + + nvr_t nvr; /* RTC/NVR */ +} rtcdev_t; + + +/************************************************************************ + * * + * Driver for the NatSemi MM58167 chip. * + * * + ************************************************************************/ +#define MM67_REGS 32 + +/* Define the RTC chip registers - see datasheet, pg4. */ +#define MM67_MSEC 0 /* milliseconds */ +#define MM67_HUNTEN 1 /* hundredths/tenths of seconds */ +#define MM67_SEC 2 /* seconds */ +#define MM67_MIN 3 /* minutes */ +#define MM67_HOUR 4 /* hours */ +#define MM67_DOW 5 /* day of the week */ +#define MM67_DOM 6 /* day of the month */ +#define MM67_MON 7 /* month */ +#define MM67_AL_MSEC 8 /* milliseconds */ +#define MM67_AL_HUNTEN 9 /* hundredths/tenths of seconds */ +#define MM67_AL_SEC 10 /* seconds */ +#define MM67_AL_MIN 11 /* minutes */ +#define MM67_AL_HOUR 12 /* hours */ +#define MM67_AL_DOW 13 /* day of the week */ +#define MM67_AL_DOM 14 /* day of the month */ +#define MM67_AL_MON 15 /* month */ +# define MM67_AL_DONTCARE 0xc0 /* always match in compare */ +#define MM67_ISTAT 16 /* IRQ status */ +#define MM67_ICTRL 17 /* IRQ control */ +# define MM67INT_COMPARE 0x01 /* Compare */ +# define MM67INT_TENTH 0x02 /* Tenth */ +# define MM67INT_SEC 0x04 /* Second */ +# define MM67INT_MIN 0x08 /* Minute */ +# define MM67INT_HOUR 0x10 /* Hour */ +# define MM67INT_DAY 0x20 /* Day */ +# define MM67INT_WEEK 0x40 /* Week */ +# define MM67INT_MON 0x80 /* Month */ +#define MM67_RSTCTR 18 /* reset counters */ +#define MM67_RSTRAM 19 /* reset RAM */ +#define MM67_STATUS 20 /* status bit */ +#define MM67_GOCMD 21 /* GO Command */ +#define MM67_STBYIRQ 22 /* standby IRQ */ +#define MM67_TEST 31 /* test mode */ + +#ifdef ENABLE_ISARTC_LOG +int isartc_do_log = ENABLE_ISARTC_LOG; + + +static void +isartc_log(const char *fmt, ...) +{ + va_list ap; + + if (isartc_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define isartc_log(fmt, ...) +#endif + + +/* Check if the current time matches a set alarm time. */ +static int8_t +mm67_chkalrm(nvr_t *nvr, int8_t addr) +{ + return((nvr->regs[addr-MM67_AL_SEC+MM67_SEC] == nvr->regs[addr]) || + ((nvr->regs[addr] & MM67_AL_DONTCARE) == MM67_AL_DONTCARE)); +} + + +/* + * This is called every second through the NVR/RTC hook. + * + * We fake a 'running' RTC by updating its registers on + * each passing second. Not exactly accurate, but good + * enough. + * + * Note that this code looks nasty because of all the + * BCD to decimal vv going on. + */ +static void +mm67_tick(nvr_t *nvr) +{ + rtcdev_t *dev = (rtcdev_t *)nvr->data; + uint8_t *regs = nvr->regs; + int mon, year, f = 0; + + /* Update and set interrupt if needed. */ + regs[MM67_SEC] = RTC_BCDINC(nvr->regs[MM67_SEC], 1); + if (regs[MM67_ICTRL] & MM67INT_SEC) f = MM67INT_SEC; + + /* Roll over? */ + if (regs[MM67_SEC] >= RTC_BCD(60)) { + /* Update and set interrupt if needed. */ + regs[MM67_SEC] = RTC_BCD(0); + regs[MM67_MIN] = RTC_BCDINC(regs[MM67_MIN], 1); + if (regs[MM67_ICTRL] & MM67INT_MIN) f = MM67INT_MIN; + + /* Roll over? */ + if (regs[MM67_MIN] >= RTC_BCD(60)) { + /* Update and set interrupt if needed. */ + regs[MM67_MIN] = RTC_BCD(0); + regs[MM67_HOUR] = RTC_BCDINC(regs[MM67_HOUR], 1); + if (regs[MM67_ICTRL] & MM67INT_HOUR) f = MM67INT_HOUR; + + /* Roll over? */ + if (regs[MM67_HOUR] >= RTC_BCD(24)) { + /* Update and set interrupt if needed. */ + regs[MM67_HOUR] = RTC_BCD(0); + regs[MM67_DOW] = RTC_BCDINC(regs[MM67_DOW], 1); + if (regs[MM67_ICTRL] & MM67INT_DAY) f = MM67INT_DAY; + + /* Roll over? */ + if (regs[MM67_DOW] > RTC_BCD(7)) { + /* Update and set interrupt if needed. */ + regs[MM67_DOW] = RTC_BCD(1); + if (regs[MM67_ICTRL] & MM67INT_WEEK) f = MM67INT_WEEK; + } + + /* Roll over? */ + regs[MM67_DOM] = RTC_BCDINC(regs[MM67_DOM], 1); + mon = RTC_DCB(regs[MM67_MON]); + if (dev->year != -1) { + year = RTC_DCB(regs[dev->year]); + if (dev->flags & FLAG_YEAR80) + year += 80; + } else + year = 80; + year += 1900; + if (RTC_DCB(regs[MM67_DOM]) > nvr_get_days(mon, year)) { + /* Update and set interrupt if needed. */ + regs[MM67_DOM] = RTC_BCD(1); + regs[MM67_MON] = RTC_BCDINC(regs[MM67_MON], 1); + if (regs[MM67_ICTRL] & MM67INT_MON) f = MM67INT_MON; + + /* Roll over? */ + if (regs[MM67_MON] > RTC_BCD(12)) { + /* Update. */ + regs[MM67_MON] = RTC_BCD(1); + if (dev->year != -1) { + year++; + if (dev->flags & FLAG_YEAR80) + year -= 80; + + if (dev->flags & FLAG_YEARBCD) + regs[dev->year] = RTC_BCD(year % 100); + else + regs[dev->year] = year % 100; + } + } + } + } + } + } + + /* Check for programmed alarm interrupt. */ + if (regs[MM67_ICTRL] & MM67INT_COMPARE) { + year = 1; + for (mon = MM67_AL_SEC; mon <= MM67_AL_MON; mon++) + if (mon != dev->year) + year &= mm67_chkalrm(nvr, mon); + f = year ? MM67INT_COMPARE : 0x00; + } + + /* Raise the IRQ if needed (and if we have one..) */ + if (f != 0) { + regs[MM67_ISTAT] = f; + if (nvr->irq != -1) + picint(1 << nvr->irq); + } +} + + +/* Get the current NVR time. */ +static void +mm67_time_get(nvr_t *nvr, struct tm *tm) +{ + rtcdev_t *dev = (rtcdev_t *)nvr->data; + uint8_t *regs = nvr->regs; + + /* NVR is in BCD data mode. */ + tm->tm_sec = RTC_DCB(regs[MM67_SEC]); + tm->tm_min = RTC_DCB(regs[MM67_MIN]); + tm->tm_hour = RTC_DCB(regs[MM67_HOUR]); + tm->tm_wday = (RTC_DCB(regs[MM67_DOW]) - 1); + tm->tm_mday = RTC_DCB(regs[MM67_DOM]); + tm->tm_mon = (RTC_DCB(regs[MM67_MON]) - 1); + if (dev->year != -1) { + if (dev->flags & FLAG_YEARBCD) + tm->tm_year = RTC_DCB(regs[dev->year]); + else + tm->tm_year = regs[dev->year]; + if (dev->flags & FLAG_YEAR80) + tm->tm_year += 80; +#ifdef MM67_CENTURY + tm->tm_year += (regs[MM67_CENTURY] * 100) - 1900; +#endif +#if ISARTC_DEBUG > 1 + isartc_log("ISARTC: get_time: year=%i [%02x]\n", tm->tm_year, regs[dev->year]); +#endif + } +} + + +/* Set the current NVR time. */ +static void +mm67_time_set(nvr_t *nvr, struct tm *tm) +{ + rtcdev_t *dev = (rtcdev_t *)nvr->data; + uint8_t *regs = nvr->regs; + int year; + + /* NVR is in BCD data mode. */ + regs[MM67_SEC] = RTC_BCD(tm->tm_sec); + regs[MM67_MIN] = RTC_BCD(tm->tm_min); + regs[MM67_HOUR] = RTC_BCD(tm->tm_hour); + regs[MM67_DOW] = RTC_BCD(tm->tm_wday + 1); + regs[MM67_DOM] = RTC_BCD(tm->tm_mday); + regs[MM67_MON] = RTC_BCD(tm->tm_mon + 1); + if (dev->year != -1) { + year = tm->tm_year; + if (dev->flags & FLAG_YEAR80) + year -= 80; + if (dev->flags & FLAG_YEARBCD) + regs[dev->year] = RTC_BCD(year % 100); + else + regs[dev->year] = year % 100; +#ifdef MM67_CENTURY + regs[MM67_CENTURY] = (year + 1900) / 100; +#endif +#if ISARTC_DEBUG > 1 + isartc_log("ISARTC: set_time: [%02x] year=%i (%i)\n", regs[dev->year], year, tm->tm_year); +#endif + } +} + + +static void +mm67_start(nvr_t *nvr) +{ + struct tm tm; + + /* Initialize the internal and chip times. */ + if (time_sync) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + mm67_time_set(nvr, &tm); + } else { + /* Set the internal clock from the chip time. */ + mm67_time_get(nvr, &tm); + nvr_time_set(&tm); + } +} + + +/* Reset the RTC counters to a sane state. */ +static void +mm67_reset(nvr_t *nvr) +{ + int i; + + /* Initialize the RTC to a known state. */ + for (i = MM67_MSEC; i <= MM67_MON; i++) + nvr->regs[i] = RTC_BCD(0); + nvr->regs[MM67_DOW] = RTC_BCD(1); + nvr->regs[MM67_DOM] = RTC_BCD(1); + nvr->regs[MM67_MON] = RTC_BCD(1); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +mm67_read(uint16_t port, void *priv) +{ + rtcdev_t *dev = (rtcdev_t *)priv; + int reg = port - dev->base_addr; + uint8_t ret = 0xff; + + /* This chip is directly mapped on I/O. */ + sub_cycles(ISA_CYCLES(4)); + + switch(reg) { + case MM67_ISTAT: /* IRQ status (RO) */ + ret = dev->nvr.regs[reg]; + dev->nvr.regs[reg] = 0x00; + if (dev->irq != -1) + picintc(1 << dev->irq); + break; + + default: + ret = dev->nvr.regs[reg]; + break; + } + +#if ISARTC_DEBUG + isartc_log("ISARTC: read(%04x) = %02x\n", port-dev->base_addr, ret); +#endif + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +mm67_write(uint16_t port, uint8_t val, void *priv) +{ + rtcdev_t *dev = (rtcdev_t *)priv; + int reg = port - dev->base_addr; + int i; + +#if ISARTC_DEBUG + isartc_log("ISARTC: write(%04x, %02x)\n", port-dev->base_addr, val); +#endif + + /* This chip is directly mapped on I/O. */ + sub_cycles(ISA_CYCLES(4)); + + switch(reg) { + case MM67_ISTAT: /* intr status (RO) */ + break; + + case MM67_ICTRL: /* intr control */ + dev->nvr.regs[MM67_ISTAT] = 0x00; + dev->nvr.regs[reg] = val; + break; + + case MM67_RSTCTR: + if (val == 0xff) + mm67_reset(&dev->nvr); + break; + + case MM67_RSTRAM: + if (val == 0xff) { + for (i = MM67_AL_MSEC; i <= MM67_AL_MON; i++) + dev->nvr.regs[i] = RTC_BCD(0); + dev->nvr.regs[MM67_DOW] = RTC_BCD(1); + dev->nvr.regs[MM67_DOM] = RTC_BCD(1); + dev->nvr.regs[MM67_MON] = RTC_BCD(1); + if (dev->year != -1) { + val = (dev->flags & FLAG_YEAR80) ? 0 : 80; + if (dev->flags & FLAG_YEARBCD) + dev->nvr.regs[dev->year] = RTC_BCD(val); + else + dev->nvr.regs[dev->year] = val; +#ifdef MM67_CENTURY + dev->nvr.regs[MM67_CENTURY] = 19; +#endif + } + } + break; + + case MM67_STATUS: /* STATUS (RO) */ + break; + + case MM67_GOCMD: +isartc_log("RTC: write gocmd=%02x\n", val); + break; + + case MM67_STBYIRQ: +isartc_log("RTC: write stby=%02x\n", val); + break; + + case MM67_TEST: +isartc_log("RTC: write test=%02x\n", val); + break; + + default: + dev->nvr.regs[reg] = val; + break; + } +} + + +/************************************************************************ + * * + * Generic code for all supported chips. * + * * + ************************************************************************/ + +/* Initialize the device for use. */ +static void * +isartc_init(const device_t *info) +{ + rtcdev_t *dev; + + /* Create a device instance. */ + dev = (rtcdev_t *)malloc(sizeof(rtcdev_t)); + memset(dev, 0x00, sizeof(rtcdev_t)); + dev->name = info->name; + dev->board = info->local; + dev->irq = -1; + dev->year = -1; + dev->nvr.data = dev; + dev->nvr.size = 16; + + /* Do per-board initialization. */ + switch(dev->board) { + case 0: /* Everex EV-170 Magic I/O */ + dev->flags |= FLAG_YEAR80; + dev->base_addr = device_get_config_hex16("base"); + dev->base_addrsz = 32; + dev->irq = device_get_config_int("irq"); + dev->f_rd = mm67_read; + dev->f_wr = mm67_write; + dev->nvr.reset = mm67_reset; + dev->nvr.start = mm67_start; + dev->nvr.tick = mm67_tick; + dev->year = MM67_AL_DOM; /* year, NON STANDARD */ + break; + + case 1: /* DTK PII-147 Hexa I/O Plus */ + dev->flags |= FLAG_YEARBCD; + dev->base_addr = device_get_config_hex16("base"); + dev->base_addrsz = 32; + dev->f_rd = mm67_read; + dev->f_wr = mm67_write; + dev->nvr.reset = mm67_reset; + dev->nvr.start = mm67_start; + dev->nvr.tick = mm67_tick; + dev->year = MM67_AL_HUNTEN; /* year, NON STANDARD */ + break; + + case 2: /* Paradise Systems 5PAK */ + dev->flags |= FLAG_YEAR80; + dev->base_addr = 0x02c0; + dev->base_addrsz = 32; + dev->irq = device_get_config_int("irq"); + dev->f_rd = mm67_read; + dev->f_wr = mm67_write; + dev->nvr.reset = mm67_reset; + dev->nvr.start = mm67_start; + dev->nvr.tick = mm67_tick; + dev->year = MM67_AL_DOM; /* year, NON STANDARD */ + break; + + default: + break; + } + + /* Say hello! */ + isartc_log("ISARTC: %s (I/O=%04XH", info->name, dev->base_addr); + if (dev->irq != -1) + isartc_log(", IRQ%i", dev->irq); + isartc_log(")\n"); + + /* Set up an I/O port handler. */ + io_sethandler(dev->base_addr, dev->base_addrsz, + dev->f_rd,NULL,NULL, dev->f_wr,NULL,NULL, dev); + + /* Hook into the NVR backend. */ + dev->nvr.fn = (wchar_t *)isartc_get_internal_name(isartc_type); + dev->nvr.irq = dev->irq; + nvr_init(&dev->nvr); + + /* Let them know our device instance. */ + return((void *)dev); +} + + +/* Remove the device from the system. */ +static void +isartc_close(void *priv) +{ + rtcdev_t *dev = (rtcdev_t *)priv; + + io_removehandler(dev->base_addr, dev->base_addrsz, + dev->f_rd,NULL,NULL, dev->f_wr,NULL,NULL, dev); + + if (dev->nvr.fn != NULL) + free((wchar_t *)dev->nvr.fn); + + free(dev); +} + + +static const device_config_t ev170_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x02C0, + { + { + "240H", 0x0240 + }, + { + "2C0H", 0x02c0 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", -1, + { + { + "Disabled", -1 + }, + { + "IRQ2", 2 + }, + { + "IRQ5", 5 + }, + { + "IRQ7", 7 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_t ev170_device = { + "Everex EV-170 Magic I/O", + DEVICE_ISA, + 0, + isartc_init, isartc_close, NULL, + NULL, NULL, NULL, + ev170_config +}; + + +static const device_config_t pii147_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x0240, + { + { + "Clock 1", 0x0240 + }, + { + "Clock 2", 0x0340 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_t pii147_device = { + "DTK PII-147 Hexa I/O Plus", + DEVICE_ISA, + 1, + isartc_init, isartc_close, NULL, + NULL, NULL, NULL, + pii147_config +}; + + +static const device_config_t p5pak_config[] = { + { + "irq", "IRQ", CONFIG_SELECTION, "", -1, + { + { + "Disabled", -1 + }, + { + "IRQ2", 2 + }, + { + "IRQ3", 3 + }, + { + "IRQ5", 5 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_t p5pak_device = { + "Paradise Systems 5-PAK", + DEVICE_ISA, + 2, + isartc_init, isartc_close, NULL, + NULL, NULL, NULL, + p5pak_config +}; + + +static const struct { + const char *name; + const char *internal_name; + const device_t *dev; +} boards[] = { + { "None", "none", NULL, }, + { "Everex EV-170 Magic I/O", "ev170", &ev170_device, }, + { "DTK PII-147 Hexa I/O Plus", "pii147", &pii147_device, }, + { "Paradise Systems 5-PAK", "p5pak", &p5pak_device, }, + { "", "", NULL, }, +}; + + +void +isartc_reset(void) +{ + if (isartc_type == 0) return; + + /* Add the device to the system. */ + device_add(boards[isartc_type].dev); +} + + +char * +isartc_get_name(int board) +{ + return((char *)boards[board].name); +} + + +char * +isartc_get_internal_name(int board) +{ + return((char *)boards[board].internal_name); +} + + +int +isartc_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *) boards[c].internal_name)) { + if (! strcmp(boards[c].internal_name, s)) + return(c); + c++; + } + + /* Not found. */ + return(0); +} + + +const device_t * +isartc_get_device(int board) +{ + return(boards[board].dev); +} diff --git a/src/isartc.h b/src/isartc.h new file mode 100644 index 000000000..457cb1c6d --- /dev/null +++ b/src/isartc.h @@ -0,0 +1,71 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the ISARTC cards. + * + * Version: @(#)isartc.h 1.0.1 2018/08/27 + * + * Authors: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + */ +#ifndef ISARTC_H +# define ISARTC_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables. */ + + +/* Functions. */ +extern void isartc_reset(void); + +extern char *isartc_get_name(int t); +extern char *isartc_get_internal_name(int t); +extern int isartc_get_from_internal_name(char *s); +extern const device_t *isartc_get_device(int t); + +#ifdef __cplusplus +} +#endif + + +#endif /*ISARTC_H*/ diff --git a/src/keyboard.c b/src/keyboard.c index 55fea6571..68f5017df 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -8,15 +8,15 @@ * * General keyboard driver interface. * - * Version: @(#)keyboard.c 1.0.15 2018/03/19 + * Version: @(#)keyboard.c 1.0.16 2019/03/05 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2015-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2015-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -27,7 +27,6 @@ #include "keyboard.h" -int64_t keyboard_delay; int keyboard_scan; void (*keyboard_send)(uint16_t val); @@ -51,7 +50,6 @@ keyboard_init(void) memset(recv_key, 0x00, sizeof(recv_key)); keyboard_scan = 1; - keyboard_delay = 0; scan_table = NULL; memset(keyboard_set3_flags, 0x00, sizeof(keyboard_set3_flags)); @@ -75,6 +73,7 @@ fake_shift_needed(uint16_t scan) case 0x148: case 0x149: case 0x14a: + case 0x14b: case 0x14d: case 0x14f: case 0x150: @@ -97,10 +96,10 @@ key_process(uint16_t scan, int down) if (! keyboard_scan) return; oldkey[scan] = down; - if (down && codes[scan].mk[0] == -1) + if (down && codes[scan].mk[0] == 0) return; - if (!down && codes[scan].brk[0] == -1) + if (!down && codes[scan].brk[0] == 0) return; if (AT && ((keyboard_mode & 3) == 3)) { @@ -113,10 +112,10 @@ key_process(uint16_t scan, int down) /* Send the special code indicating an opening fake shift might be needed. */ if (fake_shift_needed(scan)) keyboard_send(0x100); - while (codes[scan].mk[c] != -1) + while (codes[scan].mk[c] != 0) keyboard_send(codes[scan].mk[c++]); } else { - while (codes[scan].brk[c] != -1) + while (codes[scan].brk[c] != 0) keyboard_send(codes[scan].brk[c++]); /* Send the special code indicating a closing fake shift might be needed. */ if (fake_shift_needed(scan)) @@ -157,13 +156,13 @@ keyboard_input(int down, uint16_t scan) shift |= 0x20; break; case 0x038: /* Left Alt */ - shift |= 0x03; + shift |= 0x04; break; case 0x138: /* Right Alt */ - shift |= 0x30; + shift |= 0x40; break; - } - } else { + } + } else { switch(scan & 0x1ff) { case 0x01c: /* Left Ctrl */ shift &= ~0x01; @@ -178,10 +177,10 @@ keyboard_input(int down, uint16_t scan) shift &= ~0x20; break; case 0x038: /* Left Alt */ - shift &= ~0x03; + shift &= ~0x04; break; case 0x138: /* Right Alt */ - shift &= ~0x30; + shift &= ~0x40; break; case 0x03a: /* Caps Lock */ caps_lock ^= 1; @@ -265,33 +264,33 @@ keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl) if (caps_lock != cl) { i = 0; - while (codes[0x03a].mk[i] != -1) + while (codes[0x03a].mk[i] != 0) keyboard_send(codes[0x03a].mk[i++]); if (keyboard_do_break(0x03a)) { i = 0; - while (codes[0x03a].brk[i] != -1) + while (codes[0x03a].brk[i] != 0) keyboard_send(codes[0x03a].brk[i++]); } } if (num_lock != nl) { i = 0; - while (codes[0x045].mk[i] != -1) + while (codes[0x045].mk[i] != 0) keyboard_send(codes[0x045].mk[i++]); if (keyboard_do_break(0x045)) { i = 0; - while (codes[0x045].brk[i] != -1) + while (codes[0x045].brk[i] != 0) keyboard_send(codes[0x045].brk[i++]); } } if (scroll_lock != sl) { i = 0; - while (codes[0x046].mk[i] != -1) + while (codes[0x046].mk[i] != 0) keyboard_send(codes[0x046].mk[i++]); if (keyboard_do_break(0x046)) { i = 0; - while (codes[0x046].brk[i] != -1) + while (codes[0x046].brk[i] != 0) keyboard_send(codes[0x046].brk[i++]); } } diff --git a/src/keyboard.h b/src/keyboard.h index e4c846b7d..78cd50a86 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -8,23 +8,23 @@ * * Definitions for the keyboard interface. * - * Version: @(#)keyboard.h 1.0.15 2018/03/26 + * Version: @(#)keyboard.h 1.0.19 2019/10/30 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_KEYBOARD_H # define EMU_KEYBOARD_H typedef struct { - int mk[9]; - int brk[9]; + const uint8_t mk[4]; + const uint8_t brk[4]; } scancode; @@ -46,7 +46,6 @@ extern "C" { extern uint8_t keyboard_mode; extern int keyboard_scan; -extern int64_t keyboard_delay; extern void (*keyboard_send)(uint16_t val); extern void kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)); @@ -60,12 +59,22 @@ extern int mouse_queue_start, mouse_queue_end; extern int mouse_scan; #ifdef EMU_DEVICE_H +extern const device_t keyboard_pc_device; +extern const device_t keyboard_pc82_device; extern const device_t keyboard_xt_device; +extern const device_t keyboard_xt86_device; +extern const device_t keyboard_xt_compaq_device; extern const device_t keyboard_tandy_device; +#if defined(DEV_BRANCH) && defined(USE_LASERXT) +extern const device_t keyboard_xt_lxt3_device; +#endif extern const device_t keyboard_at_device; extern const device_t keyboard_at_ami_device; extern const device_t keyboard_at_toshiba_device; extern const device_t keyboard_ps2_device; +extern const device_t keyboard_ps2_ps1_device; +extern const device_t keyboard_ps2_ps2_device; +extern const device_t keyboard_ps2_xi8088_device; extern const device_t keyboard_ps2_ami_device; extern const device_t keyboard_ps2_mca_device; extern const device_t keyboard_ps2_mca_2_device; @@ -94,6 +103,7 @@ extern void keyboard_at_adddata_mouse(uint8_t val); extern void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val,void *), void *); extern uint8_t keyboard_at_get_mouse_scan(void); extern void keyboard_at_set_mouse_scan(uint8_t val); +extern void keyboard_at_reset(void); #ifdef __cplusplus } diff --git a/src/keyboard_at.c b/src/keyboard_at.c index 391f725be..7da1c4380 100644 --- a/src/keyboard_at.c +++ b/src/keyboard_at.c @@ -8,15 +8,15 @@ * * Intel 8042 (AT keyboard controller) emulation. * - * Version: @(#)keyboard_at.c 1.0.37 2018/05/25 + * Version: @(#)keyboard_at.c 1.0.46 2020/01/11 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #include #include @@ -27,14 +27,13 @@ #include #include "86box.h" #include "cpu/cpu.h" +#include "timer.h" #include "io.h" #include "pic.h" #include "pit.h" #include "ppi.h" #include "mem.h" -#include "rom.h" #include "device.h" -#include "timer.h" #include "machine/machine.h" #include "machine/m_xt_xi8088.h" #include "machine/m_at_t3100e.h" @@ -44,103 +43,87 @@ #include "sound/snd_speaker.h" #include "video/video.h" #include "keyboard.h" -#include "mouse.h" -#define STAT_PARITY 0x80 -#define STAT_RTIMEOUT 0x40 -#define STAT_TTIMEOUT 0x20 -#define STAT_MFULL 0x20 -#define STAT_LOCK 0x10 -#define STAT_CD 0x08 -#define STAT_SYSFLAG 0x04 -#define STAT_IFULL 0x02 -#define STAT_OFULL 0x01 +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_MFULL 0x20 +#define STAT_UNLOCKED 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 -#define PS2_REFRESH_TIME (16LL * TIMER_USEC) +#define PS2_REFRESH_TIME (16 * TIMER_USEC) -#define CCB_UNUSED 0x80 -#define CCB_TRANSLATE 0x40 -#define CCB_PCMODE 0x20 -#define CCB_ENABLEKBD 0x10 -#define CCB_IGNORELOCK 0x08 -#define CCB_SYSTEM 0x04 -#define CCB_ENABLEMINT 0x02 -#define CCB_ENABLEKINT 0x01 +#define CCB_UNUSED 0x80 +#define CCB_TRANSLATE 0x40 +#define CCB_PCMODE 0x20 +#define CCB_ENABLEKBD 0x10 +#define CCB_IGNORELOCK 0x08 +#define CCB_SYSTEM 0x04 +#define CCB_ENABLEMINT 0x02 +#define CCB_ENABLEKINT 0x01 -#define CCB_MASK 0x68 -#define MODE_MASK 0x6C +#define CCB_MASK 0x68 +#define MODE_MASK 0x6c -#define KBC_TYPE_ISA 0x00 -#define KBC_TYPE_PS2_1 0x01 -#define KBC_TYPE_PS2_2 0x02 +#define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ +#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */ +#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */ +#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */ #define KBC_TYPE_MASK 0x03 #define KBC_VEN_GENERIC 0x00 #define KBC_VEN_AMI 0x04 #define KBC_VEN_IBM_MCA 0x08 -#define KBC_VEN_QUADTEL 0x0C +#define KBC_VEN_QUADTEL 0x0c #define KBC_VEN_TOSHIBA 0x10 -#define KBC_VEN_MASK 0x1C +#define KBC_VEN_XI8088 0x14 +#define KBC_VEN_IBM_PS1 0x18 +#define KBC_VEN_ACER 0x1c +#define KBC_VEN_MASK 0x1c + typedef struct { - int initialized; - int want60, - wantirq, - wantirq12; - uint8_t command; - uint8_t status; + uint8_t command, status, out, secr_phase, + mem_addr, input_port, output_port, old_output_port, + key_command, output_locked, ami_stat, initialized, + want60, wantirq, key_wantdata, refresh, first_write; + uint8_t mem[0x100]; - uint8_t out; + int out_new, out_delayed; - uint8_t secr_phase; - uint8_t mem_addr; - - uint8_t input_port, - output_port; - - uint8_t old_output_port; - - uint8_t key_command; - int key_wantdata; - int last_irq; - uint8_t last_scan_code; - - int dtrans; - int first_write; - - int64_t refresh_time; - int refresh; - uint32_t flags; - uint8_t output_locked; - int64_t pulse_cb; - uint8_t ami_stat; + pc_timer_t refresh_time, pulse_cb; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); - int64_t timeout; + pc_timer_t send_delay_timer; +#ifdef USE_NEW_STUFF + /* Custom machine-dependent keyboard stuff. */ + uint8_t (*read_func)(void *priv); + void (*write_func)(void *priv, uint8_t val); + void *func_priv; +#endif } atkbd_t; /* bit 0 = repeat, bit 1 = makes break code? */ -uint8_t keyboard_set3_flags[512]; -uint8_t keyboard_set3_all_repeat; -uint8_t keyboard_set3_all_break; +uint8_t keyboard_set3_flags[512]; +uint8_t keyboard_set3_all_repeat; +uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ -uint8_t keyboard_mode = 0x42; +uint8_t keyboard_mode = 0x42; -#ifdef ENABLE_KEYBOARD_AT_LOG -int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; -#endif - -int mouse_queue_start = 0, - mouse_queue_end = 0; +int mouse_queue_start = 0, + mouse_queue_end = 0; static uint8_t key_ctrl_queue[16]; @@ -153,440 +136,445 @@ static uint8_t mouse_queue[16]; static void (*mouse_write)(uint8_t val, void *priv) = NULL; static void *mouse_p = NULL; static uint8_t sc_or = 0; -static atkbd_t *CurrentKbd = NULL; // FIXME: remove!!! --FvK +static atkbd_t *SavedKbd = NULL; // FIXME: remove!!! --FvK /* Non-translated to translated scan codes. */ static const uint8_t nont_to_t[256] = { - 0xFF, 0x43, 0x41, 0x3F, 0x3D, 0x3B, 0x3C, 0x58, - 0x64, 0x44, 0x42, 0x40, 0x3E, 0x0F, 0x29, 0x59, - 0x65, 0x38, 0x2A, 0x70, 0x1D, 0x10, 0x02, 0x5A, - 0x66, 0x71, 0x2C, 0x1F, 0x1E, 0x11, 0x03, 0x5B, - 0x67, 0x2E, 0x2D, 0x20, 0x12, 0x05, 0x04, 0x5C, - 0x68, 0x39, 0x2F, 0x21, 0x14, 0x13, 0x06, 0x5D, - 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5E, - 0x6A, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5F, - 0x6B, 0x33, 0x25, 0x17, 0x18, 0x0B, 0x0A, 0x60, - 0x6C, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0C, 0x61, - 0x6D, 0x73, 0x28, 0x74, 0x1A, 0x0D, 0x62, 0x6E, - 0x3A, 0x36, 0x1C, 0x1B, 0x75, 0x2B, 0x63, 0x76, - 0x55, 0x56, 0x77, 0x78, 0x79, 0x7A, 0x0E, 0x7B, - 0x7C, 0x4F, 0x7D, 0x4B, 0x47, 0x7E, 0x7F, 0x6F, - 0x52, 0x53, 0x50, 0x4C, 0x4D, 0x48, 0x01, 0x45, - 0x57, 0x4E, 0x51, 0x4A, 0x37, 0x49, 0x46, 0x54, + 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, + 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 + 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 }; +#ifdef USE_SET1 static const scancode scancode_set1[512] = { - { { -1},{ -1} }, { { 0x01,-1},{ 0x81,-1} }, { { 0x02,-1},{ 0x82,-1} }, { { 0x03,-1},{ 0x83,-1} }, /*000*/ - { { 0x04,-1},{ 0x84,-1} }, { { 0x05,-1},{ 0x85,-1} }, { { 0x06,-1},{ 0x86,-1} }, { { 0x07,-1},{ 0x87,-1} }, /*004*/ - { { 0x08,-1},{ 0x88,-1} }, { { 0x09,-1},{ 0x89,-1} }, { { 0x0a,-1},{ 0x8a,-1} }, { { 0x0b,-1},{ 0x8b,-1} }, /*008*/ - { { 0x0c,-1},{ 0x8c,-1} }, { { 0x0d,-1},{ 0x8d,-1} }, { { 0x0e,-1},{ 0x8e,-1} }, { { 0x0f,-1},{ 0x8f,-1} }, /*00c*/ - { { 0x10,-1},{ 0x90,-1} }, { { 0x11,-1},{ 0x91,-1} }, { { 0x12,-1},{ 0x92,-1} }, { { 0x13,-1},{ 0x93,-1} }, /*010*/ - { { 0x14,-1},{ 0x94,-1} }, { { 0x15,-1},{ 0x95,-1} }, { { 0x16,-1},{ 0x96,-1} }, { { 0x17,-1},{ 0x97,-1} }, /*014*/ - { { 0x18,-1},{ 0x98,-1} }, { { 0x19,-1},{ 0x99,-1} }, { { 0x1a,-1},{ 0x9a,-1} }, { { 0x1b,-1},{ 0x9b,-1} }, /*018*/ - { { 0x1c,-1},{ 0x9c,-1} }, { { 0x1d,-1},{ 0x9d,-1} }, { { 0x1e,-1},{ 0x9e,-1} }, { { 0x1f,-1},{ 0x9f,-1} }, /*01c*/ - { { 0x20,-1},{ 0xa0,-1} }, { { 0x21,-1},{ 0xa1,-1} }, { { 0x22,-1},{ 0xa2,-1} }, { { 0x23,-1},{ 0xa3,-1} }, /*020*/ - { { 0x24,-1},{ 0xa4,-1} }, { { 0x25,-1},{ 0xa5,-1} }, { { 0x26,-1},{ 0xa6,-1} }, { { 0x27,-1},{ 0xa7,-1} }, /*024*/ - { { 0x28,-1},{ 0xa8,-1} }, { { 0x29,-1},{ 0xa9,-1} }, { { 0x2a,-1},{ 0xaa,-1} }, { { 0x2b,-1},{ 0xab,-1} }, /*028*/ - { { 0x2c,-1},{ 0xac,-1} }, { { 0x2d,-1},{ 0xad,-1} }, { { 0x2e,-1},{ 0xae,-1} }, { { 0x2f,-1},{ 0xaf,-1} }, /*02c*/ - { { 0x30,-1},{ 0xb0,-1} }, { { 0x31,-1},{ 0xb1,-1} }, { { 0x32,-1},{ 0xb2,-1} }, { { 0x33,-1},{ 0xb3,-1} }, /*030*/ - { { 0x34,-1},{ 0xb4,-1} }, { { 0x35,-1},{ 0xb5,-1} }, { { 0x36,-1},{ 0xb6,-1} }, { { 0x37,-1},{ 0xb7,-1} }, /*034*/ - { { 0x38,-1},{ 0xb8,-1} }, { { 0x39,-1},{ 0xb9,-1} }, { { 0x3a,-1},{ 0xba,-1} }, { { 0x3b,-1},{ 0xbb,-1} }, /*038*/ - { { 0x3c,-1},{ 0xbc,-1} }, { { 0x3d,-1},{ 0xbd,-1} }, { { 0x3e,-1},{ 0xbe,-1} }, { { 0x3f,-1},{ 0xbf,-1} }, /*03c*/ - { { 0x40,-1},{ 0xc0,-1} }, { { 0x41,-1},{ 0xc1,-1} }, { { 0x42,-1},{ 0xc2,-1} }, { { 0x43,-1},{ 0xc3,-1} }, /*040*/ - { { 0x44,-1},{ 0xc4,-1} }, { { 0x45,-1},{ 0xc5,-1} }, { { 0x46,-1},{ 0xc6,-1} }, { { 0x47,-1},{ 0xc7,-1} }, /*044*/ - { { 0x48,-1},{ 0xc8,-1} }, { { 0x49,-1},{ 0xc9,-1} }, { { 0x4a,-1},{ 0xca,-1} }, { { 0x4b,-1},{ 0xcb,-1} }, /*048*/ - { { 0x4c,-1},{ 0xcc,-1} }, { { 0x4d,-1},{ 0xcd,-1} }, { { 0x4e,-1},{ 0xce,-1} }, { { 0x4f,-1},{ 0xcf,-1} }, /*04c*/ - { { 0x50,-1},{ 0xd0,-1} }, { { 0x51,-1},{ 0xd1,-1} }, { { 0x52,-1},{ 0xd2,-1} }, { { 0x53,-1},{ 0xd3,-1} }, /*050*/ - { { 0x54,-1},{ 0xd4,-1} }, { { 0x55,-1},{ 0xd5,-1} }, { { 0x56,-1},{ 0xd6,-1} }, { { 0x57,-1},{ 0xd7,-1} }, /*054*/ - { { 0x58,-1},{ 0xd8,-1} }, { { 0x59,-1},{ 0xd9,-1} }, { { 0x5a,-1},{ 0xda,-1} }, { { 0x5b,-1},{ 0xdb,-1} }, /*058*/ - { { 0x5c,-1},{ 0xdc,-1} }, { { 0x5d,-1},{ 0xdd,-1} }, { { 0x5e,-1},{ 0xde,-1} }, { { 0x5f,-1},{ 0xdf,-1} }, /*05c*/ - { { 0x60,-1},{ 0xe0,-1} }, { { 0x61,-1},{ 0xe1,-1} }, { { 0x62,-1},{ 0xe2,-1} }, { { 0x63,-1},{ 0xe3,-1} }, /*060*/ - { { 0x64,-1},{ 0xe4,-1} }, { { 0x65,-1},{ 0xe5,-1} }, { { 0x66,-1},{ 0xe6,-1} }, { { 0x67,-1},{ 0xe7,-1} }, /*064*/ - { { 0x68,-1},{ 0xe8,-1} }, { { 0x69,-1},{ 0xe9,-1} }, { { 0x6a,-1},{ 0xea,-1} }, { { 0x6b,-1},{ 0xeb,-1} }, /*068*/ - { { 0x6c,-1},{ 0xec,-1} }, { { 0x6d,-1},{ 0xed,-1} }, { { 0x6e,-1},{ 0xee,-1} }, { { 0x6f,-1},{ 0xef,-1} }, /*06c*/ - { { 0x70,-1},{ 0xf0,-1} }, { { 0x71,-1},{ 0xf1,-1} }, { { 0x72,-1},{ 0xf2,-1} }, { { 0x73,-1},{ 0xf3,-1} }, /*070*/ - { { 0x74,-1},{ 0xf4,-1} }, { { 0x75,-1},{ 0xf5,-1} }, { { 0x76,-1},{ 0xf6,-1} }, { { 0x77,-1},{ 0xf7,-1} }, /*074*/ - { { 0x78,-1},{ 0xf8,-1} }, { { 0x79,-1},{ 0xf9,-1} }, { { 0x7a,-1},{ 0xfa,-1} }, { { 0x7b,-1},{ 0xfb,-1} }, /*078*/ - { { 0x7c,-1},{ 0xfc,-1} }, { { 0x7d,-1},{ 0xfd,-1} }, { { 0x7e,-1},{ 0xfe,-1} }, { { 0x7f,-1},{ 0xff,-1} }, /*07c*/ + { { 0},{ 0} }, { { 0x01,0},{ 0x81,0} }, { { 0x02,0},{ 0x82,0} }, { { 0x03,0},{ 0x83,0} }, /*000*/ + { { 0x04,0},{ 0x84,0} }, { { 0x05,0},{ 0x85,0} }, { { 0x06,0},{ 0x86,0} }, { { 0x07,0},{ 0x87,0} }, /*004*/ + { { 0x08,0},{ 0x88,0} }, { { 0x09,0},{ 0x89,0} }, { { 0x0a,0},{ 0x8a,0} }, { { 0x0b,0},{ 0x8b,0} }, /*008*/ + { { 0x0c,0},{ 0x8c,0} }, { { 0x0d,0},{ 0x8d,0} }, { { 0x0e,0},{ 0x8e,0} }, { { 0x0f,0},{ 0x8f,0} }, /*00c*/ + { { 0x10,0},{ 0x90,0} }, { { 0x11,0},{ 0x91,0} }, { { 0x12,0},{ 0x92,0} }, { { 0x13,0},{ 0x93,0} }, /*010*/ + { { 0x14,0},{ 0x94,0} }, { { 0x15,0},{ 0x95,0} }, { { 0x16,0},{ 0x96,0} }, { { 0x17,0},{ 0x97,0} }, /*014*/ + { { 0x18,0},{ 0x98,0} }, { { 0x19,0},{ 0x99,0} }, { { 0x1a,0},{ 0x9a,0} }, { { 0x1b,0},{ 0x9b,0} }, /*018*/ + { { 0x1c,0},{ 0x9c,0} }, { { 0x1d,0},{ 0x9d,0} }, { { 0x1e,0},{ 0x9e,0} }, { { 0x1f,0},{ 0x9f,0} }, /*01c*/ + { { 0x20,0},{ 0xa0,0} }, { { 0x21,0},{ 0xa1,0} }, { { 0x22,0},{ 0xa2,0} }, { { 0x23,0},{ 0xa3,0} }, /*020*/ + { { 0x24,0},{ 0xa4,0} }, { { 0x25,0},{ 0xa5,0} }, { { 0x26,0},{ 0xa6,0} }, { { 0x27,0},{ 0xa7,0} }, /*024*/ + { { 0x28,0},{ 0xa8,0} }, { { 0x29,0},{ 0xa9,0} }, { { 0x2a,0},{ 0xaa,0} }, { { 0x2b,0},{ 0xab,0} }, /*028*/ + { { 0x2c,0},{ 0xac,0} }, { { 0x2d,0},{ 0xad,0} }, { { 0x2e,0},{ 0xae,0} }, { { 0x2f,0},{ 0xaf,0} }, /*02c*/ + { { 0x30,0},{ 0xb0,0} }, { { 0x31,0},{ 0xb1,0} }, { { 0x32,0},{ 0xb2,0} }, { { 0x33,0},{ 0xb3,0} }, /*030*/ + { { 0x34,0},{ 0xb4,0} }, { { 0x35,0},{ 0xb5,0} }, { { 0x36,0},{ 0xb6,0} }, { { 0x37,0},{ 0xb7,0} }, /*034*/ + { { 0x38,0},{ 0xb8,0} }, { { 0x39,0},{ 0xb9,0} }, { { 0x3a,0},{ 0xba,0} }, { { 0x3b,0},{ 0xbb,0} }, /*038*/ + { { 0x3c,0},{ 0xbc,0} }, { { 0x3d,0},{ 0xbd,0} }, { { 0x3e,0},{ 0xbe,0} }, { { 0x3f,0},{ 0xbf,0} }, /*03c*/ + { { 0x40,0},{ 0xc0,0} }, { { 0x41,0},{ 0xc1,0} }, { { 0x42,0},{ 0xc2,0} }, { { 0x43,0},{ 0xc3,0} }, /*040*/ + { { 0x44,0},{ 0xc4,0} }, { { 0x45,0},{ 0xc5,0} }, { { 0x46,0},{ 0xc6,0} }, { { 0x47,0},{ 0xc7,0} }, /*044*/ + { { 0x48,0},{ 0xc8,0} }, { { 0x49,0},{ 0xc9,0} }, { { 0x4a,0},{ 0xca,0} }, { { 0x4b,0},{ 0xcb,0} }, /*048*/ + { { 0x4c,0},{ 0xcc,0} }, { { 0x4d,0},{ 0xcd,0} }, { { 0x4e,0},{ 0xce,0} }, { { 0x4f,0},{ 0xcf,0} }, /*04c*/ + { { 0x50,0},{ 0xd0,0} }, { { 0x51,0},{ 0xd1,0} }, { { 0x52,0},{ 0xd2,0} }, { { 0x53,0},{ 0xd3,0} }, /*050*/ + { { 0x54,0},{ 0xd4,0} }, { { 0x55,0},{ 0xd5,0} }, { { 0x56,0},{ 0xd6,0} }, { { 0x57,0},{ 0xd7,0} }, /*054*/ + { { 0x58,0},{ 0xd8,0} }, { { 0x59,0},{ 0xd9,0} }, { { 0x5a,0},{ 0xda,0} }, { { 0x5b,0},{ 0xdb,0} }, /*058*/ + { { 0x5c,0},{ 0xdc,0} }, { { 0x5d,0},{ 0xdd,0} }, { { 0x5e,0},{ 0xde,0} }, { { 0x5f,0},{ 0xdf,0} }, /*05c*/ + { { 0x60,0},{ 0xe0,0} }, { { 0x61,0},{ 0xe1,0} }, { { 0x62,0},{ 0xe2,0} }, { { 0x63,0},{ 0xe3,0} }, /*060*/ + { { 0x64,0},{ 0xe4,0} }, { { 0x65,0},{ 0xe5,0} }, { { 0x66,0},{ 0xe6,0} }, { { 0x67,0},{ 0xe7,0} }, /*064*/ + { { 0x68,0},{ 0xe8,0} }, { { 0x69,0},{ 0xe9,0} }, { { 0x6a,0},{ 0xea,0} }, { { 0x6b,0},{ 0xeb,0} }, /*068*/ + { { 0x6c,0},{ 0xec,0} }, { { 0x6d,0},{ 0xed,0} }, { { 0x6e,0},{ 0xee,0} }, { { 0x6f,0},{ 0xef,0} }, /*06c*/ + { { 0x70,0},{ 0xf0,0} }, { { 0x71,0},{ 0xf1,0} }, { { 0x72,0},{ 0xf2,0} }, { { 0x73,0},{ 0xf3,0} }, /*070*/ + { { 0x74,0},{ 0xf4,0} }, { { 0x75,0},{ 0xf5,0} }, { { 0x76,0},{ 0xf6,0} }, { { 0x77,0},{ 0xf7,0} }, /*074*/ + { { 0x78,0},{ 0xf8,0} }, { { 0x79,0},{ 0xf9,0} }, { { 0x7a,0},{ 0xfa,0} }, { { 0x7b,0},{ 0xfb,0} }, /*078*/ + { { 0x7c,0},{ 0xfc,0} }, { { 0x7d,0},{ 0xfd,0} }, { { 0x7e,0},{ 0xfe,0} }, { { 0x7f,0},{ 0xff,0} }, /*07c*/ - { { 0x80,-1},{ -1} }, { { 0x81,-1},{ -1} }, { { 0x82,-1},{ -1} }, { { -1},{ -1} }, /*080*/ - { { -1},{ -1} }, { { 0x85,-1},{ -1} }, { { 0x86,-1},{ -1} }, { { 0x87,-1},{ -1} }, /*084*/ - { { 0x88,-1},{ -1} }, { { 0x89,-1},{ -1} }, { { 0x8a,-1},{ -1} }, { { 0x8b,-1},{ -1} }, /*088*/ - { { 0x8c,-1},{ -1} }, { { 0x8d,-1},{ -1} }, { { 0x8e,-1},{ -1} }, { { 0x8f,-1},{ -1} }, /*08c*/ - { { 0x90,-1},{ -1} }, { { 0x91,-1},{ -1} }, { { 0x92,-1},{ -1} }, { { 0x93,-1},{ -1} }, /*090*/ - { { 0x94,-1},{ -1} }, { { 0x95,-1},{ -1} }, { { 0x96,-1},{ -1} }, { { 0x97,-1},{ -1} }, /*094*/ - { { 0x98,-1},{ -1} }, { { 0x99,-1},{ -1} }, { { 0x9a,-1},{ -1} }, { { 0x9b,-1},{ -1} }, /*098*/ - { { 0x9c,-1},{ -1} }, { { 0x9d,-1},{ -1} }, { { 0x9e,-1},{ -1} }, { { 0x9f,-1},{ -1} }, /*09c*/ - { { 0xa0,-1},{ -1} }, { { 0xa1,-1},{ -1} }, { { 0xa2,-1},{ -1} }, { { 0xa3,-1},{ -1} }, /*0a0*/ - { { 0xa4,-1},{ -1} }, { { 0xa5,-1},{ -1} }, { { 0xa6,-1},{ -1} }, { { 0xa7,-1},{ -1} }, /*0a4*/ - { { 0xa8,-1},{ -1} }, { { 0xa9,-1},{ -1} }, { { 0xaa,-1},{ -1} }, { { 0xab,-1},{ -1} }, /*0a8*/ - { { 0xac,-1},{ -1} }, { { 0xad,-1},{ -1} }, { { 0xae,-1},{ -1} }, { { 0xaf,-1},{ -1} }, /*0ac*/ - { { 0xb0,-1},{ -1} }, { { 0xb1,-1},{ -1} }, { { 0xb2,-1},{ -1} }, { { 0xb3,-1},{ -1} }, /*0b0*/ - { { 0xb4,-1},{ -1} }, { { 0xb5,-1},{ -1} }, { { 0xb6,-1},{ -1} }, { { 0xb7,-1},{ -1} }, /*0b4*/ - { { 0xb8,-1},{ -1} }, { { 0xb9,-1},{ -1} }, { { 0xba,-1},{ -1} }, { { 0xbb,-1},{ -1} }, /*0b8*/ - { { 0xbc,-1},{ -1} }, { { 0xbd,-1},{ -1} }, { { 0xbe,-1},{ -1} }, { { 0xbf,-1},{ -1} }, /*0bc*/ - { { 0xc0,-1},{ -1} }, { { 0xc1,-1},{ -1} }, { { 0xc2,-1},{ -1} }, { { 0xc3,-1},{ -1} }, /*0c0*/ - { { 0xc4,-1},{ -1} }, { { 0xc5,-1},{ -1} }, { { 0xc6,-1},{ -1} }, { { 0xc7,-1},{ -1} }, /*0c4*/ - { { 0xc8,-1},{ -1} }, { { 0xc9,-1},{ -1} }, { { 0xca,-1},{ -1} }, { { 0xcb,-1},{ -1} }, /*0c8*/ - { { 0xcc,-1},{ -1} }, { { 0xcd,-1},{ -1} }, { { 0xce,-1},{ -1} }, { { 0xcf,-1},{ -1} }, /*0cc*/ - { { 0xd0,-1},{ -1} }, { { 0xd1,-1},{ -1} }, { { 0xd2,-1},{ -1} }, { { 0xd3,-1},{ -1} }, /*0d0*/ - { { 0xd4,-1},{ -1} }, { { 0xd5,-1},{ -1} }, { { 0xd6,-1},{ -1} }, { { 0xd7,-1},{ -1} }, /*0d4*/ - { { 0xd8,-1},{ -1} }, { { 0xd9,-1},{ -1} }, { { 0xda,-1},{ -1} }, { { 0xdb,-1},{ -1} }, /*0d8*/ - { { 0xdc,-1},{ -1} }, { { 0xdd,-1},{ -1} }, { { 0xde,-1},{ -1} }, { { 0xdf,-1},{ -1} }, /*0dc*/ - { { 0xe0,-1},{ -1} }, { { 0xe1,-1},{ -1} }, { { 0xe2,-1},{ -1} }, { { 0xe3,-1},{ -1} }, /*0e0*/ - { { 0xe4,-1},{ -1} }, { { 0xe5,-1},{ -1} }, { { 0xe6,-1},{ -1} }, { { 0xe7,-1},{ -1} }, /*0e4*/ - { { 0xe8,-1},{ -1} }, { { 0xe9,-1},{ -1} }, { { 0xea,-1},{ -1} }, { { 0xeb,-1},{ -1} }, /*0e8*/ - { { 0xec,-1},{ -1} }, { { 0xed,-1},{ -1} }, { { 0xee,-1},{ -1} }, { { 0xef,-1},{ -1} }, /*0ec*/ - { { -1},{ -1} }, { { 0xf1,-1},{ -1} }, { { 0xf2,-1},{ -1} }, { { 0xf3,-1},{ -1} }, /*0f0*/ - { { 0xf4,-1},{ -1} }, { { 0xf5,-1},{ -1} }, { { 0xf6,-1},{ -1} }, { { 0xf7,-1},{ -1} }, /*0f4*/ - { { 0xf8,-1},{ -1} }, { { 0xf9,-1},{ -1} }, { { 0xfa,-1},{ -1} }, { { 0xfb,-1},{ -1} }, /*0f8*/ - { { 0xfc,-1},{ -1} }, { { 0xfd,-1},{ -1} }, { { 0xfe,-1},{ -1} }, { { 0xff,-1},{ -1} }, /*0fc*/ + { { 0x80,0},{ 0} }, { { 0x81,0},{ 0} }, { { 0x82,0},{ 0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0} }, { { 0x86,0},{ 0} }, { { 0x87,0},{ 0} }, /*084*/ + { { 0x88,0},{ 0} }, { { 0x89,0},{ 0} }, { { 0x8a,0},{ 0} }, { { 0x8b,0},{ 0} }, /*088*/ + { { 0x8c,0},{ 0} }, { { 0x8d,0},{ 0} }, { { 0x8e,0},{ 0} }, { { 0x8f,0},{ 0} }, /*08c*/ + { { 0x90,0},{ 0} }, { { 0x91,0},{ 0} }, { { 0x92,0},{ 0} }, { { 0x93,0},{ 0} }, /*090*/ + { { 0x94,0},{ 0} }, { { 0x95,0},{ 0} }, { { 0x96,0},{ 0} }, { { 0x97,0},{ 0} }, /*094*/ + { { 0x98,0},{ 0} }, { { 0x99,0},{ 0} }, { { 0x9a,0},{ 0} }, { { 0x9b,0},{ 0} }, /*098*/ + { { 0x9c,0},{ 0} }, { { 0x9d,0},{ 0} }, { { 0x9e,0},{ 0} }, { { 0x9f,0},{ 0} }, /*09c*/ + { { 0xa0,0},{ 0} }, { { 0xa1,0},{ 0} }, { { 0xa2,0},{ 0} }, { { 0xa3,0},{ 0} }, /*0a0*/ + { { 0xa4,0},{ 0} }, { { 0xa5,0},{ 0} }, { { 0xa6,0},{ 0} }, { { 0xa7,0},{ 0} }, /*0a4*/ + { { 0xa8,0},{ 0} }, { { 0xa9,0},{ 0} }, { { 0xaa,0},{ 0} }, { { 0xab,0},{ 0} }, /*0a8*/ + { { 0xac,0},{ 0} }, { { 0xad,0},{ 0} }, { { 0xae,0},{ 0} }, { { 0xaf,0},{ 0} }, /*0ac*/ + { { 0xb0,0},{ 0} }, { { 0xb1,0},{ 0} }, { { 0xb2,0},{ 0} }, { { 0xb3,0},{ 0} }, /*0b0*/ + { { 0xb4,0},{ 0} }, { { 0xb5,0},{ 0} }, { { 0xb6,0},{ 0} }, { { 0xb7,0},{ 0} }, /*0b4*/ + { { 0xb8,0},{ 0} }, { { 0xb9,0},{ 0} }, { { 0xba,0},{ 0} }, { { 0xbb,0},{ 0} }, /*0b8*/ + { { 0xbc,0},{ 0} }, { { 0xbd,0},{ 0} }, { { 0xbe,0},{ 0} }, { { 0xbf,0},{ 0} }, /*0bc*/ + { { 0xc0,0},{ 0} }, { { 0xc1,0},{ 0} }, { { 0xc2,0},{ 0} }, { { 0xc3,0},{ 0} }, /*0c0*/ + { { 0xc4,0},{ 0} }, { { 0xc5,0},{ 0} }, { { 0xc6,0},{ 0} }, { { 0xc7,0},{ 0} }, /*0c4*/ + { { 0xc8,0},{ 0} }, { { 0xc9,0},{ 0} }, { { 0xca,0},{ 0} }, { { 0xcb,0},{ 0} }, /*0c8*/ + { { 0xcc,0},{ 0} }, { { 0xcd,0},{ 0} }, { { 0xce,0},{ 0} }, { { 0xcf,0},{ 0} }, /*0cc*/ + { { 0xd0,0},{ 0} }, { { 0xd1,0},{ 0} }, { { 0xd2,0},{ 0} }, { { 0xd3,0},{ 0} }, /*0d0*/ + { { 0xd4,0},{ 0} }, { { 0xd5,0},{ 0} }, { { 0xd6,0},{ 0} }, { { 0xd7,0},{ 0} }, /*0d4*/ + { { 0xd8,0},{ 0} }, { { 0xd9,0},{ 0} }, { { 0xda,0},{ 0} }, { { 0xdb,0},{ 0} }, /*0d8*/ + { { 0xdc,0},{ 0} }, { { 0xdd,0},{ 0} }, { { 0xde,0},{ 0} }, { { 0xdf,0},{ 0} }, /*0dc*/ + { { 0xe0,0},{ 0} }, { { 0xe1,0},{ 0} }, { { 0xe2,0},{ 0} }, { { 0xe3,0},{ 0} }, /*0e0*/ + { { 0xe4,0},{ 0} }, { { 0xe5,0},{ 0} }, { { 0xe6,0},{ 0} }, { { 0xe7,0},{ 0} }, /*0e4*/ + { { 0xe8,0},{ 0} }, { { 0xe9,0},{ 0} }, { { 0xea,0},{ 0} }, { { 0xeb,0},{ 0} }, /*0e8*/ + { { 0xec,0},{ 0} }, { { 0xed,0},{ 0} }, { { 0xee,0},{ 0} }, { { 0xef,0},{ 0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0} }, { { 0xf2,0},{ 0} }, { { 0xf3,0},{ 0} }, /*0f0*/ + { { 0xf4,0},{ 0} }, { { 0xf5,0},{ 0} }, { { 0xf6,0},{ 0} }, { { 0xf7,0},{ 0} }, /*0f4*/ + { { 0xf8,0},{ 0} }, { { 0xf9,0},{ 0} }, { { 0xfa,0},{ 0} }, { { 0xfb,0},{ 0} }, /*0f8*/ + { { 0xfc,0},{ 0} }, { { 0xfd,0},{ 0} }, { { 0xfe,0},{ 0} }, { { 0xff,0},{ 0} }, /*0fc*/ - { {0xe1,0x1d,-1},{0xe1, 0x9d,-1} }, { {0xe0,0x01,-1},{0xe0, 0x81,-1} }, { {0xe0,0x02,-1},{0xe0, 0x82,-1} }, { {0xe0,0x03,-1},{0xe0, 0x83,-1} }, /*100*/ - { {0xe0,0x04,-1},{0xe0, 0x84,-1} }, { {0xe0,0x05,-1},{0xe0, 0x85,-1} }, { {0xe0,0x06,-1},{0xe0, 0x86,-1} }, { {0xe0,0x07,-1},{0xe0, 0x87,-1} }, /*104*/ - { {0xe0,0x08,-1},{0xe0, 0x88,-1} }, { {0xe0,0x09,-1},{0xe0, 0x89,-1} }, { {0xe0,0x0a,-1},{0xe0, 0x8a,-1} }, { {0xe0,0x0b,-1},{0xe0, 0x8b,-1} }, /*108*/ - { {0xe0,0x0c,-1},{0xe0, 0x8c,-1} }, { { -1},{ -1} }, { {0xe0,0x0e,-1},{0xe0, 0x8e,-1} }, { {0xe0,0x0f,-1},{0xe0, 0x8f,-1} }, /*10c*/ - { {0xe0,0x10,-1},{0xe0, 0x90,-1} }, { {0xe0,0x11,-1},{0xe0, 0x91,-1} }, { {0xe0,0x12,-1},{0xe0, 0x92,-1} }, { {0xe0,0x13,-1},{0xe0, 0x93,-1} }, /*110*/ - { {0xe0,0x14,-1},{0xe0, 0x94,-1} }, { {0xe0,0x15,-1},{0xe0, 0x95,-1} }, { {0xe0,0x16,-1},{0xe0, 0x96,-1} }, { {0xe0,0x17,-1},{0xe0, 0x97,-1} }, /*114*/ - { {0xe0,0x18,-1},{0xe0, 0x98,-1} }, { {0xe0,0x19,-1},{0xe0, 0x99,-1} }, { {0xe0,0x1a,-1},{0xe0, 0x9a,-1} }, { {0xe0,0x1b,-1},{0xe0, 0x9b,-1} }, /*118*/ - { {0xe0,0x1c,-1},{0xe0, 0x9c,-1} }, { {0xe0,0x1d,-1},{0xe0, 0x9d,-1} }, { {0xe0,0x1e,-1},{0xe0, 0x9e,-1} }, { {0xe0,0x1f,-1},{0xe0, 0x9f,-1} }, /*11c*/ - { {0xe0,0x20,-1},{0xe0, 0xa0,-1} }, { {0xe0,0x21,-1},{0xe0, 0xa1,-1} }, { {0xe0,0x22,-1},{0xe0, 0xa2,-1} }, { {0xe0,0x23,-1},{0xe0, 0xa3,-1} }, /*120*/ - { {0xe0,0x24,-1},{0xe0, 0xa4,-1} }, { {0xe0,0x25,-1},{0xe0, 0xa5,-1} }, { {0xe0,0x26,-1},{0xe0, 0xa6,-1} }, { { -1},{ -1} }, /*124*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ - { {0xe0,0x2c,-1},{0xe0, 0xac,-1} }, { {0xe0,0x2d,-1},{0xe0, 0xad,-1} }, { {0xe0,0x2e,-1},{0xe0, 0xae,-1} }, { {0xe0,0x2f,-1},{0xe0, 0xaf,-1} }, /*12c*/ - { {0xe0,0x30,-1},{0xe0, 0xb0,-1} }, { {0xe0,0x31,-1},{0xe0, 0xb1,-1} }, { {0xe0,0x32,-1},{0xe0, 0xb2,-1} }, { { -1},{ -1} }, /*130*/ - { {0xe0,0x34,-1},{0xe0, 0xb4,-1} }, { {0xe0,0x35,-1},{0xe0, 0xb5,-1} }, { { -1},{ -1} }, { {0xe0,0x37,-1},{0xe0, 0xb7,-1} }, /*134*/ - { {0xe0,0x38,-1},{0xe0, 0xb8,-1} }, { { -1},{ -1} }, { {0xe0,0x3a,-1},{0xe0, 0xba,-1} }, { {0xe0,0x3b,-1},{0xe0, 0xbb,-1} }, /*138*/ - { {0xe0,0x3c,-1},{0xe0, 0xbc,-1} }, { {0xe0,0x3d,-1},{0xe0, 0xbd,-1} }, { {0xe0,0x3e,-1},{0xe0, 0xbe,-1} }, { {0xe0,0x3f,-1},{0xe0, 0xbf,-1} }, /*13c*/ - { {0xe0,0x40,-1},{0xe0, 0xc0,-1} }, { {0xe0,0x41,-1},{0xe0, 0xc1,-1} }, { {0xe0,0x42,-1},{0xe0, 0xc2,-1} }, { {0xe0,0x43,-1},{0xe0, 0xc3,-1} }, /*140*/ - { {0xe0,0x44,-1},{0xe0, 0xc4,-1} }, { { -1},{ -1} }, { {0xe0,0x46,-1},{0xe0, 0xc6,-1} }, { {0xe0,0x47,-1},{0xe0, 0xc7,-1} }, /*144*/ - { {0xe0,0x48,-1},{0xe0, 0xc8,-1} }, { {0xe0,0x49,-1},{0xe0, 0xc9,-1} }, { { -1},{ -1} }, { {0xe0,0x4b,-1},{0xe0, 0xcb,-1} }, /*148*/ - { {0xe0,0x4c,-1},{0xe0, 0xcc,-1} }, { {0xe0,0x4d,-1},{0xe0, 0xcd,-1} }, { {0xe0,0x4e,-1},{0xe0, 0xce,-1} }, { {0xe0,0x4f,-1},{0xe0, 0xcf,-1} }, /*14c*/ - { {0xe0,0x50,-1},{0xe0, 0xd0,-1} }, { {0xe0,0x51,-1},{0xe0, 0xd1,-1} }, { {0xe0,0x52,-1},{0xe0, 0xd2,-1} }, { {0xe0,0x53,-1},{0xe0, 0xd3,-1} }, /*150*/ - { { -1},{ -1} }, { {0xe0,0x55,-1},{0xe0, 0xd5,-1} }, { { -1},{ -1} }, { {0xe0,0x57,-1},{0xe0, 0xd7,-1} }, /*154*/ - { {0xe0,0x58,-1},{0xe0, 0xd8,-1} }, { {0xe0,0x59,-1},{0xe0, 0xd9,-1} }, { {0xe0,0x5a,-1},{0xe0, 0xaa,-1} }, { {0xe0,0x5b,-1},{0xe0, 0xdb,-1} }, /*158*/ - { {0xe0,0x5c,-1},{0xe0, 0xdc,-1} }, { {0xe0,0x5d,-1},{0xe0, 0xdd,-1} }, { {0xe0,0x5e,-1},{0xe0, 0xee,-1} }, { {0xe0,0x5f,-1},{0xe0, 0xdf,-1} }, /*15c*/ - { { -1},{ -1} }, { {0xe0,0x61,-1},{0xe0, 0xe1,-1} }, { {0xe0,0x62,-1},{0xe0, 0xe2,-1} }, { {0xe0,0x63,-1},{0xe0, 0xe3,-1} }, /*160*/ - { {0xe0,0x64,-1},{0xe0, 0xe4,-1} }, { {0xe0,0x65,-1},{0xe0, 0xe5,-1} }, { {0xe0,0x66,-1},{0xe0, 0xe6,-1} }, { {0xe0,0x67,-1},{0xe0, 0xe7,-1} }, /*164*/ - { {0xe0,0x68,-1},{0xe0, 0xe8,-1} }, { {0xe0,0x69,-1},{0xe0, 0xe9,-1} }, { {0xe0,0x6a,-1},{0xe0, 0xea,-1} }, { {0xe0,0x6b,-1},{0xe0, 0xeb,-1} }, /*168*/ - { {0xe0,0x6c,-1},{0xe0, 0xec,-1} }, { {0xe0,0x6d,-1},{0xe0, 0xed,-1} }, { {0xe0,0x6e,-1},{0xe0, 0xee,-1} }, { { -1},{ -1} }, /*16c*/ - { {0xe0,0x70,-1},{0xe0, 0xf0,-1} }, { {0xe0,0x71,-1},{0xe0, 0xf1,-1} }, { {0xe0,0x72,-1},{0xe0, 0xf2,-1} }, { {0xe0,0x73,-1},{0xe0, 0xf3,-1} }, /*170*/ - { {0xe0,0x74,-1},{0xe0, 0xf4,-1} }, { {0xe0,0x75,-1},{0xe0, 0xf5,-1} }, { { -1},{ -1} }, { {0xe0,0x77,-1},{0xe0, 0xf7,-1} }, /*174*/ - { {0xe0,0x78,-1},{0xe0, 0xf8,-1} }, { {0xe0,0x79,-1},{0xe0, 0xf9,-1} }, { {0xe0,0x7a,-1},{0xe0, 0xfa,-1} }, { {0xe0,0x7b,-1},{0xe0, 0xfb,-1} }, /*178*/ - { {0xe0,0x7c,-1},{0xe0, 0xfc,-1} }, { {0xe0,0x7d,-1},{0xe0, 0xfd,-1} }, { {0xe0,0x7e,-1},{0xe0, 0xfe,-1} }, { {0xe0,0x7f,-1},{0xe0, 0xff,-1} }, /*17c*/ + { {0xe1,0x1d,0},{0xe1, 0x9d,0} }, { {0xe0,0x01,0},{0xe0, 0x81,0} }, { {0xe0,0x02,0},{0xe0, 0x82,0} }, { {0xe0,0x03,0},{0xe0, 0x83,0} }, /*100*/ + { {0xe0,0x04,0},{0xe0, 0x84,0} }, { {0xe0,0x05,0},{0xe0, 0x85,0} }, { {0xe0,0x06,0},{0xe0, 0x86,0} }, { {0xe0,0x07,0},{0xe0, 0x87,0} }, /*104*/ + { {0xe0,0x08,0},{0xe0, 0x88,0} }, { {0xe0,0x09,0},{0xe0, 0x89,0} }, { {0xe0,0x0a,0},{0xe0, 0x8a,0} }, { {0xe0,0x0b,0},{0xe0, 0x8b,0} }, /*108*/ + { {0xe0,0x0c,0},{0xe0, 0x8c,0} }, { { 0},{ 0} }, { {0xe0,0x0e,0},{0xe0, 0x8e,0} }, { {0xe0,0x0f,0},{0xe0, 0x8f,0} }, /*10c*/ + { {0xe0,0x10,0},{0xe0, 0x90,0} }, { {0xe0,0x11,0},{0xe0, 0x91,0} }, { {0xe0,0x12,0},{0xe0, 0x92,0} }, { {0xe0,0x13,0},{0xe0, 0x93,0} }, /*110*/ + { {0xe0,0x14,0},{0xe0, 0x94,0} }, { {0xe0,0x15,0},{0xe0, 0x95,0} }, { {0xe0,0x16,0},{0xe0, 0x96,0} }, { {0xe0,0x17,0},{0xe0, 0x97,0} }, /*114*/ + { {0xe0,0x18,0},{0xe0, 0x98,0} }, { {0xe0,0x19,0},{0xe0, 0x99,0} }, { {0xe0,0x1a,0},{0xe0, 0x9a,0} }, { {0xe0,0x1b,0},{0xe0, 0x9b,0} }, /*118*/ + { {0xe0,0x1c,0},{0xe0, 0x9c,0} }, { {0xe0,0x1d,0},{0xe0, 0x9d,0} }, { {0xe0,0x1e,0},{0xe0, 0x9e,0} }, { {0xe0,0x1f,0},{0xe0, 0x9f,0} }, /*11c*/ + { {0xe0,0x20,0},{0xe0, 0xa0,0} }, { {0xe0,0x21,0},{0xe0, 0xa1,0} }, { {0xe0,0x22,0},{0xe0, 0xa2,0} }, { {0xe0,0x23,0},{0xe0, 0xa3,0} }, /*120*/ + { {0xe0,0x24,0},{0xe0, 0xa4,0} }, { {0xe0,0x25,0},{0xe0, 0xa5,0} }, { {0xe0,0x26,0},{0xe0, 0xa6,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x2c,0},{0xe0, 0xac,0} }, { {0xe0,0x2d,0},{0xe0, 0xad,0} }, { {0xe0,0x2e,0},{0xe0, 0xae,0} }, { {0xe0,0x2f,0},{0xe0, 0xaf,0} }, /*12c*/ + { {0xe0,0x30,0},{0xe0, 0xb0,0} }, { {0xe0,0x31,0},{0xe0, 0xb1,0} }, { {0xe0,0x32,0},{0xe0, 0xb2,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x34,0},{0xe0, 0xb4,0} }, { {0xe0,0x35,0},{0xe0, 0xb5,0} }, { { 0},{ 0} }, { {0xe0,0x37,0},{0xe0, 0xb7,0} }, /*134*/ + { {0xe0,0x38,0},{0xe0, 0xb8,0} }, { { 0},{ 0} }, { {0xe0,0x3a,0},{0xe0, 0xba,0} }, { {0xe0,0x3b,0},{0xe0, 0xbb,0} }, /*138*/ + { {0xe0,0x3c,0},{0xe0, 0xbc,0} }, { {0xe0,0x3d,0},{0xe0, 0xbd,0} }, { {0xe0,0x3e,0},{0xe0, 0xbe,0} }, { {0xe0,0x3f,0},{0xe0, 0xbf,0} }, /*13c*/ + { {0xe0,0x40,0},{0xe0, 0xc0,0} }, { {0xe0,0x41,0},{0xe0, 0xc1,0} }, { {0xe0,0x42,0},{0xe0, 0xc2,0} }, { {0xe0,0x43,0},{0xe0, 0xc3,0} }, /*140*/ + { {0xe0,0x44,0},{0xe0, 0xc4,0} }, { { 0},{ 0} }, { {0xe0,0x46,0},{0xe0, 0xc6,0} }, { {0xe0,0x47,0},{0xe0, 0xc7,0} }, /*144*/ + { {0xe0,0x48,0},{0xe0, 0xc8,0} }, { {0xe0,0x49,0},{0xe0, 0xc9,0} }, { { 0},{ 0} }, { {0xe0,0x4b,0},{0xe0, 0xcb,0} }, /*148*/ + { {0xe0,0x4c,0},{0xe0, 0xcc,0} }, { {0xe0,0x4d,0},{0xe0, 0xcd,0} }, { {0xe0,0x4e,0},{0xe0, 0xce,0} }, { {0xe0,0x4f,0},{0xe0, 0xcf,0} }, /*14c*/ + { {0xe0,0x50,0},{0xe0, 0xd0,0} }, { {0xe0,0x51,0},{0xe0, 0xd1,0} }, { {0xe0,0x52,0},{0xe0, 0xd2,0} }, { {0xe0,0x53,0},{0xe0, 0xd3,0} }, /*150*/ + { { 0},{ 0} }, { {0xe0,0x55,0},{0xe0, 0xd5,0} }, { { 0},{ 0} }, { {0xe0,0x57,0},{0xe0, 0xd7,0} }, /*154*/ + { {0xe0,0x58,0},{0xe0, 0xd8,0} }, { {0xe0,0x59,0},{0xe0, 0xd9,0} }, { {0xe0,0x5a,0},{0xe0, 0xaa,0} }, { {0xe0,0x5b,0},{0xe0, 0xdb,0} }, /*158*/ + { {0xe0,0x5c,0},{0xe0, 0xdc,0} }, { {0xe0,0x5d,0},{0xe0, 0xdd,0} }, { {0xe0,0x5e,0},{0xe0, 0xee,0} }, { {0xe0,0x5f,0},{0xe0, 0xdf,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x61,0},{0xe0, 0xe1,0} }, { {0xe0,0x62,0},{0xe0, 0xe2,0} }, { {0xe0,0x63,0},{0xe0, 0xe3,0} }, /*160*/ + { {0xe0,0x64,0},{0xe0, 0xe4,0} }, { {0xe0,0x65,0},{0xe0, 0xe5,0} }, { {0xe0,0x66,0},{0xe0, 0xe6,0} }, { {0xe0,0x67,0},{0xe0, 0xe7,0} }, /*164*/ + { {0xe0,0x68,0},{0xe0, 0xe8,0} }, { {0xe0,0x69,0},{0xe0, 0xe9,0} }, { {0xe0,0x6a,0},{0xe0, 0xea,0} }, { {0xe0,0x6b,0},{0xe0, 0xeb,0} }, /*168*/ + { {0xe0,0x6c,0},{0xe0, 0xec,0} }, { {0xe0,0x6d,0},{0xe0, 0xed,0} }, { {0xe0,0x6e,0},{0xe0, 0xee,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x70,0},{0xe0, 0xf0,0} }, { {0xe0,0x71,0},{0xe0, 0xf1,0} }, { {0xe0,0x72,0},{0xe0, 0xf2,0} }, { {0xe0,0x73,0},{0xe0, 0xf3,0} }, /*170*/ + { {0xe0,0x74,0},{0xe0, 0xf4,0} }, { {0xe0,0x75,0},{0xe0, 0xf5,0} }, { { 0},{ 0} }, { {0xe0,0x77,0},{0xe0, 0xf7,0} }, /*174*/ + { {0xe0,0x78,0},{0xe0, 0xf8,0} }, { {0xe0,0x79,0},{0xe0, 0xf9,0} }, { {0xe0,0x7a,0},{0xe0, 0xfa,0} }, { {0xe0,0x7b,0},{0xe0, 0xfb,0} }, /*178*/ + { {0xe0,0x7c,0},{0xe0, 0xfc,0} }, { {0xe0,0x7d,0},{0xe0, 0xfd,0} }, { {0xe0,0x7e,0},{0xe0, 0xfe,0} }, { {0xe0,0x7f,0},{0xe0, 0xff,0} }, /*17c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ - { { -1},{ -1} }, { {0xe0,0xe1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{ -1} }, { { -1},{ -1} }, /*1ec*/ - { { -1},{ -1} }, { {0xe0,0xf1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{ -1} }, { {0xe0,0xff,-1},{ -1} } /*1fc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{ 0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{ 0} }, { {0xe0,0xff,0},{ 0} } /*1fc*/ }; +#endif static const scancode scancode_set2[512] = { - { { -1},{ -1} }, { { 0x76,-1},{ 0xF0,0x76,-1} }, { { 0x16,-1},{ 0xF0,0x16,-1} }, { { 0x1E,-1},{ 0xF0,0x1E,-1} }, /*000*/ - { { 0x26,-1},{ 0xF0,0x26,-1} }, { { 0x25,-1},{ 0xF0,0x25,-1} }, { { 0x2E,-1},{ 0xF0,0x2E,-1} }, { { 0x36,-1},{ 0xF0,0x36,-1} }, /*004*/ - { { 0x3D,-1},{ 0xF0,0x3D,-1} }, { { 0x3E,-1},{ 0xF0,0x3E,-1} }, { { 0x46,-1},{ 0xF0,0x46,-1} }, { { 0x45,-1},{ 0xF0,0x45,-1} }, /*008*/ - { { 0x4E,-1},{ 0xF0,0x4E,-1} }, { { 0x55,-1},{ 0xF0,0x55,-1} }, { { 0x66,-1},{ 0xF0,0x66,-1} }, { { 0x0D,-1},{ 0xF0,0x0D,-1} }, /*00c*/ - { { 0x15,-1},{ 0xF0,0x15,-1} }, { { 0x1D,-1},{ 0xF0,0x1D,-1} }, { { 0x24,-1},{ 0xF0,0x24,-1} }, { { 0x2D,-1},{ 0xF0,0x2D,-1} }, /*010*/ - { { 0x2C,-1},{ 0xF0,0x2C,-1} }, { { 0x35,-1},{ 0xF0,0x35,-1} }, { { 0x3C,-1},{ 0xF0,0x3C,-1} }, { { 0x43,-1},{ 0xF0,0x43,-1} }, /*014*/ - { { 0x44,-1},{ 0xF0,0x44,-1} }, { { 0x4D,-1},{ 0xF0,0x4D,-1} }, { { 0x54,-1},{ 0xF0,0x54,-1} }, { { 0x5B,-1},{ 0xF0,0x5B,-1} }, /*018*/ - { { 0x5A,-1},{ 0xF0,0x5A,-1} }, { { 0x14,-1},{ 0xF0,0x14,-1} }, { { 0x1C,-1},{ 0xF0,0x1C,-1} }, { { 0x1B,-1},{ 0xF0,0x1B,-1} }, /*01c*/ - { { 0x23,-1},{ 0xF0,0x23,-1} }, { { 0x2B,-1},{ 0xF0,0x2B,-1} }, { { 0x34,-1},{ 0xF0,0x34,-1} }, { { 0x33,-1},{ 0xF0,0x33,-1} }, /*020*/ - { { 0x3B,-1},{ 0xF0,0x3B,-1} }, { { 0x42,-1},{ 0xF0,0x42,-1} }, { { 0x4B,-1},{ 0xF0,0x4B,-1} }, { { 0x4C,-1},{ 0xF0,0x4C,-1} }, /*024*/ - { { 0x52,-1},{ 0xF0,0x52,-1} }, { { 0x0E,-1},{ 0xF0,0x0E,-1} }, { { 0x12,-1},{ 0xF0,0x12,-1} }, { { 0x5D,-1},{ 0xF0,0x5D,-1} }, /*028*/ - { { 0x1A,-1},{ 0xF0,0x1A,-1} }, { { 0x22,-1},{ 0xF0,0x22,-1} }, { { 0x21,-1},{ 0xF0,0x21,-1} }, { { 0x2A,-1},{ 0xF0,0x2A,-1} }, /*02c*/ - { { 0x32,-1},{ 0xF0,0x32,-1} }, { { 0x31,-1},{ 0xF0,0x31,-1} }, { { 0x3A,-1},{ 0xF0,0x3A,-1} }, { { 0x41,-1},{ 0xF0,0x41,-1} }, /*030*/ - { { 0x49,-1},{ 0xF0,0x49,-1} }, { { 0x4A,-1},{ 0xF0,0x4A,-1} }, { { 0x59,-1},{ 0xF0,0x59,-1} }, { { 0x7C,-1},{ 0xF0,0x7C,-1} }, /*034*/ - { { 0x11,-1},{ 0xF0,0x11,-1} }, { { 0x29,-1},{ 0xF0,0x29,-1} }, { { 0x58,-1},{ 0xF0,0x58,-1} }, { { 0x05,-1},{ 0xF0,0x05,-1} }, /*038*/ - { { 0x06,-1},{ 0xF0,0x06,-1} }, { { 0x04,-1},{ 0xF0,0x04,-1} }, { { 0x0C,-1},{ 0xF0,0x0C,-1} }, { { 0x03,-1},{ 0xF0,0x03,-1} }, /*03c*/ - { { 0x0B,-1},{ 0xF0,0x0B,-1} }, { { 0x83,-1},{ 0xF0,0x83,-1} }, { { 0x0A,-1},{ 0xF0,0x0A,-1} }, { { 0x01,-1},{ 0xF0,0x01,-1} }, /*040*/ - { { 0x09,-1},{ 0xF0,0x09,-1} }, { { 0x77,-1},{ 0xF0,0x77,-1} }, { { 0x7E,-1},{ 0xF0,0x7E,-1} }, { { 0x6C,-1},{ 0xF0,0x6C,-1} }, /*044*/ - { { 0x75,-1},{ 0xF0,0x75,-1} }, { { 0x7D,-1},{ 0xF0,0x7D,-1} }, { { 0x7B,-1},{ 0xF0,0x7B,-1} }, { { 0x6B,-1},{ 0xF0,0x6B,-1} }, /*048*/ - { { 0x73,-1},{ 0xF0,0x73,-1} }, { { 0x74,-1},{ 0xF0,0x74,-1} }, { { 0x79,-1},{ 0xF0,0x79,-1} }, { { 0x69,-1},{ 0xF0,0x69,-1} }, /*04c*/ - { { 0x72,-1},{ 0xF0,0x72,-1} }, { { 0x7A,-1},{ 0xF0,0x7A,-1} }, { { 0x70,-1},{ 0xF0,0x70,-1} }, { { 0x71,-1},{ 0xF0,0x71,-1} }, /*050*/ - { { 0x84,-1},{ 0xF0,0x84,-1} }, { { 0x60,-1},{ 0xF0,0x60,-1} }, { { 0x61,-1},{ 0xF0,0x61,-1} }, { { 0x78,-1},{ 0xF0,0x78,-1} }, /*054*/ - { { 0x07,-1},{ 0xF0,0x07,-1} }, { { 0x0F,-1},{ 0xF0,0x0F,-1} }, { { 0x17,-1},{ 0xF0,0x17,-1} }, { { 0x1F,-1},{ 0xF0,0x1F,-1} }, /*058*/ - { { 0x27,-1},{ 0xF0,0x27,-1} }, { { 0x2F,-1},{ 0xF0,0x2F,-1} }, { { 0x37,-1},{ 0xF0,0x37,-1} }, { { 0x3F,-1},{ 0xF0,0x3F,-1} }, /*05c*/ - { { 0x47,-1},{ 0xF0,0x47,-1} }, { { 0x4F,-1},{ 0xF0,0x4F,-1} }, { { 0x56,-1},{ 0xF0,0x56,-1} }, { { 0x5E,-1},{ 0xF0,0x5E,-1} }, /*060*/ - { { 0x08,-1},{ 0xF0,0x08,-1} }, { { 0x10,-1},{ 0xF0,0x10,-1} }, { { 0x18,-1},{ 0xF0,0x18,-1} }, { { 0x20,-1},{ 0xF0,0x20,-1} }, /*064*/ - { { 0x28,-1},{ 0xF0,0x28,-1} }, { { 0x30,-1},{ 0xF0,0x30,-1} }, { { 0x38,-1},{ 0xF0,0x38,-1} }, { { 0x40,-1},{ 0xF0,0x40,-1} }, /*068*/ - { { 0x48,-1},{ 0xF0,0x48,-1} }, { { 0x50,-1},{ 0xF0,0x50,-1} }, { { 0x57,-1},{ 0xF0,0x57,-1} }, { { 0x6F,-1},{ 0xF0,0x6F,-1} }, /*06c*/ - { { 0x13,-1},{ 0xF0,0x13,-1} }, { { 0x19,-1},{ 0xF0,0x19,-1} }, { { 0x39,-1},{ 0xF0,0x39,-1} }, { { 0x51,-1},{ 0xF0,0x51,-1} }, /*070*/ - { { 0x53,-1},{ 0xF0,0x53,-1} }, { { 0x5C,-1},{ 0xF0,0x5C,-1} }, { { 0x5F,-1},{ 0xF0,0x5F,-1} }, { { 0x62,-1},{ 0xF0,0x62,-1} }, /*074*/ - { { 0x63,-1},{ 0xF0,0x63,-1} }, { { 0x64,-1},{ 0xF0,0x64,-1} }, { { 0x65,-1},{ 0xF0,0x65,-1} }, { { 0x67,-1},{ 0xF0,0x67,-1} }, /*078*/ - { { 0x68,-1},{ 0xF0,0x68,-1} }, { { 0x6A,-1},{ 0xF0,0x6A,-1} }, { { 0x6D,-1},{ 0xF0,0x6D,-1} }, { { 0x6E,-1},{ 0xF0,0x6E,-1} }, /*07c*/ + { { 0},{ 0} }, { { 0x76,0},{ 0xF0,0x76,0} }, { { 0x16,0},{ 0xF0,0x16,0} }, { { 0x1E,0},{ 0xF0,0x1E,0} }, /*000*/ + { { 0x26,0},{ 0xF0,0x26,0} }, { { 0x25,0},{ 0xF0,0x25,0} }, { { 0x2E,0},{ 0xF0,0x2E,0} }, { { 0x36,0},{ 0xF0,0x36,0} }, /*004*/ + { { 0x3D,0},{ 0xF0,0x3D,0} }, { { 0x3E,0},{ 0xF0,0x3E,0} }, { { 0x46,0},{ 0xF0,0x46,0} }, { { 0x45,0},{ 0xF0,0x45,0} }, /*008*/ + { { 0x4E,0},{ 0xF0,0x4E,0} }, { { 0x55,0},{ 0xF0,0x55,0} }, { { 0x66,0},{ 0xF0,0x66,0} }, { { 0x0D,0},{ 0xF0,0x0D,0} }, /*00c*/ + { { 0x15,0},{ 0xF0,0x15,0} }, { { 0x1D,0},{ 0xF0,0x1D,0} }, { { 0x24,0},{ 0xF0,0x24,0} }, { { 0x2D,0},{ 0xF0,0x2D,0} }, /*010*/ + { { 0x2C,0},{ 0xF0,0x2C,0} }, { { 0x35,0},{ 0xF0,0x35,0} }, { { 0x3C,0},{ 0xF0,0x3C,0} }, { { 0x43,0},{ 0xF0,0x43,0} }, /*014*/ + { { 0x44,0},{ 0xF0,0x44,0} }, { { 0x4D,0},{ 0xF0,0x4D,0} }, { { 0x54,0},{ 0xF0,0x54,0} }, { { 0x5B,0},{ 0xF0,0x5B,0} }, /*018*/ + { { 0x5A,0},{ 0xF0,0x5A,0} }, { { 0x14,0},{ 0xF0,0x14,0} }, { { 0x1C,0},{ 0xF0,0x1C,0} }, { { 0x1B,0},{ 0xF0,0x1B,0} }, /*01c*/ + { { 0x23,0},{ 0xF0,0x23,0} }, { { 0x2B,0},{ 0xF0,0x2B,0} }, { { 0x34,0},{ 0xF0,0x34,0} }, { { 0x33,0},{ 0xF0,0x33,0} }, /*020*/ + { { 0x3B,0},{ 0xF0,0x3B,0} }, { { 0x42,0},{ 0xF0,0x42,0} }, { { 0x4B,0},{ 0xF0,0x4B,0} }, { { 0x4C,0},{ 0xF0,0x4C,0} }, /*024*/ + { { 0x52,0},{ 0xF0,0x52,0} }, { { 0x0E,0},{ 0xF0,0x0E,0} }, { { 0x12,0},{ 0xF0,0x12,0} }, { { 0x5D,0},{ 0xF0,0x5D,0} }, /*028*/ + { { 0x1A,0},{ 0xF0,0x1A,0} }, { { 0x22,0},{ 0xF0,0x22,0} }, { { 0x21,0},{ 0xF0,0x21,0} }, { { 0x2A,0},{ 0xF0,0x2A,0} }, /*02c*/ + { { 0x32,0},{ 0xF0,0x32,0} }, { { 0x31,0},{ 0xF0,0x31,0} }, { { 0x3A,0},{ 0xF0,0x3A,0} }, { { 0x41,0},{ 0xF0,0x41,0} }, /*030*/ + { { 0x49,0},{ 0xF0,0x49,0} }, { { 0x4A,0},{ 0xF0,0x4A,0} }, { { 0x59,0},{ 0xF0,0x59,0} }, { { 0x7C,0},{ 0xF0,0x7C,0} }, /*034*/ + { { 0x11,0},{ 0xF0,0x11,0} }, { { 0x29,0},{ 0xF0,0x29,0} }, { { 0x58,0},{ 0xF0,0x58,0} }, { { 0x05,0},{ 0xF0,0x05,0} }, /*038*/ + { { 0x06,0},{ 0xF0,0x06,0} }, { { 0x04,0},{ 0xF0,0x04,0} }, { { 0x0C,0},{ 0xF0,0x0C,0} }, { { 0x03,0},{ 0xF0,0x03,0} }, /*03c*/ + { { 0x0B,0},{ 0xF0,0x0B,0} }, { { 0x83,0},{ 0xF0,0x83,0} }, { { 0x0A,0},{ 0xF0,0x0A,0} }, { { 0x01,0},{ 0xF0,0x01,0} }, /*040*/ + { { 0x09,0},{ 0xF0,0x09,0} }, { { 0x77,0},{ 0xF0,0x77,0} }, { { 0x7E,0},{ 0xF0,0x7E,0} }, { { 0x6C,0},{ 0xF0,0x6C,0} }, /*044*/ + { { 0x75,0},{ 0xF0,0x75,0} }, { { 0x7D,0},{ 0xF0,0x7D,0} }, { { 0x7B,0},{ 0xF0,0x7B,0} }, { { 0x6B,0},{ 0xF0,0x6B,0} }, /*048*/ + { { 0x73,0},{ 0xF0,0x73,0} }, { { 0x74,0},{ 0xF0,0x74,0} }, { { 0x79,0},{ 0xF0,0x79,0} }, { { 0x69,0},{ 0xF0,0x69,0} }, /*04c*/ + { { 0x72,0},{ 0xF0,0x72,0} }, { { 0x7A,0},{ 0xF0,0x7A,0} }, { { 0x70,0},{ 0xF0,0x70,0} }, { { 0x71,0},{ 0xF0,0x71,0} }, /*050*/ + { { 0x84,0},{ 0xF0,0x84,0} }, { { 0x60,0},{ 0xF0,0x60,0} }, { { 0x61,0},{ 0xF0,0x61,0} }, { { 0x78,0},{ 0xF0,0x78,0} }, /*054*/ + { { 0x07,0},{ 0xF0,0x07,0} }, { { 0x0F,0},{ 0xF0,0x0F,0} }, { { 0x17,0},{ 0xF0,0x17,0} }, { { 0x1F,0},{ 0xF0,0x1F,0} }, /*058*/ + { { 0x27,0},{ 0xF0,0x27,0} }, { { 0x2F,0},{ 0xF0,0x2F,0} }, { { 0x37,0},{ 0xF0,0x37,0} }, { { 0x3F,0},{ 0xF0,0x3F,0} }, /*05c*/ + { { 0x47,0},{ 0xF0,0x47,0} }, { { 0x4F,0},{ 0xF0,0x4F,0} }, { { 0x56,0},{ 0xF0,0x56,0} }, { { 0x5E,0},{ 0xF0,0x5E,0} }, /*060*/ + { { 0x08,0},{ 0xF0,0x08,0} }, { { 0x10,0},{ 0xF0,0x10,0} }, { { 0x18,0},{ 0xF0,0x18,0} }, { { 0x20,0},{ 0xF0,0x20,0} }, /*064*/ + { { 0x28,0},{ 0xF0,0x28,0} }, { { 0x30,0},{ 0xF0,0x30,0} }, { { 0x38,0},{ 0xF0,0x38,0} }, { { 0x40,0},{ 0xF0,0x40,0} }, /*068*/ + { { 0x48,0},{ 0xF0,0x48,0} }, { { 0x50,0},{ 0xF0,0x50,0} }, { { 0x57,0},{ 0xF0,0x57,0} }, { { 0x6F,0},{ 0xF0,0x6F,0} }, /*06c*/ + { { 0x13,0},{ 0xF0,0x13,0} }, { { 0x19,0},{ 0xF0,0x19,0} }, { { 0x39,0},{ 0xF0,0x39,0} }, { { 0x51,0},{ 0xF0,0x51,0} }, /*070*/ + { { 0x53,0},{ 0xF0,0x53,0} }, { { 0x5C,0},{ 0xF0,0x5C,0} }, { { 0x5F,0},{ 0xF0,0x5F,0} }, { { 0x62,0},{ 0xF0,0x62,0} }, /*074*/ + { { 0x63,0},{ 0xF0,0x63,0} }, { { 0x64,0},{ 0xF0,0x64,0} }, { { 0x65,0},{ 0xF0,0x65,0} }, { { 0x67,0},{ 0xF0,0x67,0} }, /*078*/ + { { 0x68,0},{ 0xF0,0x68,0} }, { { 0x6A,0},{ 0xF0,0x6A,0} }, { { 0x6D,0},{ 0xF0,0x6D,0} }, { { 0x6E,0},{ 0xF0,0x6E,0} }, /*07c*/ - { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ - { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ - { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ - { { 0x8c,-1},{ 0xf0,0x8c,-1} }, { { 0x8d,-1},{ 0xf0,0x8d,-1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ - { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ - { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ - { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ - { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ - { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ - { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ - { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ - { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ - { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ - { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ - { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ - { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ - { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ - { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ - { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ - { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ - { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ - { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ - { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ - { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ - { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ - { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ - { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ - { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ - { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ - { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ - { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ - { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ + { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ + { { 0x8c,0},{ 0xf0,0x8c,0} }, { { 0x8d,0},{ 0xf0,0x8d,0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ + { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ + { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ + { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ + { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ + { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ + { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ + { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ + { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ + { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ + { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ + { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ + { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ + { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ + { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ + { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ + { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ + { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ + { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ + { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ + { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ + { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ + { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ + { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ + { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ + { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ + { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ + { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ - { {0xe1,0x14,-1},{0xe1,0xf0,0x14,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ - { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ - { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ - { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ - { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ - { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ - { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ - { {0xe0,0x5A,-1},{0xe0,0xF0,0x5A,-1} }, { {0xe0,0x14,-1},{0xe0,0xF0,0x14,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ - { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ - { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ - { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ - { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ - { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { {0xe0,0x4A,-1},{0xe0,0xF0,0x4A,-1} }, { { -1},{ -1} }, { {0xe0,0x7C,-1},{0xe0,0xF0,0x7C,-1} }, /*134*/ - { {0xe0,0x11,-1},{0xe0,0xF0,0x11,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ - { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ - { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ - { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { {0xe0,0x6C,-1},{0xe0,0xF0,0x6C,-1} }, /*144*/ - { {0xe0,0x75,-1},{0xe0,0xF0,0x75,-1} }, { {0xe0,0x7D,-1},{0xe0,0xF0,0x7D,-1} }, { { -1},{ -1} }, { {0xe0,0x6B,-1},{0xe0,0xF0,0x6B,-1} }, /*148*/ - { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { {0xe0,0x74,-1},{0xe0,0xF0,0x74,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { {0xe0,0x69,-1},{0xe0,0xF0,0x69,-1} }, /*14c*/ - { {0xe0,0x72,-1},{0xe0,0xF0,0x72,-1} }, { {0xe0,0x7A,-1},{0xe0,0xF0,0x7A,-1} }, { {0xe0,0x70,-1},{0xe0,0xF0,0x70,-1} }, { {0xe0,0x71,-1},{0xe0,0xF0,0x71,-1} }, /*150*/ - { { -1},{ -1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ - { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { {0xe0,0x1F,-1},{0xe0,0xF0,0x1F,-1} }, /*158*/ - { {0xe0,0x27,-1},{0xe0,0xF0,0x27,-1} }, { {0xe0,0x2F,-1},{0xe0,0xF0,0x2F,-1} }, { {0xe0,0x37,-1},{0xe0,0xF0,0x37,-1} }, { {0xe0,0x3F,-1},{0xe0,0xF0,0x3F,-1} }, /*15c*/ - { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { {0xe0,0x5E,-1},{0xe0,0xF0,0x5E,-1} }, /*160*/ - { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ - { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ - { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ - { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ - { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ - { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ - { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + { {0xe1,0x14,0},{0xe1,0xf0,0x14,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ + { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ + { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ + { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ + { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ + { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ + { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ + { {0xe0,0x5A,0},{0xe0,0xF0,0x5A,0} }, { {0xe0,0x14,0},{0xe0,0xF0,0x14,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ + { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ + { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ + { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { {0xe0,0x4A,0},{0xe0,0xF0,0x4A,0} }, { { 0},{ 0} }, { {0xe0,0x7C,0},{0xe0,0xF0,0x7C,0} }, /*134*/ + { {0xe0,0x11,0},{0xe0,0xF0,0x11,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ + { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ + { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ + { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { {0xe0,0x6C,0},{0xe0,0xF0,0x6C,0} }, /*144*/ + { {0xe0,0x75,0},{0xe0,0xF0,0x75,0} }, { {0xe0,0x7D,0},{0xe0,0xF0,0x7D,0} }, { { 0},{ 0} }, { {0xe0,0x6B,0},{0xe0,0xF0,0x6B,0} }, /*148*/ + { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { {0xe0,0x74,0},{0xe0,0xF0,0x74,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { {0xe0,0x69,0},{0xe0,0xF0,0x69,0} }, /*14c*/ + { {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} }, /*150*/ + { { 0},{ 0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ + { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { {0xe0,0x1F,0},{0xe0,0xF0,0x1F,0} }, /*158*/ + { {0xe0,0x27,0},{0xe0,0xF0,0x27,0} }, { {0xe0,0x2F,0},{0xe0,0xF0,0x2F,0} }, { {0xe0,0x37,0},{0xe0,0xF0,0x37,0} }, { {0xe0,0x3F,0},{0xe0,0xF0,0x3F,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { {0xe0,0x5E,0},{0xe0,0xF0,0x5E,0} }, /*160*/ + { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ + { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ + { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ + { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ + { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ + { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ - { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ - { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ }; static const scancode scancode_set3[512] = { - { { -1},{ -1} }, { { 0x08,-1},{ 0xf0,0x08,-1} }, { { 0x16,-1},{ 0xf0,0x16,-1} }, { { 0x1E,-1},{ 0xf0,0x1E,-1} }, /*000*/ - { { 0x26,-1},{ 0xf0,0x26,-1} }, { { 0x25,-1},{ 0xf0,0x25,-1} }, { { 0x2E,-1},{ 0xf0,0x2E,-1} }, { { 0x36,-1},{ 0xf0,0x36,-1} }, /*004*/ - { { 0x3D,-1},{ 0xf0,0x3D,-1} }, { { 0x3E,-1},{ 0xf0,0x3E,-1} }, { { 0x46,-1},{ 0xf0,0x46,-1} }, { { 0x45,-1},{ 0xf0,0x45,-1} }, /*008*/ - { { 0x4E,-1},{ 0xf0,0x4E,-1} }, { { 0x55,-1},{ 0xf0,0x55,-1} }, { { 0x66,-1},{ 0xf0,0x66,-1} }, { { 0x0D,-1},{ 0xf0,0x0D,-1} }, /*00c*/ - { { 0x15,-1},{ 0xf0,0x15,-1} }, { { 0x1D,-1},{ 0xf0,0x1D,-1} }, { { 0x24,-1},{ 0xf0,0x24,-1} }, { { 0x2D,-1},{ 0xf0,0x2D,-1} }, /*010*/ - { { 0x2C,-1},{ 0xf0,0x2C,-1} }, { { 0x35,-1},{ 0xf0,0x35,-1} }, { { 0x3C,-1},{ 0xf0,0x3C,-1} }, { { 0x43,-1},{ 0xf0,0x43,-1} }, /*014*/ - { { 0x44,-1},{ 0xf0,0x44,-1} }, { { 0x4D,-1},{ 0xf0,0x4D,-1} }, { { 0x54,-1},{ 0xf0,0x54,-1} }, { { 0x5B,-1},{ 0xf0,0x5B,-1} }, /*018*/ - { { 0x5A,-1},{ 0xf0,0x5A,-1} }, { { 0x11,-1},{ 0xf0,0x11,-1} }, { { 0x1C,-1},{ 0xf0,0x1C,-1} }, { { 0x1B,-1},{ 0xf0,0x1B,-1} }, /*01c*/ - { { 0x23,-1},{ 0xf0,0x23,-1} }, { { 0x2B,-1},{ 0xf0,0x2B,-1} }, { { 0x34,-1},{ 0xf0,0x34,-1} }, { { 0x33,-1},{ 0xf0,0x33,-1} }, /*020*/ - { { 0x3B,-1},{ 0xf0,0x3B,-1} }, { { 0x42,-1},{ 0xf0,0x42,-1} }, { { 0x4B,-1},{ 0xf0,0x4B,-1} }, { { 0x4C,-1},{ 0xf0,0x4C,-1} }, /*024*/ - { { 0x52,-1},{ 0xf0,0x52,-1} }, { { 0x0E,-1},{ 0xf0,0x0E,-1} }, { { 0x12,-1},{ 0xf0,0x12,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, /*028*/ - { { 0x1A,-1},{ 0xf0,0x1A,-1} }, { { 0x22,-1},{ 0xf0,0x22,-1} }, { { 0x21,-1},{ 0xf0,0x21,-1} }, { { 0x2A,-1},{ 0xf0,0x2A,-1} }, /*02c*/ - { { 0x32,-1},{ 0xf0,0x32,-1} }, { { 0x31,-1},{ 0xf0,0x31,-1} }, { { 0x3A,-1},{ 0xf0,0x3A,-1} }, { { 0x41,-1},{ 0xf0,0x41,-1} }, /*030*/ - { { 0x49,-1},{ 0xf0,0x49,-1} }, { { 0x4A,-1},{ 0xf0,0x4A,-1} }, { { 0x59,-1},{ 0xf0,0x59,-1} }, { { 0x7E,-1},{ 0xf0,0x7E,-1} }, /*034*/ - { { 0x19,-1},{ 0xf0,0x19,-1} }, { { 0x29,-1},{ 0xf0,0x29,-1} }, { { 0x14,-1},{ 0xf0,0x14,-1} }, { { 0x07,-1},{ 0xf0,0x07,-1} }, /*038*/ - { { 0x0F,-1},{ 0xf0,0x0F,-1} }, { { 0x17,-1},{ 0xf0,0x17,-1} }, { { 0x1F,-1},{ 0xf0,0x1F,-1} }, { { 0x27,-1},{ 0xf0,0x27,-1} }, /*03c*/ - { { 0x2F,-1},{ 0xf0,0x2F,-1} }, { { 0x37,-1},{ 0xf0,0x37,-1} }, { { 0x3F,-1},{ 0xf0,0x3F,-1} }, { { 0x47,-1},{ 0xf0,0x47,-1} }, /*040*/ - { { 0x4F,-1},{ 0xf0,0x4F,-1} }, { { 0x76,-1},{ 0xf0,0x76,-1} }, { { 0x5F,-1},{ 0xf0,0x5F,-1} }, { { 0x6C,-1},{ 0xf0,0x6C,-1} }, /*044*/ - { { 0x75,-1},{ 0xf0,0x75,-1} }, { { 0x7D,-1},{ 0xf0,0x7D,-1} }, { { 0x84,-1},{ 0xf0,0x84,-1} }, { { 0x6B,-1},{ 0xf0,0x6B,-1} }, /*048*/ - { { 0x73,-1},{ 0xf0,0x73,-1} }, { { 0x74,-1},{ 0xf0,0x74,-1} }, { { 0x7C,-1},{ 0xf0,0x7C,-1} }, { { 0x69,-1},{ 0xf0,0x69,-1} }, /*04c*/ - { { 0x72,-1},{ 0xf0,0x72,-1} }, { { 0x7A,-1},{ 0xf0,0x7A,-1} }, { { 0x70,-1},{ 0xf0,0x70,-1} }, { { 0x71,-1},{ 0xf0,0x71,-1} }, /*050*/ - { { 0x57,-1},{ 0xf0,0x57,-1} }, { { 0x60,-1},{ 0xf0,0x60,-1} }, { { -1},{ -1} }, { { 0x56,-1},{ 0xf0,0x56,-1} }, /*054*/ - { { 0x5E,-1},{ 0xf0,0x5E,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*058*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*05c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*060*/ - { { -1},{ -1} }, { { 0x10,-1},{ 0xf0,0x10,-1} }, { { 0x18,-1},{ 0xf0,0x18,-1} }, { { 0x20,-1},{ 0xf0,0x20,-1} }, /*064*/ - { { 0x28,-1},{ 0xf0,0x28,-1} }, { { 0x30,-1},{ 0xf0,0x30,-1} }, { { 0x38,-1},{ 0xf0,0x38,-1} }, { { 0x40,-1},{ 0xf0,0x40,-1} }, /*068*/ - { { 0x48,-1},{ 0xf0,0x48,-1} }, { { 0x50,-1},{ 0xf0,0x50,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*06c*/ - { { 0x87,-1},{ 0xf0,0x87,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { 0x51,-1},{ 0xf0,0x51,-1} }, /*070*/ - { { 0x53,-1},{ 0xf0,0x53,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, { { -1},{ -1} }, { { 0x62,-1},{ 0xf0,0x62,-1} }, /*074*/ - { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x85,-1} }, /*078*/ - { { 0x68,-1},{ 0xf0,0x68,-1} }, { { 0x13,-1},{ 0xf0,0x13,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*07c*/ + { { 0},{ 0} }, { { 0x08,0},{ 0xf0,0x08,0} }, { { 0x16,0},{ 0xf0,0x16,0} }, { { 0x1E,0},{ 0xf0,0x1E,0} }, /*000*/ + { { 0x26,0},{ 0xf0,0x26,0} }, { { 0x25,0},{ 0xf0,0x25,0} }, { { 0x2E,0},{ 0xf0,0x2E,0} }, { { 0x36,0},{ 0xf0,0x36,0} }, /*004*/ + { { 0x3D,0},{ 0xf0,0x3D,0} }, { { 0x3E,0},{ 0xf0,0x3E,0} }, { { 0x46,0},{ 0xf0,0x46,0} }, { { 0x45,0},{ 0xf0,0x45,0} }, /*008*/ + { { 0x4E,0},{ 0xf0,0x4E,0} }, { { 0x55,0},{ 0xf0,0x55,0} }, { { 0x66,0},{ 0xf0,0x66,0} }, { { 0x0D,0},{ 0xf0,0x0D,0} }, /*00c*/ + { { 0x15,0},{ 0xf0,0x15,0} }, { { 0x1D,0},{ 0xf0,0x1D,0} }, { { 0x24,0},{ 0xf0,0x24,0} }, { { 0x2D,0},{ 0xf0,0x2D,0} }, /*010*/ + { { 0x2C,0},{ 0xf0,0x2C,0} }, { { 0x35,0},{ 0xf0,0x35,0} }, { { 0x3C,0},{ 0xf0,0x3C,0} }, { { 0x43,0},{ 0xf0,0x43,0} }, /*014*/ + { { 0x44,0},{ 0xf0,0x44,0} }, { { 0x4D,0},{ 0xf0,0x4D,0} }, { { 0x54,0},{ 0xf0,0x54,0} }, { { 0x5B,0},{ 0xf0,0x5B,0} }, /*018*/ + { { 0x5A,0},{ 0xf0,0x5A,0} }, { { 0x11,0},{ 0xf0,0x11,0} }, { { 0x1C,0},{ 0xf0,0x1C,0} }, { { 0x1B,0},{ 0xf0,0x1B,0} }, /*01c*/ + { { 0x23,0},{ 0xf0,0x23,0} }, { { 0x2B,0},{ 0xf0,0x2B,0} }, { { 0x34,0},{ 0xf0,0x34,0} }, { { 0x33,0},{ 0xf0,0x33,0} }, /*020*/ + { { 0x3B,0},{ 0xf0,0x3B,0} }, { { 0x42,0},{ 0xf0,0x42,0} }, { { 0x4B,0},{ 0xf0,0x4B,0} }, { { 0x4C,0},{ 0xf0,0x4C,0} }, /*024*/ + { { 0x52,0},{ 0xf0,0x52,0} }, { { 0x0E,0},{ 0xf0,0x0E,0} }, { { 0x12,0},{ 0xf0,0x12,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, /*028*/ + { { 0x1A,0},{ 0xf0,0x1A,0} }, { { 0x22,0},{ 0xf0,0x22,0} }, { { 0x21,0},{ 0xf0,0x21,0} }, { { 0x2A,0},{ 0xf0,0x2A,0} }, /*02c*/ + { { 0x32,0},{ 0xf0,0x32,0} }, { { 0x31,0},{ 0xf0,0x31,0} }, { { 0x3A,0},{ 0xf0,0x3A,0} }, { { 0x41,0},{ 0xf0,0x41,0} }, /*030*/ + { { 0x49,0},{ 0xf0,0x49,0} }, { { 0x4A,0},{ 0xf0,0x4A,0} }, { { 0x59,0},{ 0xf0,0x59,0} }, { { 0x7E,0},{ 0xf0,0x7E,0} }, /*034*/ + { { 0x19,0},{ 0xf0,0x19,0} }, { { 0x29,0},{ 0xf0,0x29,0} }, { { 0x14,0},{ 0xf0,0x14,0} }, { { 0x07,0},{ 0xf0,0x07,0} }, /*038*/ + { { 0x0F,0},{ 0xf0,0x0F,0} }, { { 0x17,0},{ 0xf0,0x17,0} }, { { 0x1F,0},{ 0xf0,0x1F,0} }, { { 0x27,0},{ 0xf0,0x27,0} }, /*03c*/ + { { 0x2F,0},{ 0xf0,0x2F,0} }, { { 0x37,0},{ 0xf0,0x37,0} }, { { 0x3F,0},{ 0xf0,0x3F,0} }, { { 0x47,0},{ 0xf0,0x47,0} }, /*040*/ + { { 0x4F,0},{ 0xf0,0x4F,0} }, { { 0x76,0},{ 0xf0,0x76,0} }, { { 0x5F,0},{ 0xf0,0x5F,0} }, { { 0x6C,0},{ 0xf0,0x6C,0} }, /*044*/ + { { 0x75,0},{ 0xf0,0x75,0} }, { { 0x7D,0},{ 0xf0,0x7D,0} }, { { 0x84,0},{ 0xf0,0x84,0} }, { { 0x6B,0},{ 0xf0,0x6B,0} }, /*048*/ + { { 0x73,0},{ 0xf0,0x73,0} }, { { 0x74,0},{ 0xf0,0x74,0} }, { { 0x7C,0},{ 0xf0,0x7C,0} }, { { 0x69,0},{ 0xf0,0x69,0} }, /*04c*/ + { { 0x72,0},{ 0xf0,0x72,0} }, { { 0x7A,0},{ 0xf0,0x7A,0} }, { { 0x70,0},{ 0xf0,0x70,0} }, { { 0x71,0},{ 0xf0,0x71,0} }, /*050*/ + { { 0x57,0},{ 0xf0,0x57,0} }, { { 0x60,0},{ 0xf0,0x60,0} }, { { 0},{ 0} }, { { 0x56,0},{ 0xf0,0x56,0} }, /*054*/ + { { 0x5E,0},{ 0xf0,0x5E,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*058*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*05c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*060*/ + { { 0},{ 0} }, { { 0x10,0},{ 0xf0,0x10,0} }, { { 0x18,0},{ 0xf0,0x18,0} }, { { 0x20,0},{ 0xf0,0x20,0} }, /*064*/ + { { 0x28,0},{ 0xf0,0x28,0} }, { { 0x30,0},{ 0xf0,0x30,0} }, { { 0x38,0},{ 0xf0,0x38,0} }, { { 0x40,0},{ 0xf0,0x40,0} }, /*068*/ + { { 0x48,0},{ 0xf0,0x48,0} }, { { 0x50,0},{ 0xf0,0x50,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*06c*/ + { { 0x87,0},{ 0xf0,0x87,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0x51,0},{ 0xf0,0x51,0} }, /*070*/ + { { 0x53,0},{ 0xf0,0x53,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, { { 0},{ 0} }, { { 0x62,0},{ 0xf0,0x62,0} }, /*074*/ + { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x85,0} }, /*078*/ + { { 0x68,0},{ 0xf0,0x68,0} }, { { 0x13,0},{ 0xf0,0x13,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*07c*/ - { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ - { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ - { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ - { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ - { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ - { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ - { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ - { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ - { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ - { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ - { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ - { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ - { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ - { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ - { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ - { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ - { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ - { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ - { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ - { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ - { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ - { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ - { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ - { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ - { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ - { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ - { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ - { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ - { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ - { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ - { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ + { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ + { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ + { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ + { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ + { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ + { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ + { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ + { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ + { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ + { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ + { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ + { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ + { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ + { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ + { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ + { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ + { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ + { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ + { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ + { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ + { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ + { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ + { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ + { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ + { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ + { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ + { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ + { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ - { { 0x62,-1},{ 0xF0,0x62,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ - { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ - { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ - { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ - { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ - { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ - { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ - { { 0x79,-1},{ 0xf0,0x79,-1} }, { { 0x58,-1},{ 0xf0,0x58,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ - { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ - { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ - { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ - { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ - { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { { 0x77,-1},{ 0xf0,0x77,-1} }, { { -1},{ -1} }, { { 0x57,-1},{ 0xf0,0x57,-1} }, /*134*/ - { { 0x39,-1},{ 0xf0,0x39,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ - { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ - { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ - { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { { 0x6E,-1},{ 0xf0,0x6E,-1} }, /*144*/ - { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x6F,-1},{ 0xf0,0x6F,-1} }, { { -1},{ -1} }, { { 0x61,-1},{ 0xf0,0x61,-1} }, /*148*/ - { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { { 0x6A,-1},{ 0xf0,0x6A,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { { 0x65,-1},{ 0xf0,0x65,-1} }, /*14c*/ - { { 0x60,-1},{ 0xf0,0x60,-1} }, { { 0x6D,-1},{ 0xf0,0x6D,-1} }, { { 0x67,-1},{ 0xf0,0x67,-1} }, { { 0x64,-1},{ 0xf0,0x64,-1} }, /*150*/ - { { 0xd4,-1},{ 0xf0,0xD4,-1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ - { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { { 0x8B,-1},{ 0xf0,0x8B,-1} }, /*158*/ - { { 0x8C,-1},{ 0xf0,0x8C,-1} }, { { 0x8D,-1},{ 0xf0,0x8D,-1} }, { { -1},{ -1} }, { { 0x7F,-1},{ 0xf0,0x7F,-1} }, /*15c*/ - { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { { -1},{ -1} }, /*160*/ - { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ - { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ - { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ - { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ - { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ - { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ - { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + { { 0x62,0},{ 0xF0,0x62,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ + { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ + { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ + { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ + { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ + { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ + { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ + { { 0x79,0},{ 0xf0,0x79,0} }, { { 0x58,0},{ 0xf0,0x58,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ + { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ + { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ + { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { { 0x77,0},{ 0xf0,0x77,0} }, { { 0},{ 0} }, { { 0x57,0},{ 0xf0,0x57,0} }, /*134*/ + { { 0x39,0},{ 0xf0,0x39,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ + { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ + { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ + { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { { 0x6E,0},{ 0xf0,0x6E,0} }, /*144*/ + { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x6F,0},{ 0xf0,0x6F,0} }, { { 0},{ 0} }, { { 0x61,0},{ 0xf0,0x61,0} }, /*148*/ + { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { { 0x6A,0},{ 0xf0,0x6A,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { { 0x65,0},{ 0xf0,0x65,0} }, /*14c*/ + { { 0x60,0},{ 0xf0,0x60,0} }, { { 0x6D,0},{ 0xf0,0x6D,0} }, { { 0x67,0},{ 0xf0,0x67,0} }, { { 0x64,0},{ 0xf0,0x64,0} }, /*150*/ + { { 0xd4,0},{ 0xf0,0xD4,0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ + { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { { 0x8B,0},{ 0xf0,0x8B,0} }, /*158*/ + { { 0x8C,0},{ 0xf0,0x8C,0} }, { { 0x8D,0},{ 0xf0,0x8D,0} }, { { 0},{ 0} }, { { 0x7F,0},{ 0xf0,0x7F,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { { 0},{ 0} }, /*160*/ + { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ + { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ + { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ + { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ + { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ + { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ - { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ - { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ }; -static void -kbdlog(const char *fmt, ...) -{ #ifdef ENABLE_KEYBOARD_AT_LOG +int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; + + +static void +kbd_log(const char *fmt, ...) +{ va_list ap; if (keyboard_at_do_log) { @@ -594,19 +582,24 @@ kbdlog(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define kbd_log(fmt, ...) +#endif static void -kbd_setmap(atkbd_t *kbd) +set_scancode_map(atkbd_t *dev) { switch (keyboard_mode & 3) { +#ifdef USE_SET1 case 1: default: keyboard_set_table(scancode_set1); break; - +#else + default: +#endif case 2: keyboard_set_table(scancode_set2); break; @@ -617,87 +610,96 @@ kbd_setmap(atkbd_t *kbd) } if (keyboard_mode & 0x20) +#ifdef USE_SET1 keyboard_set_table(scancode_set1); +#else + keyboard_set_table(scancode_set2); +#endif } static void kbd_poll(void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; - keyboard_delay += (1000LL * TIMER_USEC); + timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); - if ((kbd->out_new != -1) && !kbd->last_irq) { - kbd->wantirq = 0; - if (kbd->out_new & 0x100) { - kbdlog("ATkbd: want mouse data\n"); - if (kbd->mem[0] & 0x02) + if ((dev->out_new != -1) && !dev->last_irq) { + dev->wantirq = 0; + if (dev->out_new & 0x100) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: want mouse data\n"); +#endif + if (dev->mem[0] & 0x02) picint(0x1000); - kbd->out = kbd->out_new & 0xff; - kbd->out_new = -1; - kbd->status |= STAT_OFULL; - kbd->status &= ~STAT_IFULL; - kbd->status |= STAT_MFULL; - kbd->last_irq = 0x1000; + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status |= STAT_OFULL; + dev->status &= ~STAT_IFULL; + dev->status |= STAT_MFULL; + dev->last_irq = 0x1000; } else { - kbdlog("ATkbd: want keyboard data\n"); - if (kbd->mem[0] & 0x01) +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: want keyboard data\n"); +#endif + if (dev->mem[0] & 0x01) picint(2); - kbd->out = kbd->out_new & 0xff; - kbd->out_new = -1; - kbd->status |= STAT_OFULL; - kbd->status &= ~STAT_IFULL; - kbd->status &= ~STAT_MFULL; - kbd->last_irq = 2; + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status |= STAT_OFULL; + dev->status &= ~STAT_IFULL; + dev->status &= ~STAT_MFULL; + dev->last_irq = 2; } } - if (kbd->out_new == -1 && !(kbd->status & STAT_OFULL) && - key_ctrl_queue_start != key_ctrl_queue_end) { - kbd->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; + if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { + dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; - } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1 && - kbd->out_delayed != -1) { - kbd->out_new = kbd->out_delayed; - kbd->out_delayed = -1; - } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1 && - !(kbd->mem[0] & 0x10) && kbd->out_delayed != -1) { - kbd->out_new = kbd->out_delayed; - kbd->out_delayed = -1; - } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1/* && !(kbd->mem[0] & 0x20)*/ && + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { + dev->out_new = dev->out_delayed; + dev->out_delayed = -1; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && dev->out_delayed != -1) { + dev->out_new = dev->out_delayed; + dev->out_delayed = -1; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1/* && !(dev->mem[0] & 0x20)*/ && (mouse_queue_start != mouse_queue_end)) { - kbd->out_new = mouse_queue[mouse_queue_start] | 0x100; + dev->out_new = mouse_queue[mouse_queue_start] | 0x100; mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } else if (!(kbd->status&STAT_OFULL) && kbd->out_new == -1 && - !(kbd->mem[0]&0x10) && (key_queue_start != key_queue_end)) { - kbd->out_new = key_queue[key_queue_start]; + } else if (!(dev->status&STAT_OFULL) && dev->out_new == -1 && + !(dev->mem[0]&0x10) && (key_queue_start != key_queue_end)) { + dev->out_new = key_queue[key_queue_start]; key_queue_start = (key_queue_start + 1) & 0xf; } } static void -kbd_adddata(uint8_t val) +add_data(atkbd_t *dev, uint8_t val) { key_ctrl_queue[key_ctrl_queue_end] = val; key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; - if (!(CurrentKbd->out_new & 0x300)) { - CurrentKbd->out_delayed = CurrentKbd->out_new; - CurrentKbd->out_new = -1; + if (! (dev->out_new & 0x300)) { + dev->out_delayed = dev->out_new; + dev->out_new = -1; } } static void -kbd_adddata_vals(uint8_t *val, uint8_t len) +add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { - int translate = (keyboard_mode & 0x40) && !(keyboard_mode & 0x20); + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); int i; uint8_t or = 0; uint8_t send; + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + for (i = 0; i < len; i++) { if (translate) { if (val[i] == 0xf0) { @@ -709,93 +711,115 @@ kbd_adddata_vals(uint8_t *val, uint8_t len) or = 0; } else send = val[i]; - kbdlog("%02X", send); - kbd_adddata(send); - if (i < (len - 1)) kbdlog(" "); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("%02X", send); +#endif + key_queue[key_queue_end] = send; + key_queue_end = (key_queue_end + 1) & 0xf; +#ifdef ENABLE_KEYBOARD_AT_LOG + if (i < (len - 1)) kbd_log(" "); +#endif } +#ifdef ENABLE_KEYBOARD_AT_LOG if (translate) { - kbdlog(" original: ("); + kbd_log(" original: ("); for (i = 0; i < len; i++) { - kbdlog("%02X", val[i]); - if (i < (len - 1)) kbdlog(" "); + kbd_log("%02X", val[i]); + if (i < (len - 1)) kbd_log(" "); } - kbdlog(")"); + kbd_log(")"); } - - kbdlog("\n"); + kbd_log("\n"); +#endif } static void -kbd_adddata_keyboard(uint16_t val) +add_data_kbd(uint16_t val) { - int translate = (keyboard_mode & 0x40) && !(keyboard_mode & 0x20); - + atkbd_t *dev = SavedKbd; + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; /* Allow for scan code translation. */ if (translate && (val == 0xf0)) { - kbdlog("Translate is on, F0 prefix detected\n"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); +#endif sc_or = 0x80; return; } /* Skip break code if translated make code has bit 7 set. */ if (translate && (sc_or == 0x80) && (val & 0x80)) { - kbdlog("Translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); +#endif sc_or = 0; return; } /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if (romset == ROM_T3100E && (keyboard_recv(0xb8) || keyboard_recv(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 ((dev != NULL) && + ((dev->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) && + (keyboard_recv(0xb8) || keyboard_recv(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 */ } - kbdlog("Translate is %s, ", translate ? "on" : "off"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); +#endif switch(val) { case FAKE_LSHIFT_ON: - kbdlog("fake left shift on, scan code: "); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("fake left shift on, scan code: "); +#endif if (num_lock) { if (shift_states) { - kbdlog("N/A (one or both shifts on)\n"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("N/A (one or both shifts on)\n"); +#endif break; } else { /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0x12; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + default: - kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#endif break; } } @@ -805,14 +829,18 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; - kbd_adddata_vals(fake_shift, 3); + add_data_vals(dev, fake_shift, 3); break; + default: - kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#endif break; } } @@ -821,40 +849,55 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0xb6; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x59; - kbd_adddata_vals(fake_shift, 3); + add_data_vals(dev, fake_shift, 3); break; + default: - kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#endif break; } } +#ifdef ENABLE_KEYBOARD_AT_LOG if (!shift_states) - kbdlog("N/A (both shifts off)\n"); + kbd_log("N/A (both shifts off)\n"); +#endif } break; + case FAKE_LSHIFT_OFF: - kbdlog("fake left shift on, scan code: "); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("fake left shift on, scan code: "); +#endif if (num_lock) { if (shift_states) { - kbdlog("N/A (one or both shifts on)\n"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("N/A (one or both shifts on)\n"); +#endif break; } else { /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; - kbd_adddata_vals(fake_shift, 3); + add_data_vals(dev, fake_shift, 3); break; + default: - kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#endif break; } } @@ -864,14 +907,18 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0x12; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + default: - kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#endif break; } } @@ -880,86 +927,101 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0x36; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0x59; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + default: - kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); +#endif break; } } +#ifdef ENABLE_KEYBOARD_AT_LOG if (!shift_states) - kbdlog("N/A (both shifts off)\n"); + kbd_log("N/A (both shifts off)\n"); +#endif } break; + default: - kbdlog("scan code: "); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("scan code: "); if (translate) { - kbdlog("%02X (original: ", (nont_to_t[val] | sc_or)); + kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); if (sc_or == 0x80) - kbdlog("F0 "); - kbdlog("%02X)\n", val); + kbd_log("F0 "); + kbd_log("%02X)\n", val); } else - kbdlog("%02X\n", val); + kbd_log("%02X\n", val); +#endif key_queue[key_queue_end] = (translate ? (nont_to_t[val] | sc_or) : val); key_queue_end = (key_queue_end + 1) & 0xf; break; } - if (sc_or == 0x80) sc_or = 0; + if (sc_or == 0x80) + sc_or = 0; } static void -kbd_output_write(atkbd_t *kbd, uint8_t val) +write_output(atkbd_t *dev, uint8_t val) { - kbdlog("Write output port: %02X (old: %02X)\n", val, kbd->output_port); - if ((kbd->output_port ^ val) & 0x20) { /*IRQ 12*/ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write output port: %02X (old: %02X)\n", val, dev->output_port); +#endif + + if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ if (val & 0x20) picint(1 << 12); else picintc(1 << 12); } - if ((kbd->output_port ^ val) & 0x10) { /*IRQ 1*/ + if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ if (val & 0x10) picint(1 << 1); else picintc(1 << 1); } - if ((kbd->output_port ^ val) & 0x02) { /*A20 enable change*/ + if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ mem_a20_key = val & 0x02; mem_a20_recalc(); flushmmucache(); } - if ((kbd->output_port ^ val) & 0x01) { /*Reset*/ + if ((dev->output_port ^ val) & 0x01) { /*Reset*/ if (! (val & 0x01)) { /* Pin 0 selected. */ softresetx86(); /*Pulse reset!*/ cpu_set_edx(); } } - kbd->output_port = val; + dev->output_port = val; } static void -kbd_cmd_write(atkbd_t *kbd, uint8_t val) +write_cmd(atkbd_t *dev, uint8_t val) { - kbdlog("Write command byte: %02X (old: %02X)\n", val, kbd->mem[0]); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); +#endif - if ((val & 1) && (kbd->status & STAT_OFULL)) - kbd->wantirq = 1; - if (!(val & 1) && kbd->wantirq) - kbd->wantirq = 0; + if ((val & 1) && (dev->status & STAT_OFULL)) + dev->wantirq = 1; + if (!(val & 1) && dev->wantirq) + dev->wantirq = 0; /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { val &= ~CCB_TRANSLATE; - kbd->mem[0] &= ~CCB_TRANSLATE; + dev->mem[0] &= ~CCB_TRANSLATE; } /* Scan code translate ON/OFF. */ @@ -967,148 +1029,194 @@ kbd_cmd_write(atkbd_t *kbd, uint8_t val) keyboard_mode |= (val & MODE_MASK); keyboard_scan = !(val & 0x10); - kbdlog("ATkbd: keyboard is now %s\n", mouse_scan ? "enabled" : "disabled"); - kbdlog("ATkbd: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: keyboard is now %s\n", keyboard_scan ? "enabled" : "disabled"); + kbd_log("ATkbd: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); +#endif /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. */ - if (((kbd->flags & KBC_VEN_MASK) == KBC_VEN_AMI) || ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) { + if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_AMI) || + ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { keyboard_mode &= ~CCB_PCMODE; mouse_scan = !(val & 0x20); - kbdlog("ATkbd: mouse is now %s\n", mouse_scan ? "enabled" : "disabled"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: mouse is now %s\n", mouse_scan ? "enabled" : "disabled"); - kbdlog("ATkbd: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + kbd_log("ATkbd: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); +#endif + } + + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); +} + + +static void +pulse_output(atkbd_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_output_port = dev->output_port & ~(0xf0 | mask); + write_output(dev, dev->output_port & (0xf0 | mask)); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); } } static void -kbd_output_pulse(atkbd_t *kbd, uint8_t mask) +pulse_poll(void *priv) { - if (mask != 0xF) { - kbd->old_output_port = kbd->output_port & ~(0xF0 | mask); - kbd_output_write(kbd, kbd->output_port & (0xF0 | mask)); - kbd->pulse_cb = 6LL * TIMER_USEC; - } + atkbd_t *dev = (atkbd_t *)priv; + + write_output(dev, dev->output_port | dev->old_output_port); } static void -kbd_pulse_poll(void *p) +set_enable_kbd(atkbd_t *dev, uint8_t enable) { - atkbd_t *kbd = (atkbd_t *) p; + dev->mem[0] &= 0xef; + dev->mem[0] |= (enable ? 0x00 : 0x10); - kbd_output_write(kbd, kbd->output_port | kbd->old_output_port); - kbd->pulse_cb = 0LL; + keyboard_scan = enable; } static void -kbd_timeout_poll(void *p) +set_enable_mouse(atkbd_t *dev, uint8_t enable) { - atkbd_t *kbd = (atkbd_t *) p; + dev->mem[0] &= 0xdf; + dev->mem[0] |= (enable ? 0x00 : 0x20); - kbd->key_wantdata = 0; - kbd->want60 = 0; - if (mouse_p) - mouse_clear_data(mouse_p); - - kbd->timeout = 0LL; -} - - -static void -kbd_keyboard_set(atkbd_t *kbd, uint8_t enable) -{ - kbd->mem[0] &= 0xef; - kbd->mem[0] |= (enable ? 0x00 : 0x10); - keyboard_scan = enable; -} - - -static void -kbd_mouse_set(atkbd_t *kbd, uint8_t enable) -{ - kbd->mem[0] &= 0xdf; - kbd->mem[0] |= (enable ? 0x00 : 0x20); - mouse_scan = enable; + mouse_scan = enable; } static uint8_t -kbd_write64_generic(void *p, uint8_t val) +write64_generic(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; + uint8_t current_drive; switch (val) { - case 0xa4: /*Check if password installed*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { - kbdlog("ATkbd: check if password installed\n"); - kbd_adddata(0xf1); + case 0xa4: /* check if password installed */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: check if password installed\n"); +#endif + add_data(dev, 0xf1); return 0; - } else - kbdlog("ATkbd: bad command A4\n"); + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbd: bad command A4\n"); +#endif break; - case 0xa7: /*Disable mouse port*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { - kbdlog("ATkbd: disable mouse port\n"); - kbd_mouse_set(kbd, 0); - return 0; - } else - kbdlog("ATkbd: bad command A7\n"); - break; - case 0xa8: /*Enable mouse port*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { - kbdlog("ATkbd: enable mouse port\n"); - kbd_mouse_set(kbd, 1); - return 0; - } else - kbdlog("ATkbd: bad command A8\n"); - break; - case 0xa9: /*Test mouse port*/ - kbdlog("ATkbd: test mouse port\n"); - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { - if (mouse_write) - kbd_adddata(0x00); /*no error*/ - else - kbd_adddata(0xff); /*no mouse*/ - return 0; - } else - kbdlog("ATkbd: bad command A9\n"); - break; - case 0xaf: /*Read keyboard version*/ - kbdlog("ATkbd: read keyboard version\n"); - kbd_adddata(0x00); - return 0; - case 0xc0: /*Read input port*/ - kbdlog("ATkbd: read input port\n"); - kbd_adddata(kbd->input_port | 4 | fdc_ps1_525()); - kbd->input_port = ((kbd->input_port + 1) & 3) | (kbd->input_port & 0xfc) | fdc_ps1_525(); + case 0xa7: /* disable mouse port */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: disable mouse port\n"); +#endif + set_enable_mouse(dev, 0); + return 0; + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbd: bad command A7\n"); +#endif + break; + + case 0xa8: /*Enable mouse port*/ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: enable mouse port\n"); +#endif + set_enable_mouse(dev, 1); + return 0; + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbd: bad command A8\n"); +#endif + break; + + case 0xa9: /*Test mouse port*/ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: test mouse port\n"); +#endif + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (mouse_write) + add_data(dev, 0x00); /* no error */ + else + add_data(dev, 0xff); /* no mouse */ + return 0; + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbd: bad command A9\n"); +#endif + break; + + case 0xaf: /* read keyboard version */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: read keyboard version\n"); +#endif + add_data(dev, 0x00); return 0; - case 0xd3: /*Write mouse output buffer*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { - kbdlog("ATkbd: write mouse output buffer\n"); - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; + + case 0xc0: /* read input port */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: read input port\n"); +#endif + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_IBM_PS1) { + current_drive = fdc_get_current_drive(); + add_data(dev, dev->input_port | 4 | (fdd_is_525(current_drive) ? 0x40 : 0x00)); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc) | + (fdd_is_525(current_drive) ? 0x40 : 0x00); + } else { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + add_data(dev, (dev->input_port | 4) & 0xef); + else + add_data(dev, dev->input_port | 4); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); + } + return 0; + + case 0xd3: /* write mouse output buffer */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write mouse output buffer\n"); +#endif + dev->want60 = 1; return 0; } break; - case 0xd4: /*Write to mouse*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { - kbdlog("ATkbd: write to mouse\n"); - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; + + case 0xd4: /* write to mouse */ +#if 0 + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#endif +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write to mouse\n"); +#endif + dev->want60 = 1; return 0; +#if 0 } break; +#endif + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: - // kbdlog("ATkbd: pulse %01X\n", val & 0x0f); - kbd_output_pulse(kbd, val & 0x0f); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: pulse %01X\n", val & 0x0f); +#endif + pulse_output(dev, val & 0x0f); return 0; } @@ -1117,11 +1225,45 @@ kbd_write64_generic(void *p, uint8_t val) static uint8_t -kbd_write60_ami(void *p, uint8_t val) +write60_acer(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; +#if 0 + atkbd_t *dev = (atkbd_t *)priv; - switch(kbd->command) { + switch(dev->command) { + case 0xc0: /* sent by Acer V30 BIOS */ + return 0; + } +#endif + + return 1; +} + + +static uint8_t +write64_acer(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *)priv; + + kbd_log("ACER: write64(%02x, %02x)\n", dev->command, val); + +#if 0 + switch (val) { + case 0xc0: /* sent by Acer V30 BIOS */ + return 0; + } +#endif + + return write64_generic(dev, val); +} + + +static uint8_t +write60_ami(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *)priv; + + switch(dev->command) { /* 0x40 - 0x5F are aliases for 0x60-0x7F */ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: @@ -1131,25 +1273,30 @@ kbd_write60_ami(void *p, uint8_t val) case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbdlog("AMI - alias write to register %08X\n", kbd->command); - kbd->mem[kbd->command & 0x1f] = val; - if (kbd->command == 0x60) - kbd_cmd_write(kbd, val); + kbd_log("ATkbd: AMI - alias write to %08X\n", dev->command); + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) + write_cmd(dev, val); return 0; - case 0xaf: /*AMI - set extended controller RAM*/ - kbdlog("AMI - set extended controller RAM\n"); - if (kbd->secr_phase == 1) { - kbd->mem_addr = val; - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; - kbd->secr_phase = 2; - } else if (kbd->secr_phase == 2) { - kbd->mem[kbd->mem_addr] = val; - kbd->secr_phase = 0; + + case 0xaf: /* set extended controller RAM */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - set extended controller RAM\n"); +#endif + if (dev->secr_phase == 1) { + dev->mem_addr = val; + dev->want60 = 1; + dev->secr_phase = 2; + } else if (dev->secr_phase == 2) { + dev->mem[dev->mem_addr] = val; + dev->secr_phase = 0; } return 0; - case 0xcb: /*AMI - set keyboard mode*/ - kbdlog("AMI - set keyboard mode\n"); + + case 0xcb: /* set keyboard mode */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - set keyboard mode\n"); +#endif return 0; } @@ -1158,9 +1305,9 @@ kbd_write60_ami(void *p, uint8_t val) static uint8_t -kbd_write64_ami(void *p, uint8_t val) +write64_ami(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; switch (val) { case 0x00: case 0x01: case 0x02: case 0x03: @@ -1171,9 +1318,10 @@ kbd_write64_ami(void *p, uint8_t val) case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: - kbdlog("AMI - alias read from register %08X\n", val); - kbd_adddata(kbd->mem[val]); + kbd_log("ATkbd: AMI - alias read from %08X\n", val); + add_data(dev, dev->mem[val]); return 0; + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: @@ -1182,172 +1330,233 @@ kbd_write64_ami(void *p, uint8_t val) case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbdlog("AMI - alias write to register %08X\n", kbd->command); - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; + kbd_log("ATkbd: AMI - alias write to %08X\n", dev->command); + dev->want60 = 1; return 0; - case 0xa1: /*AMI - get controller version*/ - kbdlog("AMI - get controller version\n"); + + case 0xa1: /* get controller version */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - get controller version\n"); +#endif return 0; - case 0xa2: /*AMI - reset keyboard controller lines P22 and P23 low*/ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { - kbdlog("AMI - reset keyboard controller lines P22 and P23 low\n"); - kbd_output_write(kbd, kbd->output_port & 0xf3); - kbd_adddata(0x00); + + case 0xa2: /* clear keyboard controller lines P22/P23 */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - clear KBC lines P22 and P23\n"); +#endif + write_output(dev, dev->output_port & 0xf3); + add_data(dev, 0x00); return 0; } break; - case 0xa3: /*AMI - set keyboard controller lines P22 and P23 high*/ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { - kbdlog("AMI - set keyboard controller lines P22 and P23 high\n"); - kbd_output_write(kbd, kbd->output_port | 0x0c); - kbd_adddata(0x00); + + case 0xa3: /* set keyboard controller lines P22/P23 */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - set KBC lines P22 and P23\n"); +#endif + write_output(dev, dev->output_port | 0x0c); + add_data(dev, 0x00); return 0; } break; - case 0xa4: /* AMI - write clock = low */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { - kbdlog("AMI - write clock = low\n"); - kbd->ami_stat &= 0xfe; + + case 0xa4: /* write clock = low */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - write clock = low\n"); +#endif + dev->ami_stat &= 0xfe; return 0; } break; - case 0xa5: /* AMI - write clock = high */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { - kbdlog("AMI - write clock = high\n"); - kbd->ami_stat |= 0x01; + + case 0xa5: /* write clock = high */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - write clock = high\n"); +#endif + dev->ami_stat |= 0x01; return 0; } break; - case 0xa6: /* AMI - read clock */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { - kbdlog("AMI - read clock\n"); - kbd_adddata(!!(kbd->ami_stat & 1)); + + case 0xa6: /* read clock */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - read clock\n"); +#endif + add_data(dev, !!(dev->ami_stat & 1)); return 0; } break; - case 0xa7: /* AMI - write cache bad */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { - kbdlog("AMI - write cache bad\n"); - kbd->ami_stat &= 0xfd; + + case 0xa7: /* write cache bad */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - write cache bad\n"); +#endif + dev->ami_stat &= 0xfd; return 0; } break; - case 0xa8: /* AMI - write cache good */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { - kbdlog("AMI - write cache good\n"); - kbd->ami_stat |= 0x02; + + case 0xa8: /* write cache good */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - write cache good\n"); +#endif + dev->ami_stat |= 0x02; return 0; } break; - case 0xa9: /* AMI - read cache */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { - kbdlog("AMI - read cache\n"); - kbd_adddata(!!(kbd->ami_stat & 2)); + + case 0xa9: /* read cache */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - read cache\n"); +#endif + add_data(dev, !!(dev->ami_stat & 2)); return 0; } break; - case 0xaf: /*Set extended controller RAM*/ - kbdlog("ATkbd: set extended controller RAM\n"); - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; - kbd->secr_phase = 1; + + case 0xaf: /* set extended controller RAM */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: set extended controller RAM\n"); +#endif + dev->want60 = 1; + dev->secr_phase = 1; return 0; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: - /*Set keyboard controller line P10-P13 (input port bits 0-3) low*/ + /* set KBC lines P10-P13 (input port bits 0-3) low */ if (!PCI || (val > 0xb1)) - kbd->input_port &= ~(1 << (val & 0x03)); - kbd_adddata(0x00); + dev->input_port &= ~(1 << (val & 0x03)); + add_data(dev, 0x00); return 0; + case 0xb4: case 0xb5: - /*Set keyboard controller line P22-P23 (output port bits 2-3) low*/ - if (!PCI) - kbd_output_write(kbd, kbd->output_port & ~(4 << (val & 0x01))); - kbd_adddata(0x00); + /* set KBC lines P22-P23 (output port bits 2-3) low */ + if (! PCI) + write_output(dev, dev->output_port & ~(4 << (val & 0x01))); + add_data(dev, 0x00); return 0; + case 0xb8: case 0xb9: case 0xba: case 0xbb: - /*Set keyboard controller line P10-P13 (input port bits 0-3) high*/ + /* set KBC lines P10-P13 (input port bits 0-3) high */ if (!PCI || (val > 0xb9)) { - kbd->input_port |= (1 << (val & 0x03)); - kbd_adddata(0x00); + dev->input_port |= (1 << (val & 0x03)); + add_data(dev, 0x00); } return 0; + case 0xbc: case 0xbd: - /*Set keyboard controller line P22-P23 (output port bits 2-3) high*/ - if (!PCI) - kbd_output_write(kbd, kbd->output_port | (4 << (val & 0x01))); - kbd_adddata(0x00); + /* set KBC lines P22-P23 (output port bits 2-3) high */ + if (! PCI) + write_output(dev, dev->output_port | (4 << (val & 0x01))); + add_data(dev, 0x00); return 0; - case 0xc8: /*AMI - unblock keyboard controller lines P22 and P23 - (allow command D1 to change bits 2 and 3 of the output - port)*/ - kbdlog("AMI - unblock keyboard controller lines P22 and P23\n"); - kbd->output_locked = 1; + + case 0xc8: + /* + * unblock KBC lines P22/P23 + * (allow command D1 to change bits 2/3 of the output port) + */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - unblock KBC lines P22 and P23\n"); +#endif + dev->output_locked = 1; return 0; - case 0xc9: /*AMI - block keyboard controller lines P22 and P23 - (prevent command D1 from changing bits 2 and 3 of the - output port)*/ - kbdlog("AMI - block keyboard controller lines P22 and P23\n"); - kbd->output_locked = 1; + + case 0xc9: + /* + * block KBC lines P22/P23 + * (disallow command D1 from changing bits 2/3 of the port) + */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - block KBC lines P22 and P23\n"); +#endif + dev->output_locked = 1; return 0; - case 0xca: /*AMI - read keyboard mode*/ - kbdlog("AMI - read keyboard mode\n"); - kbd_adddata(0x00); /*ISA mode*/ + + case 0xca: /* read keyboard mode */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - read keyboard mode\n"); +#endif + add_data(dev, 0x00); /*ISA mode*/ return 0; - case 0xcb: /*AMI - set keyboard mode*/ - kbdlog("AMI - set keyboard mode\n"); - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; + + case 0xcb: /* set keyboard mode */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: AMI - set keyboard mode\n"); +#endif + dev->want60 = 1; return 0; - case 0xef: /*??? - sent by AMI486*/ - kbdlog("??? - sent by AMI486\n"); + + case 0xef: /* ??? - sent by AMI486 */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: ??? - sent by AMI486\n"); +#endif return 0; } - return kbd_write64_generic(kbd, val); + return write64_generic(dev, val); } static uint8_t -kbd_write64_ibm_mca(void *p, uint8_t val) +write64_ibm_mca(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; switch (val) { case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ - kbdlog("ATkbd: copy bits 0 to 3 of input port to status bits 4 to 7\n"); - kbd->status &= 0xf; - kbd->status |= ((((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf) << 4); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: copy bits 0 to 3 of input port to status bits 4 to 7\n"); +#endif + dev->status &= 0x0f; + dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); return 0; + case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ - kbdlog("ATkbd: copy bits 4 to 7 of input port to status bits 4 to 7\n"); - kbd->status &= 0xf; - kbd->status |= (((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf0); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: copy bits 4 to 7 of input port to status bits 4 to 7\n"); +#endif + dev->status &= 0x0f; + dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); return 0; + case 0xaf: - kbdlog("ATkbd: bad kbc command AF\n"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: bad KBC command AF\n"); +#endif return 1; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: - kbdlog("ATkbd: pulse: %01X\n", (val & 0x03) | 0x0c); - kbd_output_pulse(kbd, (val & 0x03) | 0x0c); + kbd_log("ATkbd: pulse: %01X\n", (val & 0x03) | 0x0c); + pulse_output(dev, (val & 0x03) | 0x0c); return 0; } - return kbd_write64_generic(kbd, val); + return write64_generic(dev, val); } static uint8_t -kbd_write60_quadtel(void *p, uint8_t val) +write60_quadtel(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; - switch(kbd->command) { - case 0xcf: /*??? - sent by MegaPC BIOS*/ - kbdlog("??? - sent by MegaPC BIOS\n"); + switch(dev->command) { + case 0xcf: /*??? - sent by MegaPC BIOS*/ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: ??? - sent by MegaPC BIOS\n"); +#endif return 0; } @@ -1356,32 +1565,36 @@ kbd_write60_quadtel(void *p, uint8_t val) static uint8_t -kbd_write64_quadtel(void *p, uint8_t val) +write64_quadtel(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; switch (val) { case 0xaf: - kbdlog("ATkbd: bad kbc command AF\n"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: bad KBC command AF\n"); +#endif return 1; - case 0xcf: /*??? - sent by MegaPC BIOS*/ - kbdlog("??? - sent by MegaPC BIOS\n"); - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: ??? - sent by MegaPC BIOS\n"); +#endif + dev->want60 = 1; return 0; } - return kbd_write64_generic(kbd, val); + return write64_generic(dev, val); } static uint8_t -kbd_write60_toshiba(void *p, uint8_t val) +write60_toshiba(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; - switch(kbd->command) { - case 0xb6: /* T3100e - set colour/mono switch */ + switch(dev->command) { + case 0xb6: /* T3100e - set color/mono switch */ t3100e_mono_set(val); return 0; } @@ -1391,83 +1604,102 @@ kbd_write60_toshiba(void *p, uint8_t val) static uint8_t -kbd_write64_toshiba(void *p, uint8_t val) +write64_toshiba(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; switch (val) { case 0xaf: - kbdlog("ATkbd: bad kbc command AF\n"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: bad KBC command AF\n"); +#endif return 1; - case 0xb0: /* T3100e: Turbo on */ + + case 0xb0: /* T3100e: Turbo on */ t3100e_turbo_set(1); return 0; - case 0xb1: /* T3100e: Turbo off */ + + case 0xb1: /* T3100e: Turbo off */ t3100e_turbo_set(0); return 0; - case 0xb2: /* T3100e: Select external display */ + + case 0xb2: /* T3100e: Select external display */ t3100e_display_set(0x00); return 0; - case 0xb3: /* T3100e: Select internal display */ + + case 0xb3: /* T3100e: Select internal display */ t3100e_display_set(0x01); return 0; - case 0xb4: /* T3100e: Get configuration / status */ - kbd_adddata(t3100e_config_get()); + + case 0xb4: /* T3100e: Get configuration / status */ + add_data(dev, t3100e_config_get()); return 0; - case 0xb5: /* T3100e: Get colour / mono byte */ - kbd_adddata(t3100e_mono_get()); + + case 0xb5: /* T3100e: Get colour / mono byte */ + add_data(dev, t3100e_mono_get()); return 0; - case 0xb6: /* T3100e: Set colour / mono byte */ - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; + + case 0xb6: /* T3100e: Set colour / mono byte */ + dev->want60 = 1; return 0; - case 0xb7: /* T3100e: Emulate PS/2 keyboard - not implemented */ - case 0xb8: /* T3100e: Emulate AT keyboard - not implemented */ + + case 0xb7: /* T3100e: Emulate PS/2 keyboard - not implemented */ + case 0xb8: /* T3100e: Emulate AT keyboard - not implemented */ return 0; - 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'. */ + + 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 (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ - kbd_adddata(0x04); - else kbd_adddata(0x00); + add_data(dev, 0x04); + else add_data(dev, 0x00); return 0; - case 0xbc: /* T3100e: Reset Fn+Key notification */ + + case 0xbc: /* T3100e: Reset Fn+Key notification */ t3100e_notify_set(0x00); return 0; - case 0xc0: /*Read input port*/ - kbdlog("ATkbd: read input port\n"); + + case 0xc0: /*Read input port*/ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: read input port\n"); +#endif /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ - kbd->input_port = (t3100e_mono_get() & 1) ? 0xFF : 0xBF; - kbd_adddata(kbd->input_port); + dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + add_data(dev, dev->input_port); return 0; } - return kbd_write64_generic(kbd, val); + return write64_generic(dev, val); } static void kbd_write(uint16_t port, uint8_t val, void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; int i = 0; int bad = 1; uint8_t mask; - if (romset == ROM_XI8088 && port == 0x63) + if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63)) port = 0x61; +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write(%04X, %02X)\n", port, val); +#endif + switch (port) { case 0x60: - if (kbd->want60) { - /*Write to controller*/ - kbd->want60 = 0; - switch (kbd->command) { + if (dev->want60) { + /* Write data to controller. */ + dev->want60 = 0; + + switch (dev->command) { case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: @@ -1476,205 +1708,301 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: - kbd->mem[kbd->command & 0x1f] = val; - if (kbd->command == 0x60) - kbd_cmd_write(kbd, val); + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) + write_cmd(dev, val); break; - case 0xd1: /*Write output port*/ - // kbdlog("Write output port\n"); - if (kbd->output_locked) { + case 0xd1: /* write output port */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write output port\n"); +#endif + if (dev->output_locked) { /*If keyboard controller lines P22-P23 are blocked, we force them to remain unchanged.*/ val &= ~0x0c; - val |= (kbd->output_port & 0x0c); + val |= (dev->output_port & 0x0c); } - kbd_output_write(kbd, val); + write_output(dev, val); break; - case 0xd2: /*Write to keyboard output buffer*/ - kbdlog("ATkbd: write to keyboard output buffer\n"); - kbd_adddata_keyboard(val); + case 0xd2: /* write to keyboard output buffer */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write to keyboard output buffer\n"); +#endif + add_data_kbd(val); break; - case 0xd3: /*Write to mouse output buffer*/ - kbdlog("ATkbd: write to mouse output buffer\n"); - if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + case 0xd3: /* write to mouse output buffer */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write to mouse output buffer\n"); +#endif + if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) keyboard_at_adddata_mouse(val); break; - case 0xd4: /*Write to mouse*/ - kbdlog("ATkbd: write to mouse (%02X)\n", val); - kbd_mouse_set(kbd, 1); - if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + case 0xd4: /* write to mouse */ + kbd_log("ATkbd: write to mouse (%02X)\n", val); + + if (val == 0xbb) + break; + + set_enable_mouse(dev, 1); + if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) mouse_write(val, mouse_p); - else if (!mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + else if (!mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && + ((dev->flags & KBC_VEN_MASK) == KBC_VEN_AMI)) keyboard_at_adddata_mouse(0xff); break; default: - /* Run the vendor-specific command handler, if present, - otherwise (or if the former returns 1), assume bad command. */ - if (kbd->write60_ven) - bad = kbd->write60_ven(kbd, val); + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); - if (bad) - kbdlog("ATkbd: bad keyboard controller 0060 write %02X command %02X\n", val, kbd->command); + if (bad) { + kbd_log("ATkbd: bad controller command %02x data %02x\n", dev->command, val); + add_data_kbd(0xfe); + } } } else { - /*Write to keyboard*/ - kbd->mem[0] &= ~0x10; - if (kbd->key_wantdata) { - kbd->key_wantdata = 0; - switch (kbd->key_command) { - case 0xed: /*Set/reset LEDs*/ - kbd_adddata_keyboard(0xfa); + /* Write data to keyboard. */ + dev->mem[0] &= ~0x10; + + if (dev->key_wantdata) { + dev->key_wantdata = 0; + + /* + * Several system BIOSes and OS device drivers + * mess up with this, and repeat the command + * code many times. Fun! + */ + if (val == dev->key_command) { +#if 1 + /* Respond NAK and ignore it. */ + add_data_kbd(0xfe); + dev->key_command = 0x00; + break; +#else + goto do_command; +#endif + } + + switch (dev->key_command) { + case 0xed: /* set/reset LEDs */ + add_data_kbd(0xfa); + kbd_log("ATkbd: set LEDs [%02x]\n", val); break; - case 0xf0: /*Get/set scancode set*/ + case 0xf0: /* get/set scancode set */ + add_data_kbd(0xfa); if (val == 0) { - kbd_adddata_keyboard(keyboard_mode & 3); + kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); + add_data_kbd(keyboard_mode & 3); } else { - if (val <= 3) { - keyboard_mode &= 0xFC; + if ((val <= 3) && (val != 1)) { + keyboard_mode &= 0xfc; keyboard_mode |= (val & 3); + kbd_log("Scan code set now: %02X\n", val); } - kbd_adddata_keyboard(0xfa); - kbd_setmap(kbd); + set_scancode_map(dev); } break; - case 0xf3: /*Set typematic rate/delay*/ - kbd_adddata_keyboard(0xfa); + case 0xf3: /* set typematic rate/delay */ + add_data_kbd(0xfa); break; default: - kbdlog("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, kbd->key_command); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); +#endif + add_data_kbd(0xfe); + break; } + + /* Keyboard command is now done. */ + dev->key_command = 0x00; } else { - kbd->key_command = val; - kbd_keyboard_set(kbd, 1); +#if 0 +do_command: +#endif + /* No keyboard command in progress. */ + dev->key_command = 0x00; + + set_enable_kbd(dev, 1); + switch (val) { case 0x00: - kbdlog("ATkbd: command 00\n"); - kbd_adddata_keyboard(0xfa); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: command 00\n"); +#endif + add_data_kbd(0xfa); break; case 0x05: /*??? - sent by NT 4.0*/ - kbdlog("ATkbd: nt 4.0 command fe\n"); - kbd_adddata_keyboard(0xfe); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: command 05 (NT 4.0)\n"); +#endif + add_data_kbd(0xfe); break; - case 0x71: /*These two commands are sent by Pentium-era AMI BIOS'es.*/ + /* Sent by Pentium-era AMI BIOS'es.*/ + case 0x71: case 0x82: - kbdlog("ATkbd: pentium-era ami bios command %02x\n", val); + kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); break; - case 0xed: /*Set/reset LEDs*/ - kbdlog("ATkbd: set/reset leds\n"); - kbd->key_wantdata = 1; - kbd->timeout = 25000LL * TIMER_USEC; - kbd_adddata_keyboard(0xfa); + case 0xed: /* set/reset LEDs */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: set/reset leds\n"); +#endif + add_data_kbd(0xfa); + + dev->key_wantdata = 1; break; - case 0xee: /*Diagnostic echo*/ - kbdlog("ATkbd: diagnostic echo\n"); - kbd_adddata_keyboard(0xee); + case 0xee: /* diagnostic echo */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: ECHO\n"); +#endif + add_data_kbd(0xee); break; - case 0xef: /*NOP (No OPeration). Reserved for future use.*/ - kbdlog("ATkbd: kbd nop\n"); + case 0xef: /* NOP (reserved for future use) */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: NOP\n"); +#endif break; - case 0xf0: /*Get/set scan code set*/ - kbdlog("ATkbd: scan code set\n"); - kbd->key_wantdata = 1; - kbd->timeout = 25000LL * TIMER_USEC; - kbd_adddata_keyboard(0xfa); + case 0xf0: /* get/set scan code set */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: scan code set\n"); +#endif + add_data_kbd(0xfa); + dev->key_wantdata = 1; break; - case 0xf2: /*Read ID*/ - /* Fixed as translation will be done in kbd_adddata_keyboard(). */ - kbdlog("ATkbd: read keyboard id\n"); - kbd_adddata_keyboard(0xfa); - kbd_adddata_keyboard(0xab); - kbd_adddata_keyboard(0x83); + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: read keyboard id\n"); +#endif + add_data_kbd(0xfa); + add_data_kbd(0xab); + add_data_kbd(0x83); break; - case 0xf3: /*Set typematic rate/delay*/ - kbdlog("ATkbd: set typematic rate/delay\n"); - kbd->key_wantdata = 1; - kbd->timeout = 25000LL * TIMER_USEC; - kbd_adddata_keyboard(0xfa); + case 0xf3: /* set typematic rate/delay */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: set typematic rate/delay\n"); +#endif + add_data_kbd(0xfa); + dev->key_wantdata = 1; break; - case 0xf4: /*Enable keyboard*/ - kbdlog("ATkbd: enable keyboard via keyboard\n"); + case 0xf4: /* enable keyboard */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: enable keyboard via keyboard\n"); +#endif + add_data_kbd(0xfa); keyboard_scan = 1; - kbd_adddata_keyboard(0xfa); break; - case 0xf5: /*Disable keyboard*/ - kbdlog("ATkbd: disable keyboard via keyboard\n"); + case 0xf5: /* disable keyboard */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: disable keyboard via keyboard\n"); +#endif keyboard_scan = 0; - kbd_adddata_keyboard(0xfa); - break; - case 0xf6: /*Set defaults*/ - kbdlog("ATkbd: set defaults\n"); + /* + * Disabling the keyboard also + * resets it to the default + * values. + */ + /*FALLTHROUGH*/ + + case 0xf6: /* set defaults */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: set defaults\n"); +#endif + dev->out_new = -1; + dev->out_delayed = -1; + add_data_kbd(0xfa); + keyboard_set3_all_break = 0; keyboard_set3_all_repeat = 0; memset(keyboard_set3_flags, 0, 512); - keyboard_mode = (keyboard_mode & 0xFC) | 0x02; - kbd_adddata_keyboard(0xfa); - kbd_setmap(kbd); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); break; - case 0xf7: /*Set all keys to repeat*/ - kbdlog("ATkbd: set all keys to repeat\n"); + case 0xf7: /* set all keys to repeat */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: set all keys to repeat\n"); +#endif + add_data_kbd(0xfa); keyboard_set3_all_break = 1; - kbd_adddata_keyboard(0xfa); break; - case 0xf8: /*Set all keys to give make/break codes*/ - kbdlog("ATkbd: set all keys to give make/break codes\n"); + case 0xf8: /* set all keys to give make/break codes */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: set all keys to give make/break codes\n"); +#endif + add_data_kbd(0xfa); keyboard_set3_all_break = 1; - kbd_adddata_keyboard(0xfa); break; - case 0xf9: /*Set all keys to give make codes only*/ - kbdlog("ATkbd: set all keys to give make codes only\n"); + case 0xf9: /* set all keys to give make codes only */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: set all keys to give make codes only\n"); +#endif + add_data_kbd(0xfa); keyboard_set3_all_break = 0; - kbd_adddata_keyboard(0xfa); break; - case 0xfa: /*Set all keys to repeat and give make/break codes*/ - kbdlog("ATkbd: set all keys to repeat and give make/break codes\n"); + case 0xfa: /* set all keys to repeat and give make/break codes */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); +#endif + add_data_kbd(0xfa); keyboard_set3_all_repeat = 1; keyboard_set3_all_break = 1; - kbd_adddata_keyboard(0xfa); break; - case 0xfe: /*Resend last scan code*/ - kbdlog("ATkbd: reset last scan code\n"); - kbd_adddata_keyboard(kbd->last_scan_code); + case 0xfe: /* resend last scan code */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: reset last scan code\n"); +#endif + add_data_kbd(key_queue[key_queue_end]); break; - case 0xff: /*Reset*/ - kbdlog("ATkbd: kbd reset\n"); + case 0xff: /* reset */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: kbd reset\n"); +#endif key_queue_start = key_queue_end = 0; /*Clear key queue*/ - kbd_adddata_keyboard(0xfa); - kbd_adddata_keyboard(0xaa); - /* Set system flag to 1 and scan code set to 2. */ - keyboard_mode &= 0xFC; - keyboard_mode |= 2; - kbd_setmap(kbd); + add_data_kbd(0xfa); + add_data_kbd(0xaa); + + /* Set scan code set to 2. */ + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); break; default: - kbdlog("ATkbd: bad keyboard command %02X\n", val); - kbd_adddata_keyboard(0xfe); + kbd_log("ATkbd: bad keyboard command %02X\n", val); + add_data_kbd(0xfe); } + + /* If command needs data, remember command. */ + if (dev->key_wantdata == 1) + dev->key_command = val; } } break; @@ -1682,29 +2010,27 @@ kbd_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); + pit_ctr_set_gate(&pit->counters[2], val & 1); - if (romset == ROM_XI8088) { - if (val & 0x04) - xi8088_turbo_set(1); - else - xi8088_turbo_set(0); - } + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) +#ifdef USE_NEW_STUFF + dev->write_func(dev->func_priv, !!(val & 0x04)); +#else + xi8088_turbo_set(!!(val & 0x04)); +#endif break; case 0x64: - kbd->want60 = 0; - kbd->command = val; - /*New controller command*/ + /* Controller command. */ + dev->want60 = 0; + switch (val) { + /* Read data from KBC memory. */ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b: @@ -1713,9 +2039,10 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: - kbd_adddata(kbd->mem[val & 0x1f]); + add_data(dev, dev->mem[val & 0x1f]); break; + /* Write data to KBC memory. */ case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: @@ -1724,98 +2051,135 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; + dev->want60 = 1; break; - case 0xaa: /*Self-test*/ - kbdlog("Self-test\n"); - if ((kbd->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) - kbd->status |= STAT_IFULL; - if (! kbd->initialized) { - kbd->initialized = 1; + case 0xaa: /* self-test */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: self-test\n"); +#endif + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) + dev->status |= STAT_IFULL; + if (! dev->initialized) { + dev->initialized = 1; key_ctrl_queue_start = key_ctrl_queue_end = 0; - kbd->status &= ~STAT_OFULL; + dev->status &= ~STAT_OFULL; } - kbd->status |= STAT_SYSFLAG; - kbd->mem[0] |= 0x04; - kbd_keyboard_set(kbd, 1); - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) - kbd_mouse_set(kbd, 1); - kbd_output_write(kbd, 0xcf); - kbd_adddata(0x55); + dev->status |= STAT_SYSFLAG; + dev->mem[0] |= 0x04; + keyboard_mode |= 0x04; + set_enable_kbd(dev, 1); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + set_enable_mouse(dev, 1); + write_output(dev, 0xcf); + add_data(dev, 0x55); break; - case 0xab: /*Interface test*/ - kbdlog("ATkbd: interface test\n"); - kbd_adddata(0x00); /*no error*/ + case 0xab: /* interface test */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: interface test\n"); +#endif + add_data(dev, 0x00); /*no error*/ break; - case 0xac: /*Diagnostic dump*/ - kbdlog("ATkbd: diagnostic dump\n"); - for (i=0; i<16; i++) - kbd_adddata(kbd->mem[i]); - kbd_adddata((kbd->input_port & 0xf0) | 0x80); - kbd_adddata(kbd->output_port); - kbd_adddata(kbd->status); + case 0xac: /* diagnostic dump */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: diagnostic dump\n"); +#endif + for (i = 0; i < 16; i++) + add_data(dev, dev->mem[i]); + add_data(dev, (dev->input_port & 0xf0) | 0x80); + add_data(dev, dev->output_port); + add_data(dev, dev->status); break; - case 0xad: /*Disable keyboard*/ - kbdlog("ATkbd: disable keyboard\n"); - kbd_keyboard_set(kbd, 0); + case 0xad: /* disable keyboard */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: disable keyboard\n"); +#endif + set_enable_kbd(dev, 0); break; - case 0xae: /*Enable keyboard*/ - kbdlog("ATkbd: enable keyboard\n"); - kbd_keyboard_set(kbd, 1); + case 0xae: /* enable keyboard */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: enable keyboard\n"); +#endif + set_enable_kbd(dev, 1); break; - case 0xd0: /*Read output port*/ - kbdlog("ATkbd: read output port\n"); + case 0xd0: /* read output port */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: read output port\n"); +#endif mask = 0xff; - if(!keyboard_scan) + if (!keyboard_scan) mask &= 0xbf; - if(!mouse_scan && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + if (!mouse_scan && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) mask &= 0xf7; - kbd_adddata(kbd->output_port & mask); + add_data(dev, dev->output_port & mask); break; - case 0xd1: /*Write output port*/ - // kbdlog("ATkbd: write output port\n"); - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; + case 0xd1: /* write output port */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write output port\n"); +#endif + dev->want60 = 1; break; - case 0xd2: /*Write keyboard output buffer*/ - kbdlog("ATkbd: write keyboard output buffer\n"); - kbd->want60 = 1; - kbd->timeout = 25000LL * TIMER_USEC; + case 0xd2: /* write keyboard output buffer */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write keyboard output buffer\n"); +#endif + dev->want60 = 1; break; - case 0xdd: /* Disable A20 Address Line */ - kbdlog("ATkbd: disable A20 Address Line\n"); - kbd_output_write(kbd, kbd->output_port & 0xfd); +#if 0 + case 0xd4: /* dunno, but OS/2 2.00LA sends it */ + dev->want60 = 1; + break; +#endif + + case 0xdd: /* disable A20 address line */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: disable A20\n"); +#endif + write_output(dev, dev->output_port & 0xfd); break; - case 0xdf: /* Enable A20 Address Line */ - kbdlog("ATkbd: enable A20 address line\n"); - kbd_output_write(kbd, kbd->output_port | 0x02); + case 0xdf: /* enable A20 address line */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: enable A20\n"); +#endif + write_output(dev, dev->output_port | 0x02); break; - case 0xe0: /*Read test inputs*/ - kbdlog("ATkbd: read test inputs\n"); - kbd_adddata(0x00); + case 0xe0: /* read test inputs */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: read test inputs\n"); +#endif + add_data(dev, 0x00); break; default: - /* Run the vendor-specific command handler, if present, - otherwise (or if the former returns 1), assume bad command. */ - if (kbd->write64_ven) - bad = kbd->write64_ven(kbd, val); + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); +#ifdef ENABLE_KEYBOARD_AT_LOG if (bad) - kbdlog("ATkbd: bad controller command %02X\n", val); + kbd_log("ATkbd: bad controller command %02X\n", val); +#endif } + + /* If the command needs data, remember the command. */ + if (dev->want60) + dev->command = val; break; } } @@ -1824,32 +2188,38 @@ kbd_write(uint16_t port, uint8_t val, void *priv) static uint8_t kbd_read(uint16_t port, void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; - if (romset == ROM_XI8088 && port == 0x63) + if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63)) port = 0x61; switch (port) { case 0x60: - ret = kbd->out; - kbd->status &= ~(STAT_OFULL); - picintc(kbd->last_irq); - kbd->last_irq = 0; + ret = dev->out; + dev->status &= ~(STAT_OFULL); + if (dev->last_irq) { + picintc(dev->last_irq); + dev->last_irq = 0; + } break; case 0x61: ret = ppi.pb & ~0xe0; if (ppispeakon) ret |= 0x20; - if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { - if (kbd->refresh) + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { + if (dev->refresh) ret |= 0x10; else ret &= ~0x10; } - if (romset == ROM_XI8088){ - if (xi8088_turbo_get()) + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) { +#ifdef USE_NEW_STUFF + if (dev->read_func(dev->func_priv)) +#else + if (xi8088_turbo_get()) +#endif ret |= 0x04; else ret &= ~0x04; @@ -1857,14 +2227,26 @@ kbd_read(uint16_t port, void *priv) break; case 0x64: - ret = (kbd->status & 0xFB) | (keyboard_mode & CCB_SYSTEM); - ret |= STAT_LOCK; + // ret = (dev->status & 0xFB) | (keyboard_mode & CCB_SYSTEM); + // ret |= STAT_UNLOCKED; + ret = (dev->status & 0xFB); + if (dev->mem[0] & STAT_SYSFLAG) + ret |= STAT_SYSFLAG; /* The transmit timeout (TTIMEOUT) flag should *NOT* be cleared, otherwise the IBM PS/2 Model 80's BIOS gives error 8601 (mouse error). */ - kbd->status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + dev->status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + break; + + default: + kbd_log("ATkbd: read(%04x) invalid!\n", port); break; } +#ifdef ENABLE_KEYBOARD_AT_LOG + if (port != 0x61) + kbd_log("ATkbd: read(%04X) = %02X\n", port, ret); +#endif + return(ret); } @@ -1872,120 +2254,72 @@ kbd_read(uint16_t port, void *priv) static void kbd_refresh(void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; - kbd->refresh = !kbd->refresh; - kbd->refresh_time += PS2_REFRESH_TIME; + dev->refresh = !dev->refresh; + timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); } static void kbd_reset(void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; - kbd->initialized = 0; - kbd->dtrans = 0; - kbd->first_write = 1; - kbd->status = STAT_LOCK | STAT_CD; - kbd->mem[0] = 0x01; - kbd->wantirq = 0; - kbd_output_write(kbd, 0xcf); - kbd->input_port = (video_is_mda()) ? 0xf0 : 0xb0; - kbd->out_new = -1; - kbd->last_irq = 0; - kbd->secr_phase = 0; - kbd->key_wantdata = 0; - kbd->timeout = 0LL; + dev->initialized = 0; + dev->first_write = 1; + dev->status = STAT_UNLOCKED | STAT_CD; + dev->mem[0] = 0x01; + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) + dev->mem[0] |= CCB_TRANSLATE; + dev->wantirq = 0; + write_output(dev, 0xcf); + dev->out_new = -1; + dev->out_delayed = -1; + dev->last_irq = 0; + dev->secr_phase = 0; + dev->key_wantdata = 0; - keyboard_mode = 0x02 | kbd->dtrans; + /* Set up the correct Video Type bits. */ + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) + dev->input_port = video_is_mda() ? 0xb0 : 0xf0; + else + dev->input_port = video_is_mda() ? 0xf0 : 0xb0; + kbd_log("ATkbd: input port = %02x\n", dev->input_port); - kbd_keyboard_set(kbd, 1); - kbd_mouse_set(kbd, 0); + keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); + + /* Enable keyboard, disable mouse. */ + set_enable_kbd(dev, 1); + set_enable_mouse(dev, 0); sc_or = 0; - keyboard_update_states(0, 0, 0); memset(keyboard_set3_flags, 0, 512); - kbd_setmap(kbd); + set_scancode_map(dev); } -static void * -kbd_init(const device_t *info) +/* Reset the AT keyboard - this is needed for the PCI TRC and is done + until a better solution is found. */ +void +keyboard_at_reset(void) { - atkbd_t *kbd; - - kbd = (atkbd_t *)malloc(sizeof(atkbd_t)); - memset(kbd, 0x00, sizeof(atkbd_t)); - - kbd->flags = info->local; - - kbd_reset(kbd); - - io_sethandler(0x0060, 5, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); - keyboard_send = kbd_adddata_keyboard; - - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); - - if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { - if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) - keyboard_mode &= ~0x03; /* These machines force translation off, so the keyboard - must start in scan code set 0. */ - - timer_add(kbd_refresh, - &kbd->refresh_time, TIMER_ALWAYS_ENABLED, kbd); - } - - timer_add(kbd_pulse_poll, - &kbd->pulse_cb, &kbd->pulse_cb, kbd); - - timer_add(kbd_timeout_poll, - &kbd->timeout, &kbd->timeout, kbd); - - kbd->write60_ven = NULL; - kbd->write64_ven = NULL; - - switch(kbd->flags & KBC_VEN_MASK) { - case KBC_VEN_GENERIC: - kbd->write64_ven = &kbd_write64_generic; - break; - case KBC_VEN_AMI: - kbd->write60_ven = &kbd_write60_ami; - kbd->write64_ven = &kbd_write64_ami; - break; - case KBC_VEN_IBM_MCA: - kbd->write64_ven = &kbd_write64_ibm_mca; - break; - case KBC_VEN_QUADTEL: - kbd->write60_ven = &kbd_write60_quadtel; - kbd->write64_ven = &kbd_write64_quadtel; - break; - case KBC_VEN_TOSHIBA: - kbd->write60_ven = &kbd_write60_toshiba; - kbd->write64_ven = &kbd_write64_toshiba; - break; - } - - /* We need this, sadly. */ - CurrentKbd = kbd; - - return(kbd); + kbd_reset(SavedKbd); } static void kbd_close(void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; - kbd_reset(kbd); + kbd_reset(dev); /* Stop timers. */ - keyboard_delay = 0; - kbd->refresh_time = 0; + timer_disable(&dev->send_delay_timer); + timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -1993,8 +2327,74 @@ kbd_close(void *priv) /* Disable the scancode maps. */ keyboard_set_table(NULL); - CurrentKbd = NULL; - free(kbd); + SavedKbd = NULL; + free(dev); +} + + +static void * +kbd_init(const device_t *info) +{ + atkbd_t *dev; + + dev = (atkbd_t *)malloc(sizeof(atkbd_t)); + memset(dev, 0x00, sizeof(atkbd_t)); + + dev->flags = info->local; + + video_reset(gfxcard); + kbd_reset(dev); + + io_sethandler(0x0060, 5, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + keyboard_send = add_data_kbd; + + timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); + + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) + timer_add(&dev->refresh_time, kbd_refresh, dev, 1); + + timer_add(&dev->pulse_cb, pulse_poll, dev, 0); + + dev->write60_ven = NULL; + dev->write64_ven = NULL; + + switch(dev->flags & KBC_VEN_MASK) { + case KBC_VEN_GENERIC: + case KBC_VEN_IBM_PS1: + case KBC_VEN_XI8088: + dev->write64_ven = write64_generic; + break; + + case KBC_VEN_AMI: + dev->write60_ven = write60_ami; + dev->write64_ven = write64_ami; + break; + + case KBC_VEN_IBM_MCA: + dev->write64_ven = write64_ibm_mca; + break; + + case KBC_VEN_QUADTEL: + dev->write60_ven = write60_quadtel; + dev->write64_ven = write64_quadtel; + break; + + case KBC_VEN_TOSHIBA: + dev->write60_ven = write60_toshiba; + dev->write64_ven = write64_toshiba; + break; + + case KBC_VEN_ACER: + dev->write60_ven = write60_acer; + dev->write64_ven = write64_acer; + break; + } + + /* We need this, sadly. */ + SavedKbd = dev; + + return(dev); } @@ -2005,7 +2405,7 @@ const device_t keyboard_at_device = { kbd_init, kbd_close, kbd_reset, - NULL, NULL, NULL + NULL, NULL, NULL, NULL }; const device_t keyboard_at_ami_device = { @@ -2015,7 +2415,7 @@ const device_t keyboard_at_ami_device = { kbd_init, kbd_close, kbd_reset, - NULL, NULL, NULL + NULL, NULL, NULL, NULL }; const device_t keyboard_at_toshiba_device = { @@ -2025,27 +2425,57 @@ const device_t keyboard_at_toshiba_device = { kbd_init, kbd_close, kbd_reset, - NULL, NULL, NULL + NULL, NULL, NULL, NULL }; const device_t keyboard_ps2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ps2_device = { "PS/2 Keyboard", 0, KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, - NULL, NULL, NULL + NULL, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ps1_device = { + "PS/2 Keyboard (IBM PS/1)", + 0, + KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_xi8088_device = { + "PS/2 Keyboard (Xi8088)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_XI8088, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL, NULL }; const device_t keyboard_ps2_ami_device = { "PS/2 Keyboard (AMI)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, - NULL, NULL, NULL + NULL, NULL, NULL, NULL }; const device_t keyboard_ps2_mca_device = { @@ -2055,7 +2485,7 @@ const device_t keyboard_ps2_mca_device = { kbd_init, kbd_close, kbd_reset, - NULL, NULL, NULL + NULL, NULL, NULL, NULL }; const device_t keyboard_ps2_mca_2_device = { @@ -2065,23 +2495,23 @@ const device_t keyboard_ps2_mca_2_device = { kbd_init, kbd_close, kbd_reset, - NULL, NULL, NULL + NULL, NULL, NULL, NULL }; const device_t keyboard_ps2_quadtel_device = { "PS/2 Keyboard (Quadtel/MegaPC)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, + KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, kbd_init, kbd_close, kbd_reset, - NULL, NULL, NULL + NULL, NULL, NULL, NULL }; const device_t keyboard_ps2_pci_device = { "PS/2 Keyboard", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, @@ -2091,7 +2521,21 @@ const device_t keyboard_ps2_pci_device = { const device_t keyboard_ps2_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_acer_device = { + "PS/2 Keyboard (Acer 90M002A)", + DEVICE_PCI, +#ifdef KBC_VEN_ACER + KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, +#else + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, +#endif kbd_init, kbd_close, kbd_reset, @@ -2123,17 +2567,33 @@ keyboard_at_adddata_mouse(uint8_t val) } +#ifdef USE_NEW_STUFF +/* Set custom machine-dependent keyboard stuff. */ +void +keyboard_at_set_funcs(void *arg, uint8_t (*readfunc)(void *), void (*writefunc)(void *, uint8_t), void *priv) +{ + atkbd_t *dev = (atkbd_t *)arg; + + dev->read_func = readfunc; + dev->write_func = writefunc; + dev->func_priv = priv; +} +#endif + + void keyboard_at_set_mouse_scan(uint8_t val) { - atkbd_t *kbd = CurrentKbd; + atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; if (temp_mouse_scan == mouse_scan) return; - kbd_mouse_set(kbd, val ? 1 : 0); + set_enable_mouse(dev, val ? 1 : 0); - kbdlog("ATkbd: mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); +#endif } diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c index 80405387c..7f8be716c 100644 --- a/src/keyboard_xt.c +++ b/src/keyboard_xt.c @@ -8,15 +8,15 @@ * * Implementation of the XT-style keyboard. * - * Version: @(#)keyboard_xt.c 1.0.12 2018/04/26 + * Version: @(#)keyboard_xt.c 1.0.19 2019/11/15 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van kempen. */ #include #include @@ -24,15 +24,17 @@ #include #include #include "86box.h" +#include "device.h" +#include "timer.h" +#include "floppy/fdd.h" #include "machine/machine.h" +#include "machine/m_xt_t1000.h" #include "io.h" #include "pic.h" #include "pit.h" #include "ppi.h" #include "mem.h" #include "rom.h" -#include "timer.h" -#include "device.h" #include "sound/sound.h" #include "sound/snd_speaker.h" #include "video/video.h" @@ -50,279 +52,303 @@ typedef struct { + int want_irq; int blocked; - - uint8_t pa; - uint8_t pb; - int tandy; + + uint8_t pa, pb, pd; + uint8_t key_waiting; + uint8_t type; + + pc_timer_t send_delay_timer; } xtkbd_t; /*XT keyboard has no escape scancodes, and no scancodes beyond 53*/ const scancode scancode_xt[512] = { - { {-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} }, /*054*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*058*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*05c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*060*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*064*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*068*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*06c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*070*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*074*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*078*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*07c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*080*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*084*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*088*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*08c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*090*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*094*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*098*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*09c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0ac*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0bc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0cc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0dc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0ec*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0fc*/ - { {-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*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*110*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*114*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*118*/ - { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*11c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*120*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*124*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*128*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*12c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*130*/ - { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, - { {-1}, {-1} }, { {0x37, -1}, {0xb7, -1} }, /*134*/ - { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*138*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*13c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*140*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*144*/ - { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, - { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*148*/ - { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, - { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*14c*/ - { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, - { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*150*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*154*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*158*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*15c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*160*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*164*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*168*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*16c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*170*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*174*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*148*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*17c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*180*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*184*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*18c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*190*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*194*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*198*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*19c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1ac*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1bc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1cc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1dc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1ec*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} } /*1fc*/ + { {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} }, /*054*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*058*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*05c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*060*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*064*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*068*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*06c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*070*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*074*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*078*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*07c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*080*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*084*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*088*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*08c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*090*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*094*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*098*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*09c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0ac*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0bc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0cc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0dc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0ec*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0fc*/ + { {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*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*110*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*114*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*118*/ + { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, + { {0}, {0} }, { {0}, {0} }, /*11c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*120*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*124*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*128*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*12c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*130*/ + { {0}, {0} }, { {0x35, 0}, {0xb5, 0} }, + { {0}, {0} }, { {0x37, 0}, {0xb7, 0} }, /*134*/ + { {0x38, 0}, {0xb8, 0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*138*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*13c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*140*/ + { {0}, {0} }, { {0}, {0} }, + { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, /*144*/ + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, + { {0}, {0} }, { {0x4b, 0}, {0xcb, 0} }, /*148*/ + { {0}, {0} }, { {0x4d, 0}, {0xcd, 0} }, + { {0}, {0} }, { {0x4f, 0}, {0xcf, 0} }, /*14c*/ + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, + { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, /*150*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*154*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*158*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*15c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*160*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*164*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*168*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*16c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*170*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*174*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*148*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*17c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*180*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*184*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*88*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*18c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*190*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*194*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*198*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*19c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1ac*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1bc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1cc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1dc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1ec*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} } /*1fc*/ }; static uint8_t key_queue[16]; -static int key_queue_start, - key_queue_end; +static int key_queue_start = 0, + key_queue_end = 0; +static int is_t1x00 = 0; + + +#ifdef ENABLE_KEYBOARD_XT_LOG +int keyboard_xt_do_log = ENABLE_KEYBOARD_XT_LOG; + + +static void +kbd_log(const char *fmt, ...) +{ + va_list ap; + + if (keyboard_xt_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define kbd_log(fmt, ...) +#endif static void @@ -330,17 +356,27 @@ kbd_poll(void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; - keyboard_delay += (1000LL * TIMER_USEC); + timer_advance_u64(&kbd->send_delay_timer, 1000 * TIMER_USEC); + + if (!(kbd->pb & 0x40) && (kbd->type != 5)) + return; + + if (kbd->want_irq) { + kbd->want_irq = 0; + kbd->pa = kbd->key_waiting; + kbd->blocked = 1; + picint(2); +#ifdef ENABLE_KEYBOARD_XT_LOG + kbd_log("keyboard_xt : take IRQ\n"); +#endif + } if (key_queue_start != key_queue_end && !kbd->blocked) { - kbd->pa = key_queue[key_queue_start]; - picint(2); -#if ENABLE_KEYBOARD_LOG - pclog("XTkbd: reading %02X from the key queue at %i\n", - kbd->pa, key_queue_start); -#endif + kbd->key_waiting = key_queue[key_queue_start]; + kbd_log("XTkbd: reading %02X from the key queue at %i\n", + kbd->key_waiting, key_queue_start); key_queue_start = (key_queue_start + 1) & 0x0f; - kbd->blocked = 1; + kbd->want_irq = 1; } } @@ -348,11 +384,33 @@ kbd_poll(void *priv) static void kbd_adddata(uint16_t val) { + /* Test for T1000 'Fn' key (Right Alt / Right Ctrl) */ + if (is_t1x00) { + if (keyboard_recv(0xb8) || keyboard_recv(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; -#if ENABLE_KEYBOARD_LOG - pclog("XTkbd: %02X added to key queue at %i\n", - val, key_queue_end); -#endif + kbd_log("XTkbd: %02X added to key queue at %i\n", + val, key_queue_end); key_queue_end = (key_queue_end + 1) & 0x0f; } @@ -410,10 +468,10 @@ kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) } -void +static void kbd_adddata_ex(uint16_t val) { - kbd_adddata_process(val, kbd_adddata); + kbd_adddata_process(val, kbd_adddata); } @@ -422,33 +480,46 @@ kbd_write(uint16_t port, uint8_t val, void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; - if (port != 0x61) return; + switch (port) { + case 0x61: + if (!(kbd->pb & 0x40) && (val & 0x40)) { + key_queue_start = key_queue_end = 0; + kbd->want_irq = 0; + kbd->blocked = 0; + kbd_adddata(0xaa); + } + kbd->pb = val; + ppi.pb = val; - if (!(kbd->pb & 0x40) && (val & 0x40)) { /*Reset keyboard*/ -#if ENABLE_KEYBOARD_LOG - pclog("XTkbd: reset keyboard\n"); + speaker_update(); + if ((kbd->type <= 1) && !(kbd->pb & 0x08)) + speaker_gated = speaker_enable = 1; + else { + speaker_gated = val & 1; + speaker_enable = val & 2; + } + if (speaker_enable) + was_speaker_enable = 1; + pit_ctr_set_gate(&pit->counters[2], val & 1); + + if (val & 0x80) { + kbd->pa = 0; + kbd->blocked = 0; + picintc(2); + } + +#ifdef ENABLE_KEYBOARD_XT_LOG + if (kbd->type <= 1) + kbd_log("Casette motor is %s\n", !(val & 0x08) ? "ON" : "OFF"); +#endif + break; +#ifdef ENABLE_KEYBOARD_XT_LOG + case 0x62: + if (kbd->type <= 1) + kbd_log("Casette IN is %i\n", !!(val & 0x10)); + break; #endif - key_queue_end = key_queue_start; - kbd_adddata(0xaa); } - - if ((kbd->pb & 0x80)==0 && (val & 0x80)!=0) { - kbd->pa = 0; - kbd->blocked = 0; - picintc(2); - } - kbd->pb = val; - ppi.pb = val; - - timer_process(); - timer_update_outstanding(); - - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; - if (speaker_enable) - was_speaker_enable = 1; - pit_set_gate(&pit, 2, val & 1); } @@ -460,14 +531,11 @@ kbd_read(uint16_t port, void *priv) switch (port) { case 0x60: - if ((romset == ROM_IBMPC) && (kbd->pb & 0x80)) { - if (video_is_ega_vga()) - ret = 0x4d; - else if (video_is_mda()) - ret = 0x7d; - else - ret = 0x6d; - } else + if ((kbd->type <= 1) && (kbd->pb & 0x80)) + ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00); + else if (((kbd->type == 2) || (kbd->type == 3)) && (kbd->pb & 0x80)) + ret = 0xff; /* According to Ruud on the PCem forum, this is supposed to return 0xFF on the XT. */ + else ret = kbd->pa; break; @@ -476,39 +544,42 @@ kbd_read(uint16_t port, void *priv) break; case 0x62: - if (romset == ROM_IBMPC) { + if (kbd->type == 0) + ret = 0x00; + else if (kbd->type == 1) { if (kbd->pb & 0x04) ret = ((mem_size-64) / 32) & 0x0f; else ret = ((mem_size-64) / 32) >> 4; } else { - if (kbd->pb & 0x08) { - if (video_is_ega_vga()) - ret = 0x4; - else if (video_is_mda()) - ret = 0x7; - else - ret = 0x6; - } else { + if (kbd->pb & 0x08) + ret = kbd->pd >> 4; + else { /* LaserXT = Always 512k RAM; LaserXT/3 = Bit 0: set = 512k, clear = 256k. */ #if defined(DEV_BRANCH) && defined(USE_LASERXT) - if (romset == ROM_LXT3) - ret = (mem_size == 512) ? 0x0d : 0x0c; + if (kbd->type == 6) + ret = ((mem_size == 512) ? 0x0d : 0x0c) | (hasfpu ? 0x02 : 0x00); else #endif - ret = 0x0d; + ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00); } } ret |= (ppispeakon ? 0x20 : 0); - if (kbd->tandy) + /* This is needed to avoid error 131 (cassette error). + This is serial read: bit 5 = clock, bit 4 = data, cassette header is 256 x 0xff. */ + if (kbd->type <= 1) + ret |= (ppispeakon ? 0x10 : 0); + + if (kbd->type == 5) ret |= (tandy1k_eeprom_read() ? 0x10 : 0); break; - default: - pclog("XTkbd: bad read %04X\n", port); - ret = 0xff; + case 0x63: + if ((kbd->type == 2) || (kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) + ret = kbd->pd; + break; } return(ret); @@ -520,10 +591,13 @@ kbd_reset(void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; + kbd->want_irq = 0; kbd->blocked = 0; kbd->pa = 0x00; kbd->pb = 0x00; + keyboard_scan = 1; + key_queue_start = 0, key_queue_end = 0; } @@ -532,23 +606,106 @@ kbd_reset(void *priv) static void * kbd_init(const device_t *info) { + int i, fdd_count = 0; + xtkbd_t *kbd; kbd = (xtkbd_t *)malloc(sizeof(xtkbd_t)); memset(kbd, 0x00, sizeof(xtkbd_t)); - keyboard_set_table(scancode_xt); - - if (info->local == 1) { - kbd->tandy = 1; - } - - keyboard_scan = 1; - io_sethandler(0x0060, 4, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); keyboard_send = kbd_adddata_ex; - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); + kbd_reset(kbd); + kbd->type = info->local; + + key_queue_start = key_queue_end = 0; + + video_reset(gfxcard); + + if (kbd->type <= 3) { + for (i = 0; i < FDD_NUM; i++) { + if (fdd_get_flags(i)) + fdd_count++; + } + + /* DIP switch readout: bit set = OFF, clear = ON. */ + /* Switches 7, 8 - floppy drives. */ + if (!fdd_count) + kbd->pd = 0x00; + else + kbd->pd = ((fdd_count - 1) << 6) | 0x01; + /* Switches 5, 6 - video. */ + if (video_is_mda()) + kbd->pd |= 0x30; + else if (video_is_cga()) + kbd->pd |= 0x20; /* 0x10 would be 40x25 */ + else + kbd->pd |= 0x00; + /* Switches 3, 4 - memory size. */ + if ((kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) { + switch (mem_size) { + case 256: + kbd->pd |= 0x00; + break; + case 512: + kbd->pd |= 0x04; + break; + case 576: + kbd->pd |= 0x08; + break; + case 640: + default: + kbd->pd |= 0x0c; + break; + } + } else if (kbd->type >= 1) { + switch (mem_size) { + case 64: + kbd->pd |= 0x00; + break; + case 128: + kbd->pd |= 0x04; + break; + case 192: + kbd->pd |= 0x08; + break; + case 256: + default: + kbd->pd |= 0x0c; + break; + } + } else { + switch (mem_size) { + case 16: + kbd->pd |= 0x00; + break; + case 32: + kbd->pd |= 0x04; + break; + case 48: + kbd->pd |= 0x08; + break; + case 64: + default: + kbd->pd |= 0x0c; + break; + } + } + + /* Switch 2 - 8087 FPU. */ + if (hasfpu) + kbd->pd |= 0x02; + + /* Switch 1 - always off. */ + kbd->pd |= 0x01; + } + + timer_add(&kbd->send_delay_timer, kbd_poll, kbd, 1); + + keyboard_set_table(scancode_xt); + + is_t1x00 = (kbd->type == 6); return(kbd); } @@ -560,7 +717,7 @@ kbd_close(void *priv) xtkbd_t *kbd = (xtkbd_t *)priv; /* Stop the timer. */ - keyboard_delay = 0; + timer_disable(&kbd->send_delay_timer); /* Disable scanning. */ keyboard_scan = 0; @@ -574,10 +731,50 @@ kbd_close(void *priv) } +const device_t keyboard_pc_device = { + "IBM PC Keyboard (1981)", + 0, + 0, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_pc82_device = { + "IBM PC Keyboard (1982)", + 0, + 1, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + const device_t keyboard_xt_device = { - "PC/XT Keyboard", + "XT (1982) Keyboard", 0, + 2, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_xt86_device = { + "XT (1986) Keyboard", 0, + 3, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_xt_compaq_device = { + "Compaq Portable Keyboard", + 0, + 4, kbd_init, kbd_close, kbd_reset, @@ -587,9 +784,31 @@ const device_t keyboard_xt_device = { const device_t keyboard_tandy_device = { "Tandy 1000 Keyboard", 0, - 1, + 5, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; + +const device_t keyboard_xt_t1x00_device = { + "Toshiba T1x00 Keyboard", + 0, + 6, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +#if defined(DEV_BRANCH) && defined(USE_LASERXT) +const device_t keyboard_xt_lxt3_device = { + "VTech Laser XT3 Keyboard", + 0, + 7, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; +#endif diff --git a/src/lang/language.h b/src/lang/language.h index 39e3aff6a..7150fbe2d 100644 --- a/src/lang/language.h +++ b/src/lang/language.h @@ -10,7 +10,7 @@ * * NOTE: FIXME: Strings 2176 and 2193 are same. * - * Version: @(#)language.h 1.0.8 2018/05/25 + * Version: @(#)language.h 1.0.10 2018/11/19 * * Author: Fred N. van Kempen, * @@ -24,7 +24,7 @@ #define IDS_STRINGS 2048 // "86Box" #define IDS_2049 2049 // "86Box Error" #define IDS_2050 2050 // "86Box Fatal Error" -#define IDS_2051 2051 // "This will reset 86Box.." +#define IDS_2051 2051 // "This will hard reset the.." #define IDS_2052 2052 // "Use CTRL+ALT+PAGE DOWN.." #define IDS_2053 2053 // "Speed" #define IDS_2054 2054 // "ZIP %i (%03i): %ls" @@ -92,6 +92,11 @@ #define IDS_2116 2116 // "%u MB (CHS: %i, %i, %i)" #define IDS_2117 2117 // "Floppy %i (%s): %ls" #define IDS_2118 2118 // "All floppy images (*.0??;*.." +#define IDS_2119 2119 // "Unable to initialize Free.." +#define IDS_2120 2120 // "Unable to initialize SDL..." +#define IDS_2121 2121 // "Are you sure you want to..." +#define IDS_2122 2122 // "Are you sure you want to..." +#define IDS_2123 2123 // "Unable to initialize Ghostscript..." #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -170,7 +175,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 71 +#define STR_NUM_2048 76 #define STR_NUM_3072 11 #define STR_NUM_4096 18 #define STR_NUM_4352 7 diff --git a/src/lpt.c b/src/lpt.c index fbd048beb..f67eba3cc 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -8,11 +8,13 @@ #include "86box.h" #include "io.h" #include "lpt.h" +#include "pic.h" #include "sound/snd_lpt_dac.h" #include "sound/snd_lpt_dss.h" +#include "printer/prt_devs.h" -char lpt_device_names[3][16]; +lpt_port_t lpt_ports[3]; static const struct @@ -26,186 +28,207 @@ static const struct {"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}, + {"Generic Text Printer", "text_prt", &lpt_prt_text_device}, + {"Generic ESC/P Dot-Matrix", "dot_matrix", &lpt_prt_escp_device}, + {"Generic PostScript Printer", "postscript", &lpt_prt_ps_device}, {"", "", NULL} }; -char *lpt_device_get_name(int id) + +char * +lpt_device_get_name(int id) { - if (strlen((char *) lpt_devices[id].name) == 0) - return NULL; - return (char *) lpt_devices[id].name; -} -char *lpt_device_get_internal_name(int id) -{ - if (strlen((char *) lpt_devices[id].internal_name) == 0) - return NULL; - return (char *) lpt_devices[id].internal_name; + if (strlen((char *) lpt_devices[id].name) == 0) + return NULL; + + return (char *) lpt_devices[id].name; } -static lpt_device_t *lpt_device_ts[3]; -static void *lpt_device_ps[3]; -void lpt_devices_init() +char * +lpt_device_get_internal_name(int id) { - int i = 0; - int c; + if (strlen((char *) lpt_devices[id].internal_name) == 0) + return NULL; + return (char *) lpt_devices[id].internal_name; +} - for (i = 0; i < 3; i++) { - c = 0; - while (strcmp((char *) lpt_devices[c].internal_name, lpt_device_names[i]) && strlen((char *) lpt_devices[c].internal_name) != 0) - c++; +int +lpt_device_get_from_internal_name(char *s) +{ + int c = 0; - if (strlen((char *) lpt_devices[c].internal_name) == 0) - lpt_device_ts[i] = NULL; - else - { - lpt_device_ts[i] = (lpt_device_t *) lpt_devices[c].device; - if (lpt_device_ts[i]) - lpt_device_ps[i] = lpt_device_ts[i]->init(); - } + while (strlen((char *) lpt_devices[c].internal_name) != 0) { + if (strcmp(lpt_devices[c].internal_name, s) == 0) + return c; + c++; + } + + return 0; +} + + +void +lpt_devices_init(void) +{ + int i = 0; + + for (i = 0; i < 3; i++) { + lpt_ports[i].dt = (lpt_device_t *) lpt_devices[lpt_ports[i].device].device; + + if (lpt_ports[i].dt) + lpt_ports[i].priv = lpt_ports[i].dt->init(&lpt_ports[i]); + } +} + + +void +lpt_devices_close(void) +{ + int i = 0; + lpt_port_t *dev; + + for (i = 0; i < 3; i++) { + dev = &lpt_ports[i]; + + if (dev->dt) + dev->dt->close(dev->priv); + + dev->dt = NULL; + } +} + + +void +lpt_write(uint16_t port, uint8_t val, void *priv) +{ + lpt_port_t *dev = (lpt_port_t *) priv; + + switch (port & 3) { + case 0: + if (dev->dt && dev->dt->write_data) + dev->dt->write_data(val, dev->priv); + dev->dat = val; + break; + + case 1: + break; + + case 2: + if (dev->dt && dev->dt->write_ctrl) + dev->dt->write_ctrl(val, dev->priv); + dev->ctrl = val; + dev->enable_irq = val & 0x10; + break; + } +} + + +uint8_t +lpt_read(uint16_t port, void *priv) +{ + uint8_t ret = 0xff; + lpt_port_t *dev = (lpt_port_t *) priv; + + switch (port & 3) { + case 0: + if (dev->dt && dev->dt->read_data) + ret = dev->dt->read_data(dev->priv); + else + ret = dev->dat; + break; + + case 1: + if (dev->dt && dev->dt->read_status) + ret = dev->dt->read_status(dev->priv) | 0x0f; + else + ret = 0xdf; + break; + + case 2: + if (dev->dt && dev->dt->read_ctrl) + ret = (dev->dt->read_ctrl(dev->priv) & 0xef) | dev->enable_irq; + else + ret = 0xe0 | dev->ctrl | dev->enable_irq; + break; + } + + return ret; +} + + +void +lpt_irq(void *priv, int raise) +{ + lpt_port_t *dev = (lpt_port_t *) priv; + + if (dev->enable_irq && (dev->irq != 0xff)) { + if (raise) + picint(1 << dev->irq); + else + picintc(1 << dev->irq); + } +} + + +void +lpt_init(void) +{ + int i; + uint16_t default_ports[3] = { 0x378, 0x278, 0x3bc }; + uint8_t default_irqs[3] = { 7, 5, 7 }; + + for (i = 0; i < 3; i++) { + lpt_ports[i].addr = 0xffff; + lpt_ports[i].irq = 0xff; + lpt_ports[i].enable_irq = 0x10; + + if (lpt_ports[i].enabled) { + lpt_port_init(i, default_ports[i]); + lpt_port_irq(i, default_irqs[i]); } + } } -void lpt_devices_close() -{ - int i = 0; - for (i = 0; i < 3; i++) { - if (lpt_device_ts[i]) - lpt_device_ts[i]->close(lpt_device_ps[i]); - lpt_device_ts[i] = NULL; - } +void +lpt_port_init(int i, uint16_t port) +{ + if (lpt_ports[i].enabled) { + if (lpt_ports[i].addr != 0xffff) + io_removehandler(lpt_ports[i].addr, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]); + if (port != 0xffff) + io_sethandler(port, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]); + lpt_ports[i].addr = port; + } else + lpt_ports[i].addr = 0xffff; } -static uint8_t lpt_dats[3], lpt_ctrls[3]; -void lpt_write(int i, uint16_t port, uint8_t val, void *priv) +void +lpt_port_irq(int i, uint8_t irq) { - switch (port & 3) - { - case 0: - if (lpt_device_ts[i]) - lpt_device_ts[i]->write_data(val, lpt_device_ps[i]); - lpt_dats[i] = val; - break; - case 2: - if (lpt_device_ts[i]) - lpt_device_ts[i]->write_ctrl(val, lpt_device_ps[i]); - lpt_ctrls[i] = val; - break; - } -} -uint8_t lpt_read(int i, uint16_t port, void *priv) -{ - switch (port & 3) - { - case 0: - return lpt_dats[i]; - case 1: - if (lpt_device_ts[i]) - return lpt_device_ts[i]->read_status(lpt_device_ps[i]); - return 0; - case 2: - return lpt_ctrls[i]; - } - return 0xff; + if (lpt_ports[i].enabled) + lpt_ports[i].irq = irq; + else + lpt_ports[i].irq = 0xff; } -void lpt1_write(uint16_t port, uint8_t val, void *priv) + +void +lpt_port_remove(int i) { - lpt_write(0, port, val, priv); + if (lpt_ports[i].enabled && (lpt_ports[i].addr != 0xffff)) { + io_removehandler(lpt_ports[i].addr, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]); + lpt_ports[i].addr = 0xffff; + } } -uint8_t lpt1_read(uint16_t port, void *priv) -{ - return lpt_read(0, port, priv); -} -void lpt2_write(uint16_t port, uint8_t val, void *priv) +void +lpt1_remove_ams(void) { - lpt_write(1, port, val, priv); -} - -uint8_t lpt2_read(uint16_t port, void *priv) -{ - return lpt_read(1, port, priv); -} - -void lpt3_write(uint16_t port, uint8_t val, void *priv) -{ - lpt_write(2, port, val, priv); -} - -uint8_t lpt3_read(uint16_t port, void *priv) -{ - return lpt_read(2, port, priv); -} - -uint16_t lpt_addr[3] = { 0x378, 0x278, 0x3bc }; - -void lpt_init(void) -{ - if (lpt_enabled) - { - 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); - lpt_addr[0] = 0x378; - lpt_addr[1] = 0x278; - } -} - -void lpt1_init(uint16_t port) -{ - if (lpt_enabled) - { - io_sethandler(port, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); - lpt_addr[0] = port; - } -} -void lpt1_remove(void) -{ - if (lpt_enabled) - { - io_removehandler(lpt_addr[0], 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); - } -} -void lpt2_init(uint16_t port) -{ - if (lpt_enabled) - { - io_sethandler(port, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); - lpt_addr[1] = port; - } -} -void lpt2_remove(void) -{ - if (lpt_enabled) - { - io_removehandler(lpt_addr[1], 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); - } -} - -void lpt2_remove_ams(void) -{ - if (lpt_enabled) - { - io_removehandler(0x0379, 0x0002, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); - } -} - -void lpt3_init(uint16_t port) -{ - if (lpt_enabled) - { - io_sethandler(port, 0x0003, lpt3_read, NULL, NULL, lpt3_write, NULL, NULL, NULL); - lpt_addr[2] = port; - } -} -void lpt3_remove(void) -{ - if (lpt_enabled) - { - io_removehandler(lpt_addr[2], 0x0003, lpt3_read, NULL, NULL, lpt3_write, NULL, NULL, NULL); - } + if (lpt_ports[0].enabled) + io_removehandler(lpt_ports[0].addr + 1, 0x0002, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[0]); } diff --git a/src/lpt.h b/src/lpt.h index 7db61930b..c6a95fc4e 100644 --- a/src/lpt.h +++ b/src/lpt.h @@ -1,26 +1,55 @@ -extern void lpt_init(); -extern void lpt1_init(uint16_t port); -extern void lpt1_remove(); -extern void lpt2_init(uint16_t port); -extern void lpt2_remove(); -extern void lpt2_remove_ams(); -extern void lpt3_init(uint16_t port); -extern void lpt3_remove(); - -void lpt_devices_init(); -void lpt_devices_close(); - -char *lpt_device_get_name(int id); -char *lpt_device_get_internal_name(int id); - -extern char lpt_device_names[3][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); + const char *name; + + void * (*init)(void *lpt); + void (*close)(void *p); + void (*write_data)(uint8_t val, void *p); + void (*write_ctrl)(uint8_t val, void *p); + uint8_t (*read_data)(void *p); + uint8_t (*read_status)(void *p); + uint8_t (*read_ctrl)(void *p); } lpt_device_t; + + +extern void lpt_init(void); +extern void lpt_port_init(int i, uint16_t port); +extern void lpt_port_irq(int i, uint8_t irq); +extern void lpt_port_remove(int i); +extern void lpt1_remove_ams(void); + +#define lpt1_init(a) lpt_port_init(0, a); +#define lpt1_irq(a) lpt_port_irq(0, a); +#define lpt1_remove() lpt_port_remove(0); +#define lpt2_init(a) lpt_port_init(1, a); +#define lpt2_irq(a) lpt_port_irq(1, a); +#define lpt2_remove() lpt_port_remove(1); +#define lpt3_init(a) lpt_port_init(2, a); +#define lpt3_irq(a) lpt_port_irq(2, a); +#define lpt3_remove() lpt_port_remove(2); + + +void lpt_devices_init(void); +void lpt_devices_close(void); + + +typedef struct { + uint8_t enabled, irq, + dat, ctrl; + uint16_t addr, pad0; + int device, enable_irq; + lpt_device_t * dt; + void * priv; +} lpt_port_t; + +extern lpt_port_t lpt_ports[3]; + +extern void lpt_write(uint16_t port, uint8_t val, void *priv); +extern uint8_t lpt_read(uint16_t port, void *priv); + +extern void lpt_irq(void *priv, int raise); + +extern char * lpt_device_get_name(int id); +extern char * lpt_device_get_internal_name(int id); + +extern int lpt_device_get_from_internal_name(char *s); diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 62614afee..6a9b56b1c 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -1,1296 +1,2626 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Emulation of the Amstrad series of PC's: PC1512, PC1640 and - * PC200, including their keyboard, mouse and video devices, as - * well as the PC2086 and PC3086 systems. - * - * PC1512: The PC1512 extends CGA with a bit-planar 640x200x16 mode. - * Most CRTC registers are fixed. - * - * The Technical Reference Manual lists the video waitstate - * time as between 12 and 46 cycles. We currently always use - * the lower number. - * - * PC1640: Mostly standard EGA, but with CGA & Hercules emulation. - * - * PC200: 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. - * - * TODO: This module is not complete yet: - * - * PC1512: The BIOS assumes 512K RAM, because I cannot figure out how to - * read the status of the LK4 jumper on the mainboard, which is - * somehow linked to the bus gate array on the NDMACS line... - * - * PC1612: EGA mode does not seem to work in the PC1640; it works fine - * in alpha mode, but in highres ("ECD350") mode, it displays - * some semi-random junk. Video-memory pointer maybe? - * - * Version: @(#)m_amstrad.c 1.0.14 2018/04/29 - * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "../86box.h" -#include "../cpu/cpu.h" -#include "../io.h" -#include "../nmi.h" -#include "../pic.h" -#include "../pit.h" -#include "../ppi.h" -#include "../mem.h" -#include "../rom.h" -#include "../timer.h" -#include "../device.h" -#include "../nvr.h" -#include "../keyboard.h" -#include "../mouse.h" -#include "../game/gameport.h" -#include "../lpt.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../sound/sound.h" -#include "../sound/snd_speaker.h" -#include "../video/video.h" -#include "../video/vid_cga.h" -#include "../video/vid_ega.h" -#include "../video/vid_paradise.h" -#include "machine.h" - - -#define STAT_PARITY 0x80 -#define STAT_RTIMEOUT 0x40 -#define STAT_TTIMEOUT 0x20 -#define STAT_LOCK 0x10 -#define STAT_CD 0x08 -#define STAT_SYSFLAG 0x04 -#define STAT_IFULL 0x02 -#define STAT_OFULL 0x01 - - -typedef struct { - rom_t bios_rom; /* 1640 */ - cga_t cga; /* 1640/200 */ - ega_t ega; /* 1640 */ - uint8_t crtc[32]; - int crtcreg; - int cga_enabled; /* 1640 */ - uint8_t cgacol, - cgamode, - stat; - uint8_t plane_write, /* 1512/200 */ - plane_read, /* 1512/200 */ - border; /* 1512/200 */ - int linepos, - displine; - int sc, vc; - int cgadispon; - int con, coff, - cursoron, - cgablink; - int64_t vsynctime; - int vadj; - uint16_t ma, maback; - int dispon; - int blink; - int64_t dispontime, /* 1512/1640 */ - dispofftime; /* 1512/1640 */ - int64_t vidtime; /* 1512/1640 */ - int firstline, - lastline; - uint8_t *vram; -} amsvid_t; - -typedef struct { - /* Machine stuff. */ - uint8_t dead; - uint8_t stat1, - stat2; - - /* Keyboard stuff. */ - int8_t wantirq; - uint8_t key_waiting; - uint8_t pa; - uint8_t pb; - - /* Mouse stuff. */ - uint8_t mousex, - mousey; - int oldb; - - /* Video stuff. */ - amsvid_t *vid; -} amstrad_t; - - -static uint8_t key_queue[16]; -static int key_queue_start = 0, - key_queue_end = 0; -static uint8_t crtc_mask[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 -}; - - -#ifdef ENABLE_AMSTRAD_LOG -int amstrad_do_log = ENABLE_AMSTRAD_LOG; -#endif - - -static void -amstrad_log(const char *fmt, ...) -{ -#ifdef ENABLE_AMSTRAD_LOG - va_list ap; - - if (amstrad_do_log) - { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - -static void -recalc_timings_1512(amsvid_t *vid) -{ - double _dispontime, _dispofftime, disptime; - - disptime = 128; /*Fixed on PC1512*/ - _dispontime = 80; - _dispofftime = disptime - _dispontime; - _dispontime *= CGACONST; - _dispofftime *= CGACONST; - vid->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - vid->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); -} - - -static void -vid_out_1512(uint16_t addr, uint8_t val, void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - uint8_t old; - - switch (addr) { - case 0x03d4: - vid->crtcreg = val & 31; - return; - - case 0x03d5: - old = vid->crtc[vid->crtcreg]; - vid->crtc[vid->crtcreg] = val & crtc_mask[vid->crtcreg]; - if (old != val) { - if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { - fullchange = changeframecount; - recalc_timings_1512(vid); - } - } - return; - - case 0x03d8: - if ((val & 0x12) == 0x12 && (vid->cgamode & 0x12) != 0x12) { - vid->plane_write = 0xf; - vid->plane_read = 0; - } - vid->cgamode = val; - return; - - case 0x03d9: - vid->cgacol = val; - return; - - case 0x03dd: - vid->plane_write = val; - return; - - case 0x03de: - vid->plane_read = val & 3; - return; - - case 0x03df: - vid->border = val; - return; - } -} - - -static uint8_t -vid_in_1512(uint16_t addr, void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - uint8_t ret = 0xff; - - switch (addr) { - case 0x03d4: - ret = vid->crtcreg; - - case 0x03d5: - ret = vid->crtc[vid->crtcreg]; - - case 0x03da: - ret = vid->stat; - } - - return(ret); -} - - -static void -vid_write_1512(uint32_t addr, uint8_t val, void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - egawrites++; - cycles -= 12; - addr &= 0x3fff; - - if ((vid->cgamode & 0x12) == 0x12) { - if (vid->plane_write & 1) vid->vram[addr] = val; - if (vid->plane_write & 2) vid->vram[addr | 0x4000] = val; - if (vid->plane_write & 4) vid->vram[addr | 0x8000] = val; - if (vid->plane_write & 8) vid->vram[addr | 0xc000] = val; - } else - vid->vram[addr] = val; -} - - -static uint8_t -vid_read_1512(uint32_t addr, void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - egareads++; - cycles -= 12; - addr &= 0x3fff; - - if ((vid->cgamode & 0x12) == 0x12) - return(vid->vram[addr | (vid->plane_read << 14)]); - - return(vid->vram[addr]); -} - - -static void -vid_poll_1512(void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x, c; - uint8_t chr, attr; - uint16_t dat, dat2, dat3, dat4; - int cols[4]; - int col; - int oldsc; - - if (! vid->linepos) { - vid->vidtime += vid->dispofftime; - vid->stat |= 1; - vid->linepos = 1; - oldsc = vid->sc; - if (vid->dispon) { - if (vid->displine < vid->firstline) { - vid->firstline = vid->displine; - video_wait_for_buffer(); - } - vid->lastline = vid->displine; - for (c = 0; c < 8; c++) { - if ((vid->cgamode & 0x12) == 0x12) { - buffer->line[vid->displine][c] = (vid->border & 15) + 16; - if (vid->cgamode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; - else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; - } else { - buffer->line[vid->displine][c] = (vid->cgacol & 15) + 16; - if (vid->cgamode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->cgacol & 15) + 16; - else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->cgacol & 15) + 16; - } - } - if (vid->cgamode & 1) { - for (x = 0; x < 80; x++) { - chr = vid->vram[ ((vid->ma << 1) & 0x3fff)]; - attr = vid->vram[(((vid->ma << 1) + 1) & 0x3fff)]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; - } - if (drawcursor) { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; - } else { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } - vid->ma++; - } - } else if (! (vid->cgamode & 2)) { - for (x = 0; x < 40; x++) { - chr = vid->vram[((vid->ma << 1) & 0x3fff)]; - attr = vid->vram[(((vid->ma << 1) + 1) & 0x3fff)]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; - if ((vid->blink & 16) && (attr & 0x80)) - cols[1] = cols[0]; - } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; - } - vid->ma++; - if (drawcursor) { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; - } else { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } - } - } else if (! (vid->cgamode & 16)) { - cols[0] = (vid->cgacol & 15) | 16; - col = (vid->cgacol & 16) ? 24 : 16; - if (vid->cgamode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; - } else if (vid->cgacol & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; - } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; - } - for (x = 0; x < 40; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 8; c++) { - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; - dat <<= 2; - } - } - } else { - for (x = 0; x < 40; x++) { - ca = ((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000); - dat = (vid->vram[ca] << 8) | vid->vram[ca + 1]; - dat2 = (vid->vram[ca + 0x4000] << 8) | vid->vram[ca + 0x4001]; - dat3 = (vid->vram[ca + 0x8000] << 8) | vid->vram[ca + 0x8001]; - dat4 = (vid->vram[ca + 0xc000] << 8) | vid->vram[ca + 0xc001]; - - vid->ma++; - for (c = 0; c < 16; c++) { - buffer->line[vid->displine][(x << 4) + c + 8] = (((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (vid->cgacol & 15)) + 16; - dat <<= 1; - dat2 <<= 1; - dat3 <<= 1; - dat4 <<= 1; - } - } - } - } else { - cols[0] = ((vid->cgamode & 0x12) == 0x12) ? 0 : (vid->cgacol & 15) + 16; - if (vid->cgamode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); - else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); - } - - vid->sc = oldsc; - if (vid->vsynctime) - vid->stat |= 8; - vid->displine++; - if (vid->displine >= 360) - vid->displine = 0; - } else { - vid->vidtime += vid->dispontime; - if ((vid->lastline - vid->firstline) == 199) - vid->dispon = 0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ - if (vid->dispon) - vid->stat &= ~1; - vid->linepos = 0; - if (vid->vsynctime) { - vid->vsynctime--; - if (! vid->vsynctime) - vid->stat &= ~8; - } - if (vid->sc == (vid->crtc[11] & 31)) { - vid->con = 0; - vid->coff = 1; - } - if (vid->vadj) { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; - vid->vadj--; - if (! vid->vadj) { - vid->dispon = 1; - vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; - vid->sc = 0; - } - } else if (vid->sc == vid->crtc[9]) { - vid->maback = vid->ma; - vid->sc = 0; - vid->vc++; - vid->vc &= 127; - - if (vid->displine == 32) { - vid->vc = 0; - vid->vadj = 6; - if ((vid->crtc[10] & 0x60) == 0x20) - vid->cursoron = 0; - else - vid->cursoron = vid->blink & 16; - } - - if (vid->displine >= 262) { - vid->dispon = 0; - vid->displine = 0; - vid->vsynctime = 46; - - if (vid->cgamode&1) - x = (vid->crtc[1] << 3) + 16; - else - x = (vid->crtc[1] << 4) + 16; - vid->lastline++; - - if ((x != xsize) || ((vid->lastline - vid->firstline) != ysize) || video_force_resize_get()) { - xsize = x; - ysize = vid->lastline - vid->firstline; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, (ysize << 1) + 16); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - - video_blit_memtoscreen_8(0, vid->firstline - 4, 0, (vid->lastline - vid->firstline) + 8, xsize, (vid->lastline - vid->firstline) + 8); - - video_res_x = xsize - 16; - video_res_y = ysize; - if (vid->cgamode & 1) { - video_res_x /= 8; - video_res_y /= vid->crtc[9] + 1; - video_bpp = 0; - } else if (! (vid->cgamode & 2)) { - video_res_x /= 16; - video_res_y /= vid->crtc[9] + 1; - video_bpp = 0; - } else if (! (vid->cgamode & 16)) { - video_res_x /= 2; - video_bpp = 2; - } else { - video_bpp = 4; - } - - vid->firstline = 1000; - vid->lastline = 0; - vid->blink++; - } - } else { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; - } - if (vid->sc == (vid->crtc[10] & 31)) - vid->con = 1; - } -} - - -static void -vid_init_1512(amstrad_t *ams) -{ - amsvid_t *vid; - - /* Allocate a video controller block. */ - vid = (amsvid_t *)malloc(sizeof(amsvid_t)); - memset(vid, 0x00, sizeof(amsvid_t)); - - vid->vram = malloc(0x10000); - vid->cgacol = 7; - vid->cgamode = 0x12; - - timer_add(vid_poll_1512, &vid->vidtime, TIMER_ALWAYS_ENABLED, vid); - mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, - vid_read_1512, NULL, NULL, vid_write_1512, NULL, NULL, - NULL, 0, vid); - io_sethandler(0x03d0, 16, - vid_in_1512, NULL, NULL, vid_out_1512, NULL, NULL, vid); - - overscan_x = overscan_y = 16; - - ams->vid = vid; -} - - -static void -vid_close_1512(void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - free(vid->vram); - - free(vid); -} - - -static void -vid_speed_change_1512(void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - recalc_timings_1512(vid); -} - - -static const device_t vid_1512_device = { - "Amstrad PC1512 (video)", - 0, 0, - NULL, vid_close_1512, NULL, - NULL, - vid_speed_change_1512, - NULL -}; - - -static void -recalc_timings_1640(amsvid_t *vid) -{ - cga_recalctimings(&vid->cga); - ega_recalctimings(&vid->ega); - - if (vid->cga_enabled) { - overscan_x = overscan_y = 16; - - vid->dispontime = vid->cga.dispontime; - vid->dispofftime = vid->cga.dispofftime; - } else { - overscan_x = 16; overscan_y = 28; - - vid->dispontime = vid->ega.dispontime; - vid->dispofftime = vid->ega.dispofftime; - } -} - - -static void -vid_out_1640(uint16_t addr, uint8_t val, void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - switch (addr) { - case 0x03db: - vid->cga_enabled = val & 0x40; - if (vid->cga_enabled) { - mem_mapping_enable(&vid->cga.mapping); - mem_mapping_disable(&vid->ega.mapping); - } else { - mem_mapping_disable(&vid->cga.mapping); - switch (vid->ega.gdcreg[6] & 0xc) { - case 0x0: /*128k at A0000*/ - mem_mapping_set_addr(&vid->ega.mapping, - 0xa0000, 0x20000); - break; - - case 0x4: /*64k at A0000*/ - mem_mapping_set_addr(&vid->ega.mapping, - 0xa0000, 0x10000); - break; - - case 0x8: /*32k at B0000*/ - mem_mapping_set_addr(&vid->ega.mapping, - 0xb0000, 0x08000); - break; - - case 0xC: /*32k at B8000*/ - mem_mapping_set_addr(&vid->ega.mapping, - 0xb8000, 0x08000); - break; - } - } - return; - } - - if (vid->cga_enabled) - cga_out(addr, val, &vid->cga); - else - ega_out(addr, val, &vid->ega); -} - - -static uint8_t -vid_in_1640(uint16_t addr, void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - switch (addr) { - } - - if (vid->cga_enabled) - return(cga_in(addr, &vid->cga)); - else - return(ega_in(addr, &vid->ega)); -} - - -static void -vid_poll_1640(void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - if (vid->cga_enabled) { - overscan_x = overscan_y = 16; - - vid->cga.vidtime = vid->vidtime; - cga_poll(&vid->cga); - vid->vidtime = vid->cga.vidtime; - } else { - overscan_x = 16; overscan_y = 28; - - vid->ega.vidtime = vid->vidtime; - ega_poll(&vid->ega); - vid->vidtime = vid->ega.vidtime; - } -} - - -static void -vid_init_1640(amstrad_t *ams) -{ - amsvid_t *vid; - - /* Allocate a video controller block. */ - vid = (amsvid_t *)malloc(sizeof(amsvid_t)); - memset(vid, 0x00, sizeof(amsvid_t)); - - rom_init(&vid->bios_rom, L"roms/machines/pc1640/40100", - 0xc0000, 0x8000, 0x7fff, 0, 0); - - ega_init(&vid->ega, 9, 0); - vid->cga.vram = vid->ega.vram; - vid->cga_enabled = 1; - cga_init(&vid->cga); - - mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, - cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, &vid->cga); - mem_mapping_add(&vid->ega.mapping, 0, 0, - ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, &vid->ega); - io_sethandler(0x03a0, 64, - vid_in_1640, NULL, NULL, vid_out_1640, NULL, NULL, vid); - - timer_add(vid_poll_1640, &vid->vidtime, TIMER_ALWAYS_ENABLED, vid); - - overscan_x = overscan_y = 16; - - ams->vid = vid; -} - - -static void -vid_close_1640(void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - free(vid->ega.vram); - - free(vid); -} - - -static void -vid_speed_changed_1640(void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - recalc_timings_1640(vid); -} - - -static const device_t vid_1640_device = { - "Amstrad PC1640 (video)", - 0, 0, - NULL, vid_close_1640, NULL, - NULL, - vid_speed_changed_1640, - NULL -}; - - -static void -vid_out_200(uint16_t addr, uint8_t val, void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - cga_t *cga = &vid->cga; - uint8_t old; - - switch (addr) { - case 0x03d5: - if (!(vid->plane_read & 0x40) && cga->crtcreg <= 11) { - if (vid->plane_read & 0x80) - nmi = 1; - - vid->plane_write = 0x20 | (cga->crtcreg & 0x1f); - vid->border = val; - return; - } - old = cga->crtc[cga->crtcreg]; - cga->crtc[cga->crtcreg] = val & crtc_mask[cga->crtcreg]; - if (old != val) { - if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) { - fullchange = changeframecount; - cga_recalctimings(cga); - } - } - return; - - case 0x03d8: - old = cga->cgamode; - cga->cgamode = val; - if ((cga->cgamode ^ old) & 3) - cga_recalctimings(cga); - vid->plane_write |= 0x80; - if (vid->plane_read & 0x80) - nmi = 1; - return; - - case 0x03de: - vid->plane_read = val; - vid->plane_write = 0x1f; - if (val & 0x80) - vid->plane_write |= 0x40; - return; - } - - cga_out(addr, val, cga); -} - - -static uint8_t -vid_in_200(uint16_t addr, void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - cga_t *cga = &vid->cga; - uint8_t ret; - - switch (addr) { - case 0x03d8: - return(cga->cgamode); - - case 0x03dd: - ret = vid->plane_write; - vid->plane_write &= 0x1f; - nmi = 0; - return(ret); - - case 0x03de: - return((vid->plane_read & 0xc7) | 0x10); /*External CGA*/ - - case 0x03df: - return(vid->border); - } - - return(cga_in(addr, cga)); -} - - -static void -vid_init_200(amstrad_t *ams) -{ - amsvid_t *vid; - cga_t *cga; - - /* Allocate a video controller block. */ - vid = (amsvid_t *)malloc(sizeof(amsvid_t)); - memset(vid, 0x00, sizeof(amsvid_t)); - - cga = &vid->cga; - cga->vram = malloc(0x4000); - cga_init(cga); - - mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, - cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); - io_sethandler(0x03d0, 16, - vid_in_200, NULL, NULL, vid_out_200, NULL, NULL, vid); - - timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); - - overscan_x = overscan_y = 16; - - ams->vid = vid; -} - - -static void -vid_close_200(void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - free(vid->cga.vram); - - free(vid); -} - - -static void -vid_speed_changed_200(void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - cga_recalctimings(&vid->cga); -} - - -static const device_t vid_200_device = { - "Amstrad PC200 (video)", - 0, 0, - NULL, vid_close_200, NULL, - NULL, - vid_speed_changed_200, - NULL -}; - - -static void -ms_write(uint16_t addr, uint8_t val, void *priv) -{ - amstrad_t *ams = (amstrad_t *)priv; - - if (addr == 0x78) - ams->mousex = 0; - else - ams->mousey = 0; -} - - -static uint8_t -ms_read(uint16_t addr, void *priv) -{ - amstrad_t *ams = (amstrad_t *)priv; - - if (addr == 0x78) - return(ams->mousex); - - return(ams->mousey); -} - - -static int -ms_poll(int x, int y, int z, int b, void *priv) -{ - amstrad_t *ams = (amstrad_t *)priv; - - ams->mousex += x; - ams->mousey -= y; - - if ((b & 1) && !(ams->oldb & 1)) - keyboard_send(0x7e); - if ((b & 2) && !(ams->oldb & 2)) - keyboard_send(0x7d); - if (!(b & 1) && (ams->oldb & 1)) - keyboard_send(0xfe); - if (!(b & 2) && (ams->oldb & 2)) - keyboard_send(0xfd); - - ams->oldb = b; - - return(0); -} - - -static void -kbd_adddata(uint16_t val) -{ - key_queue[key_queue_end] = val; - amstrad_log("keyboard_amstrad : %02X added to key queue at %i\n", - val, key_queue_end); - key_queue_end = (key_queue_end + 1) & 0xf; -} - - -static void -kbd_adddata_ex(uint16_t val) -{ - kbd_adddata_process(val, kbd_adddata); -} - - -static void -kbd_write(uint16_t port, uint8_t val, void *priv) -{ - amstrad_t *ams = (amstrad_t *)priv; - - amstrad_log("keyboard_amstrad : write %04X %02X %02X\n", port, val, ams->pb); - - switch (port) { - case 0x61: - /* - * PortB - System Control. - * - * 7 Enable Status-1/Disable Keyboard Code on Port A. - * 6 Enable incoming Keyboard Clock. - * 5 Prevent external parity errors from causing NMI. - * 4 Disable parity checking of on-board system Ram. - * 3 Undefined (Not Connected). - * 2 Enable Port C LSB / Disable MSB. (See 1.8.3) - * 1 Speaker Drive. - * 0 8253 GATE 2 (Speaker Modulate). - * - * This register is controlled by BIOS and/or ROS. - */ - amstrad_log("AMSkb: write PB %02x (%02x)\n", val, ams->pb); - if (!(ams->pb & 0x40) && (val & 0x40)) { /*Reset keyboard*/ - amstrad_log("AMSkb: reset keyboard\n"); - kbd_adddata(0xaa); - } - ams->pb = val; - ppi.pb = val; - - timer_process(); - timer_update_outstanding(); - - speaker_update(); - speaker_gated = val & 0x01; - speaker_enable = val & 0x02; - if (speaker_enable) - was_speaker_enable = 1; - pit_set_gate(&pit, 2, val & 0x01); - - if (val & 0x80) { - /* Keyboard enabled, so enable PA reading. */ - ams->pa = 0x00; - } - break; - - case 0x63: - break; - - case 0x64: - ams->stat1 = val; - break; - - case 0x65: - ams->stat2 = val; - break; - - case 0x66: - pc_reset(1); - break; - - default: - amstrad_log("AMSkb: bad keyboard write %04X %02X\n", port, val); - } -} - - -static uint8_t -kbd_read(uint16_t port, void *priv) -{ - amstrad_t *ams = (amstrad_t *)priv; - uint8_t ret = 0xff; - - switch (port) { - case 0x60: - if (ams->pb & 0x80) { - /* - * PortA - System Status 1 - * - * 7 Always 0 (KBD7) - * 6 Second Floppy disk drive installed (KBD6) - * 5 DDM1 - Default Display Mode bit 1 (KBD5) - * 4 DDM0 - Default Display Mode bit 0 (KBD4) - * 3 Always 1 (KBD3) - * 2 Always 1 (KBD2) - * 1 8087 NDP installed (KBD1) - * 0 Always 1 (KBD0) - * - * DDM00 - * 00 unknown, external color? - * 01 Color,alpha,40x25, bright white on black. - * 10 Color,alpha,80x25, bright white on black. - * 11 External Monochrome,80x25. - * - * Following a reset, the hardware selects VDU mode - * 2. The ROS then sets the initial VDU state based - * on the DDM value. - */ - ret = (0x0d | ams->stat1) & 0x7f; - } else { - ret = ams->pa; - if (key_queue_start == key_queue_end) { - ams->wantirq = 0; - } else { - ams->key_waiting = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; - ams->wantirq = 1; - } - } - break; - - case 0x61: - ret = ams->pb; - break; - - case 0x62: - /* - * PortC - System Status 2. - * - * 7 On-board system RAM parity error. - * 6 External parity error (I/OCHCK from expansion bus). - * 5 8253 PIT OUT2 output. - * 4 Undefined (Not Connected). - *------------------------------------------- - * LSB MSB (depends on PB2) - *------------------------------------------- - * 3 RAM3 Undefined - * 2 RAM2 Undefined - * 1 RAM1 Undefined - * 0 RAM0 RAM4 - * - * PC7 is forced to 0 when on-board system RAM parity - * checking is disabled by PB4. - * - * RAM4:0 - * 01110 512K bytes on-board. - * 01111 544K bytes (32K external). - * 10000 576K bytes (64K external). - * 10001 608K bytes (96K external). - * 10010 640K bytes (128K external or fitted on-board). - */ - if (ams->pb & 0x04) - ret = ams->stat2 & 0x0f; - else - ret = ams->stat2 >> 4; - ret |= (ppispeakon ? 0x20 : 0); - if (nmi) - ret |= 0x40; - break; - - default: - amstrad_log("AMDkb: bad keyboard read %04X\n", port); - } - - return(ret); -} - - -static void -kbd_poll(void *priv) -{ - amstrad_t *ams = (amstrad_t *)priv; - - keyboard_delay += (1000 * TIMER_USEC); - - if (ams->wantirq) { - ams->wantirq = 0; - ams->pa = ams->key_waiting; - picint(2); - amstrad_log("keyboard_amstrad : take IRQ\n"); - } - - if (key_queue_start != key_queue_end && !ams->pa) { - ams->key_waiting = key_queue[key_queue_start]; - amstrad_log("Reading %02X from the key queue at %i\n", - ams->key_waiting, key_queue_start); - key_queue_start = (key_queue_start + 1) & 0xf; - ams->wantirq = 1; - } -} - - -static void -ams_write(uint16_t port, uint8_t val, void *priv) -{ - amstrad_t *ams = (amstrad_t *)priv; - - switch (port) { - case 0xdead: - ams->dead = val; - break; - } -} - - -static uint8_t -ams_read(uint16_t port, void *priv) -{ - amstrad_t *ams = (amstrad_t *)priv; - uint8_t ret = 0xff; - - switch (port) { - case 0x0379: /* printer control, also set LK1-3. - * 0 English Language. - * 1 German Language. - * 2 French Language. - * 3 Spanish Language. - * 4 Danish Language. - * 5 Swedish Language. - * 6 Italian Language. - * 7 Diagnostic Mode. - */ - ret = 0x02; /* ENGLISH. no Diags mode */ - break; - - case 0x037a: /* printer status */ - switch(romset) { - case ROM_PC1512: - ret = 0x20; - break; - - case ROM_PC200: - ret = 0x80; - break; - - default: - ret = 0x00; - } - break; - - case 0xdead: - ret = ams->dead; - break; - } - - return(ret); -} - - -void -machine_amstrad_init(const machine_t *model) -{ - amstrad_t *ams; - - ams = (amstrad_t *)malloc(sizeof(amstrad_t)); - memset(ams, 0x00, sizeof(amstrad_t)); - - device_add(&amstrad_nvr_device); - - machine_common_init(model); - - nmi_init(); - - lpt2_remove_ams(); - - io_sethandler(0x0379, 2, - ams_read, NULL, NULL, NULL, NULL, NULL, ams); - - io_sethandler(0xdead, 1, - ams_read, NULL, NULL, ams_write, NULL, NULL, ams); - - io_sethandler(0x0078, 1, - ms_read, NULL, NULL, ms_write, NULL, NULL, ams); - - io_sethandler(0x007a, 1, - ms_read, NULL, NULL, ms_write, NULL, NULL, ams); - -// device_add(&fdc_at_actlow_device); - - switch(romset) { - case ROM_PC1512: - device_add(&fdc_xt_device); - break; - - case ROM_PC1640: - device_add(&fdc_xt_device); - break; - - case ROM_PC200: - device_add(&fdc_xt_device); - break; - - case ROM_PC2086: - device_add(&fdc_at_actlow_device); - break; - - case ROM_PC3086: - device_add(&fdc_at_actlow_device); - break; - - case ROM_MEGAPC: - device_add(&fdc_at_actlow_device); - break; - } - - if (gfxcard == GFX_INTERNAL) switch(romset) { - case ROM_PC1512: - loadfont(L"roms/machines/pc1512/40078", 2); - vid_init_1512(ams); - device_add_ex(&vid_1512_device, ams->vid); - break; - - case ROM_PC1640: - vid_init_1640(ams); - device_add_ex(&vid_1640_device, ams->vid); - break; - - case ROM_PC200: - loadfont(L"roms/machines/pc200/40109.bin", 1); - vid_init_200(ams); - device_add_ex(&vid_200_device, ams->vid); - break; - - case ROM_PC2086: - device_add(¶dise_pvga1a_pc2086_device); - break; - - case ROM_PC3086: - device_add(¶dise_pvga1a_pc3086_device); - break; - - case ROM_MEGAPC: - device_add(¶dise_wd90c11_megapc_device); - break; - } - - /* Initialize the (custom) keyboard/mouse interface. */ - ams->wantirq = 0; - io_sethandler(0x0060, 7, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, ams); - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, ams); - keyboard_set_table(scancode_xt); - keyboard_send = kbd_adddata_ex; - keyboard_scan = 1; - - /* Tell mouse driver about our internal mouse. */ - mouse_reset(); - mouse_set_poll(ms_poll, ams); - - if (joystick_type != 7) - device_add(&gameport_device); -} +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the Amstrad series of PC's: PC1512, PC1640 and + * PC200, including their keyboard, mouse and video devices, as + * well as the PC2086 and PC3086 systems. + * + * PC1512: The PC1512 extends CGA with a bit-planar 640x200x16 mode. + * Most CRTC registers are fixed. + * + * The Technical Reference Manual lists the video waitstate + * time as between 12 and 46 cycles. We currently always use + * the lower number. + * + * PC1640: Mostly standard EGA, but with CGA & Hercules emulation. + * + * PC200: 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. + * + * PPC512/640: Portable with both CGA-compatible and MDA-compatible monitors. + * + * TODO: This module is not complete yet: + * + * All models: The internal mouse controller does not work correctly with + * version 7.04 of the mouse driver. + * + * Version: @(#)m_amstrad.c 1.0.21 2019/11/15 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * John Elliott, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2019 John Elliott. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../io.h" +#include "../nmi.h" +#include "../pic.h" +#include "../pit.h" +#include "../ppi.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../keyboard.h" +#include "../mouse.h" +#include "../game/gameport.h" +#include "../lpt.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../sound/sound.h" +#include "../sound/snd_speaker.h" +#include "../video/video.h" +#include "../video/vid_cga.h" +#include "../video/vid_ega.h" +#include "../video/vid_mda.h" +#include "../video/vid_paradise.h" +#include "machine.h" +#include "m_amstrad.h" + + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + + +typedef struct { + rom_t bios_rom; /* 1640 */ + cga_t cga; /* 1640/200 */ + mda_t mda; /* 1512/200/PPC512/640*/ + ega_t ega; /* 1640 */ + 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, type; + uint8_t crtc[32]; + int crtcreg; + int cga_enabled; /* 1640 */ + uint8_t cgacol, + cgamode, + stat; + uint8_t plane_write, /* 1512/200 */ + plane_read, /* 1512/200 */ + border; /* 1512/200 */ + int fontbase; /* 1512/200 */ + int linepos, + displine; + int sc, vc; + int cgadispon; + int con, coff, + cursoron, + cgablink; + int vsynctime; + int vadj; + uint16_t ma, maback; + int dispon; + int blink; + uint64_t dispontime, /* 1512/1640 */ + dispofftime; /* 1512/1640 */ + pc_timer_t timer; /* 1512/1640 */ + int firstline, + lastline; + uint8_t *vram; + void *ams; +} amsvid_t; + +typedef struct { + /* Machine stuff. */ + uint8_t dead; + uint8_t stat1, + stat2; + uint8_t type, + language; + + /* Keyboard stuff. */ + int8_t wantirq; + uint8_t key_waiting; + uint8_t pa; + uint8_t pb; + pc_timer_t send_delay_timer; + + /* Mouse stuff. */ + uint8_t mousex, + mousey; + int oldb; + + /* Video stuff. */ + amsvid_t *vid; + fdc_t *fdc; +} amstrad_t; + + +int amstrad_latch; + + +static uint8_t key_queue[16]; +static int key_queue_start = 0, + key_queue_end = 0; +static uint8_t crtc_mask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static 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}; + + +enum +{ + AMS_PC1512, + AMS_PC1640, + AMS_PC200, + AMS_PPC512, + AMS_PC2086, + AMS_PC3086 +}; + + +#ifdef ENABLE_AMSTRAD_LOG +int amstrad_do_log = ENABLE_AMSTRAD_LOG; + + +static void +amstrad_log(const char *fmt, ...) +{ + va_list ap; + + if (amstrad_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define amstrad_log(fmt, ...) +#endif + + +static void +recalc_timings_1512(amsvid_t *vid) +{ + double _dispontime, _dispofftime, disptime; + + disptime = /*128*/ 114; /*Fixed on PC1512*/ + _dispontime = 80; + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + vid->dispontime = (uint64_t)_dispontime; + vid->dispofftime = (uint64_t)_dispofftime; +} + + +static void +vid_out_1512(uint16_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + uint8_t old; + + switch (addr) { + case 0x03d4: + vid->crtcreg = val & 31; + return; + + case 0x03d5: + old = vid->crtc[vid->crtcreg]; + vid->crtc[vid->crtcreg] = val & crtc_mask[vid->crtcreg]; + if (old != val) { + if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { + fullchange = changeframecount; + recalc_timings_1512(vid); + } + } + return; + + case 0x03d8: + if ((val & 0x12) == 0x12 && (vid->cgamode & 0x12) != 0x12) { + vid->plane_write = 0xf; + vid->plane_read = 0; + } + vid->cgamode = val; + return; + + case 0x03d9: + vid->cgacol = val; + return; + + case 0x03dd: + vid->plane_write = val; + return; + + case 0x03de: + vid->plane_read = val & 3; + return; + + case 0x03df: + vid->border = val; + return; + } +} + + +static uint8_t +vid_in_1512(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x03d4: + ret = vid->crtcreg; + break; + + case 0x03d5: + ret = vid->crtc[vid->crtcreg]; + break; + + case 0x03da: + ret = vid->stat; + break; + } + + return(ret); +} + + +static void +vid_write_1512(uint32_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + egawrites++; + sub_cycles(12); + addr &= 0x3fff; + + if ((vid->cgamode & 0x12) == 0x12) { + if (vid->plane_write & 1) vid->vram[addr] = val; + if (vid->plane_write & 2) vid->vram[addr | 0x4000] = val; + if (vid->plane_write & 4) vid->vram[addr | 0x8000] = val; + if (vid->plane_write & 8) vid->vram[addr | 0xc000] = val; + } else + vid->vram[addr] = val; +} + + +static uint8_t +vid_read_1512(uint32_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + egareads++; + sub_cycles(12); + addr &= 0x3fff; + + if ((vid->cgamode & 0x12) == 0x12) + return(vid->vram[addr | (vid->plane_read << 14)]); + + return(vid->vram[addr]); +} + + +static void +vid_poll_1512(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c, xs_temp, ys_temp; + uint8_t chr, attr; + uint16_t dat, dat2, dat3, dat4; + int cols[4]; + int col; + int oldsc; + + if (! vid->linepos) { + timer_advance_u64(&vid->timer, vid->dispofftime); + vid->stat |= 1; + vid->linepos = 1; + oldsc = vid->sc; + if (vid->dispon) { + if (vid->displine < vid->firstline) { + vid->firstline = vid->displine; + video_wait_for_buffer(); + } + vid->lastline = vid->displine; + for (c = 0; c < 8; c++) { + if ((vid->cgamode & 0x12) == 0x12) { + buffer32->line[(vid->displine << 1)][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->border & 15) + 16; + if (vid->cgamode & 1) { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 3) + 8] = + buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = 0; + } else { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 4) + 8] = + buffer32->line[(vid->displine << 1)+ 1][c + (vid->crtc[1] << 4) + 8] = 0; + } + } else { + buffer32->line[(vid->displine << 1)][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->cgacol & 15) + 16; + if (vid->cgamode & 1) { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 3) + 8] = + buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = (vid->cgacol & 15) + 16; + } else { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 4) + 8] = + buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = (vid->cgacol & 15) + 16; + } + } + } + if (vid->cgamode & 1) { + for (x = 0; x < 80; x++) { + chr = vid->vram[ ((vid->ma << 1) & 0x3fff)]; + attr = vid->vram[(((vid->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->cgamode & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) { + for (c = 0; c < 8; c++) { + buffer32->line[(vid->displine << 1)][(x << 3) + c + 8] = + buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + } else { + for (c = 0; c < 8; c++) { + buffer32->line[(vid->displine << 1)][(x << 3) + c + 8] = + buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + vid->ma++; + } + } else if (! (vid->cgamode & 2)) { + for (x = 0; x < 40; x++) { + chr = vid->vram[((vid->ma << 1) & 0x3fff)]; + attr = vid->vram[(((vid->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->cgamode & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((vid->blink & 16) && (attr & 0x80)) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + vid->ma++; + if (drawcursor) { + for (c = 0; c < 8; c++) { + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + } else { + for (c = 0; c < 8; c++) { + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + } else if (! (vid->cgamode & 16)) { + cols[0] = (vid->cgacol & 15) | 16; + col = (vid->cgacol & 16) ? 24 : 16; + if (vid->cgamode & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else if (vid->cgacol & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < 40; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 8; c++) { + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[dat >> 14]; + dat <<= 2; + } + } + } else { + for (x = 0; x < 40; x++) { + ca = ((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000); + dat = (vid->vram[ca] << 8) | vid->vram[ca + 1]; + dat2 = (vid->vram[ca + 0x4000] << 8) | vid->vram[ca + 0x4001]; + dat3 = (vid->vram[ca + 0x8000] << 8) | vid->vram[ca + 0x8001]; + dat4 = (vid->vram[ca + 0xc000] << 8) | vid->vram[ca + 0xc001]; + + vid->ma++; + for (c = 0; c < 16; c++) { + buffer32->line[(vid->displine << 1)][(x << 4) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] = + (((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (vid->cgacol & 15)) + 16; + dat <<= 1; + dat2 <<= 1; + dat3 <<= 1; + dat4 <<= 1; + } + } + } + } else { + cols[0] = ((vid->cgamode & 0x12) == 0x12) ? 0 : (vid->cgacol & 15) + 16; + if (vid->cgamode & 1) { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, cols[0]); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, cols[0]); + } else { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, cols[0]); + } + } + + vid->sc = oldsc; + if (vid->vsynctime) + vid->stat |= 8; + vid->displine++; + if (vid->displine >= 360) + vid->displine = 0; + } else { + timer_advance_u64(&vid->timer, vid->dispontime); + if ((vid->lastline - vid->firstline) == 199) + vid->dispon = 0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ + if (vid->dispon) + vid->stat &= ~1; + vid->linepos = 0; + if (vid->vsynctime) { + vid->vsynctime--; + if (! vid->vsynctime) + vid->stat &= ~8; + } + if (vid->sc == (vid->crtc[11] & 31)) { + vid->con = 0; + vid->coff = 1; + } + if (vid->vadj) { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + vid->vadj--; + if (! vid->vadj) { + vid->dispon = 1; + vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + vid->sc = 0; + } + } else if (vid->sc == vid->crtc[9]) { + vid->maback = vid->ma; + vid->sc = 0; + vid->vc++; + vid->vc &= 127; + + if (vid->displine == 32) { + vid->vc = 0; + vid->vadj = 6; + if ((vid->crtc[10] & 0x60) == 0x20) + vid->cursoron = 0; + else + vid->cursoron = vid->blink & 16; + } + + if (vid->displine >= 262) { + vid->dispon = 0; + vid->displine = 0; + vid->vsynctime = 46; + + if (vid->cgamode&1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + vid->lastline++; + + xs_temp = x; + ys_temp = (vid->lastline - vid->firstline) << 1; + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xs_temp < 64) xs_temp = 656; + if (ys_temp < 32) ys_temp = 400; + if (!enable_overscan) + xs_temp -= 16; + + if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan) { + video_blit_memtoscreen_8(0, (vid->firstline - 4) << 1, 0, ((vid->lastline - vid->firstline) + 8) << 1, + xsize, ((vid->lastline - vid->firstline) + 8) << 1); + } else { + video_blit_memtoscreen_8(8, vid->firstline << 1, 0, (vid->lastline - vid->firstline) << 1, + xsize, (vid->lastline - vid->firstline) << 1); + } + } + + video_res_x = xsize; + video_res_y = ysize; + if (vid->cgamode & 1) { + video_res_x /= 8; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->cgamode & 2)) { + video_res_x /= 16; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->cgamode & 16)) { + video_res_x /= 2; + video_bpp = 2; + } else { + video_bpp = 4; + } + + vid->firstline = 1000; + vid->lastline = 0; + vid->blink++; + } + } else { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + } + if (vid->sc == (vid->crtc[10] & 31)) + vid->con = 1; + } +} + + +static void +vid_init_1512(amstrad_t *ams) +{ + amsvid_t *vid; + + /* Allocate a video controller block. */ + vid = (amsvid_t *)malloc(sizeof(amsvid_t)); + memset(vid, 0x00, sizeof(amsvid_t)); + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_pc1512); + + vid->vram = malloc(0x10000); + vid->cgacol = 7; + vid->cgamode = 0x12; + + timer_add(&vid->timer, vid_poll_1512, vid, 1); + mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, + vid_read_1512, NULL, NULL, vid_write_1512, NULL, NULL, + NULL, 0, vid); + io_sethandler(0x03d0, 16, + vid_in_1512, NULL, NULL, vid_out_1512, NULL, NULL, vid); + + overscan_x = overscan_y = 16; + + vid->fontbase = (device_get_config_int("codepage") & 3) * 256; + + cga_palette = (device_get_config_int("display_type") << 1); + cgapal_rebuild(); + + ams->vid = vid; +} + + +static void +vid_close_1512(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + free(vid->vram); + + free(vid); +} + + +static void +vid_speed_change_1512(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + recalc_timings_1512(vid); +} + + +device_config_t vid_1512_config[] = +{ + { + "display_type", "Display type", CONFIG_SELECTION, "", 0, + { + { + "PC-CM (Colour)", 0 + }, + { + "PC-MM (Monochrome)", 3 + }, + { + "" + } + } + }, + { + "codepage", "Hardware font", CONFIG_SELECTION, "", 3, + { + { + "US English", 3 + }, + { + "Danish", 1 + }, + { + "Greek", 0 + }, + { + "" + } + } + }, + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "German", 6 + }, + { + "French", 5 + }, + { + "Spanish", 4 + }, + { + "Danish", 3 + }, + { + "Swedish", 2 + }, + { + "Italian", 1 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_t vid_1512_device = { + "Amstrad PC1512 (video)", + 0, 0, + NULL, vid_close_1512, NULL, + NULL, + vid_speed_change_1512, + NULL, + vid_1512_config +}; + + +const device_t * +pc1512_get_device(void) +{ + return(&vid_1512_device); +} + + +static void +recalc_timings_1640(amsvid_t *vid) +{ + cga_recalctimings(&vid->cga); + ega_recalctimings(&vid->ega); + + if (vid->cga_enabled) { + overscan_x = overscan_y = 16; + + vid->dispontime = vid->cga.dispontime; + vid->dispofftime = vid->cga.dispofftime; + } else { + overscan_x = 16; overscan_y = 28; + + vid->dispontime = vid->ega.dispontime; + vid->dispofftime = vid->ega.dispofftime; + } +} + + +static void +vid_out_1640(uint16_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + switch (addr) { + case 0x03db: + vid->cga_enabled = val & 0x40; + if (vid->cga_enabled) { + timer_disable(&vid->ega.timer); + timer_set_delay_u64(&vid->cga.timer, 0); + mem_mapping_enable(&vid->cga.mapping); + mem_mapping_disable(&vid->ega.mapping); + } else { + timer_disable(&vid->cga.timer); + timer_set_delay_u64(&vid->ega.timer, 0); + mem_mapping_disable(&vid->cga.mapping); + switch (vid->ega.gdcreg[6] & 0xc) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xa0000, 0x20000); + break; + + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xa0000, 0x10000); + break; + + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xb0000, 0x08000); + break; + + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xb8000, 0x08000); + break; + } + } + return; + } + + if (vid->cga_enabled) + cga_out(addr, val, &vid->cga); + else + ega_out(addr, val, &vid->ega); +} + + +static uint8_t +vid_in_1640(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + if (vid->cga_enabled) + return(cga_in(addr, &vid->cga)); + else + return(ega_in(addr, &vid->ega)); +} + + +static void +vid_init_1640(amstrad_t *ams) +{ + amsvid_t *vid; + + /* Allocate a video controller block. */ + vid = (amsvid_t *)malloc(sizeof(amsvid_t)); + memset(vid, 0x00, sizeof(amsvid_t)); + + rom_init(&vid->bios_rom, L"roms/machines/pc1640/40100", + 0xc0000, 0x8000, 0x7fff, 0, 0); + + ega_init(&vid->ega, 9, 0); + vid->cga.vram = vid->ega.vram; + vid->cga_enabled = 1; + cga_init(&vid->cga); + timer_disable(&vid->ega.timer); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_pc1640); + + mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, + cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, &vid->cga); + mem_mapping_add(&vid->ega.mapping, 0, 0, + ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, &vid->ega); + io_sethandler(0x03a0, 64, + vid_in_1640, NULL, NULL, vid_out_1640, NULL, NULL, vid); + + overscan_x = overscan_y = 16; + + vid->fontbase = 768; + + cga_palette = 0; + cgapal_rebuild(); + + ams->vid = vid; +} + + +static void +vid_close_1640(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + free(vid->ega.vram); + + free(vid); +} + + +static void +vid_speed_changed_1640(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + recalc_timings_1640(vid); +} + + +device_config_t vid_1640_config[] = +{ + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "German", 6 + }, + { + "French", 5 + }, + { + "Spanish", 4 + }, + { + "Danish", 3 + }, + { + "Swedish", 2 + }, + { + "Italian", 1 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_t vid_1640_device = { + "Amstrad PC1640 (video)", + 0, 0, + NULL, vid_close_1640, NULL, + NULL, + vid_speed_changed_1640, + NULL, + vid_1640_config +}; + +const device_t * +pc1640_get_device(void) +{ + return(&vid_1640_device); +} + +/* 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*/ + +extern int nmi_mask; + +static uint32_t blue, green; + +static uint32_t lcdcols[256][2][2]; + + +static void +ams_inform(amsvid_t *vid) +{ + switch (vid->emulation) { + case PC200_CGA: + case PC200_TV: + case PC200_LCDC: + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_pc200); + break; + case PC200_MDA: + case PC200_LCDM: + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_pc200); + break; + } +} + + +static void +vid_speed_changed_200(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + cga_recalctimings(&vid->cga); + mda_recalctimings(&vid->mda); +} + + +/* 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; + } + } +} + + +static uint8_t +vid_in_200(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + cga_t *cga = &vid->cga; + mda_t *mda = &vid->mda; + uint8_t ret; + + switch (addr) { + case 0x03b8: + return(mda->ctrl); + + case 0x03d8: + return(cga->cgamode); + + case 0x03dd: + ret = vid->crtc_index; /* Read NMI reason */ + vid->crtc_index &= 0x1f; /* Reset NMI reason */ + nmi = 0; /* And reset NMI flag */ + return(ret); + + case 0x03de: + return((vid->operation_ctrl & 0xc7) | vid->dipswitches); /*External CGA*/ + + case 0x03df: + return(vid->reg_3df); + } + + if (addr >= 0x3D0 && addr <= 0x3DF) + return cga_in(addr, cga); + + if (addr >= 0x3B0 && addr <= 0x3BB) + return mda_in(addr, mda); + + return 0xFF; +} + + +static void +vid_out_200(uint16_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + cga_t *cga = &vid->cga; + mda_t *mda = &vid->mda; + uint8_t old; + + switch (addr) { +/* MDA writes ============================================================== */ + case 0x3b1: + case 0x3b3: + case 0x3b5: + case 0x3b7: + /* Writes banned to CRTC registers 0-11? */ + if (!(vid->operation_ctrl & 0x40) && mda->crtcreg <= 11) { + vid->crtc_index = 0x20 | (mda->crtcreg & 0x1f); + if (vid->operation_ctrl & 0x80) + nmi = 1; + vid->reg_3df = val; + return; + } + old = mda->crtc[mda->crtcreg]; + mda->crtc[mda->crtcreg] = val & crtc_mask[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); + vid->crtc_index &= 0x1F; + vid->crtc_index |= 0x80; + if (vid->operation_ctrl & 0x80) + nmi = 1; + return; + +/* CGA writes ============================================================== */ + case 0x03d1: + case 0x03d3: + case 0x03d5: + case 0x03d7: + if (!(vid->operation_ctrl & 0x40) && cga->crtcreg <= 11) { + vid->crtc_index = 0x20 | (cga->crtcreg & 0x1f); + if (vid->operation_ctrl & 0x80) + nmi = 1; + vid->reg_3df = val; + return; + } + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtc_mask[cga->crtcreg]; + if (old != val) { + if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + + case 0x03d8: + old = cga->cgamode; + cga->cgamode = val; + if ((cga->cgamode ^ old) & 3) + cga_recalctimings(cga); + vid->crtc_index &= 0x1f; + vid->crtc_index |= 0x80; + if (vid->operation_ctrl & 0x80) + nmi = 1; + else + set_lcd_cols(val); + return; + +/* PC200 control port writes ============================================== */ + case 0x03de: + vid->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) { + vid->operation_ctrl = val; + vid->crtc_index |= 0x40; + nmi = 1; + return; + } + timer_disable(&vid->cga.timer); + timer_disable(&vid->mda.timer); + timer_disable(&vid->timer); + vid->operation_ctrl = val; + /* Bits 0 and 1 control emulation and output mode */ + amstrad_log("emulation and mode = %02X\n", val & 0x03); + if (val & 1) /* Monitor */ + vid->emulation = (val & 2) ? PC200_MDA : PC200_CGA; + else if (vid->type == AMS_PPC512) + vid->emulation = (val & 2) ? PC200_LCDM : PC200_LCDC; + else + vid->emulation = PC200_TV; + if (vid->emulation == PC200_CGA || vid->emulation == PC200_TV) + timer_advance_u64(&vid->cga.timer, 1); + else if (vid->emulation == PC200_MDA) + timer_advance_u64(&vid->mda.timer, 1); + else + timer_advance_u64(&vid->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 (vid->emulation == PC200_MDA || + vid->emulation == PC200_LCDM) { + mem_mapping_disable(&vid->cga.mapping); + mem_mapping_enable(&vid->mda.mapping); + } + else { + mem_mapping_disable(&vid->mda.mapping); + mem_mapping_enable(&vid->cga.mapping); + } + return; + } + + if (addr >= 0x3D0 && addr <= 0x3DF) + cga_out(addr, val, cga); + + if (addr >= 0x3B0 && addr <= 0x3BB) + mda_out(addr, val, mda); +} + + +static void +lcd_draw_char_80(amsvid_t *vid, 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 + vid->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]; + } +} + + +static void +lcd_draw_char_40(amsvid_t *vid, 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 + vid->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]; + } + } +} + + +static void +lcdm_poll(amsvid_t *vid) +{ + mda_t *mda = &vid->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(&vid->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; + 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(vid, &((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; + mda->displine++; + if (mda->displine >= 500) + mda->displine=0; + } else { + timer_advance_u64(&vid->timer, mda->dispontime); + if (mda->dispon) mda->stat&=~1; + mda->linepos=0; + if (mda->vsynctime) { + mda->vsynctime--; + if (!mda->vsynctime) + mda->stat&=~8; + } + 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]) { + 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]) { + x = mda->crtc[1] * 8; + mda->lastline++; + if ((x != xsize) || ((mda->lastline - mda->firstline) != ysize) || video_force_resize_get()) { + xsize = x; + ysize = mda->lastline - mda->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + 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; + } +} + + +static void +lcdc_poll(amsvid_t *vid) +{ + cga_t *cga = &vid->cga; + int drawcursor; + int x, c, xs_temp, ys_temp; + 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(&vid->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(); + } + 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(vid, &(buffer32->line[(cga->displine << 1)])[x * 8], chr, attr, drawcursor, blink, cga->sc, cga->cgamode & 0x40, cga->cgamode); + lcd_draw_char_80(vid, &(buffer32->line[(cga->displine << 1) + 1])[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(vid, &(buffer32->line[(cga->displine << 1)])[x * 16], chr, attr, drawcursor, blink, cga->sc, cga->cgamode); + lcd_draw_char_40(vid, &(buffer32->line[(cga->displine << 1) + 1])[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++) { + buffer32->line[(cga->displine << 1)][(x << 4) + c] = buffer32->line[(cga->displine << 1) + 1][(x << 4) + c] = + (dat & 0x8000) ? blue : green; + dat <<= 1; + } + } + } + } else { + if (cga->cgamode & 1) { + hline(buffer32, 0, (cga->displine << 1), (cga->crtc[1] << 3), green); + hline(buffer32, 0, (cga->displine << 1) + 1, (cga->crtc[1] << 3), green); + } else { + hline(buffer32, 0, (cga->displine << 1), (cga->crtc[1] << 4), green); + hline(buffer32, 0, (cga->displine << 1) + 1, (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(&vid->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++; + + xs_temp = x; + ys_temp = (cga->lastline - cga->firstline) << 1; + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xs_temp < 64) xs_temp = 640; + if (ys_temp < 32) ys_temp = 400; + + if ((cga->cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + video_blit_memtoscreen(0, cga->firstline << 1, 0, (cga->lastline - cga->firstline) << 1, + xsize, (cga->lastline - cga->firstline) << 1); + } + + frames++; + + video_res_x = xsize; + 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)]; + } + } +} + + +static void +vid_poll_200(void *p) +{ + amsvid_t *vid = (amsvid_t *)p; + + switch (vid->emulation) { + case PC200_LCDM: + lcdm_poll(vid); + return; + case PC200_LCDC: + lcdc_poll(vid); + return; + } +} + + +static void +vid_init_200(amstrad_t *ams) +{ + amsvid_t *vid; + cga_t *cga; + mda_t *mda; + + /* Allocate a video controller block. */ + vid = (amsvid_t *)malloc(sizeof(amsvid_t)); + memset(vid, 0x00, sizeof(amsvid_t)); + + vid->emulation = device_get_config_int("video_emulation"); + cga_palette = (device_get_config_int("display_type") << 1); + ams_inform(vid); + + /* Default to CGA */ + vid->dipswitches = 0x10; + vid->type = ams->type; + + if (ams->type == AMS_PC200) switch (vid->emulation) { + /* DIP switches for PC200. Switches 2,3 give video emulation. + * Switch 1 is 'swap floppy drives' (not implemented) */ + case PC200_CGA: vid->dipswitches = 0x10; break; + case PC200_MDA: vid->dipswitches = 0x30; break; + case PC200_TV: vid->dipswitches = 0x00; break; + /* The other combination is 'IDA disabled' (0x20) - see + * m_amstrad.c */ + } else switch (vid->emulation) { + /* DIP switches for PPC512. Switch 1 is CRT/LCD. Switch 2 + * is MDA / CGA. Switch 3 disables IDA, not implemented. */ + /* 1 = on, 0 = off + SW1: off = crt, on = lcd; + SW2: off = mda, on = cga; + SW3: off = disable built-in card, on = enable */ + case PC200_CGA: vid->dipswitches = 0x08; break; + case PC200_MDA: vid->dipswitches = 0x18; break; + case PC200_LCDC: vid->dipswitches = 0x00; break; + case PC200_LCDM: vid->dipswitches = 0x10; break; + } + + cga = &vid->cga; + mda = &vid->mda; + cga->vram = mda->vram = malloc(0x4000); + cga_init(cga); + mda_init(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); + + cga->fontbase = (device_get_config_int("codepage") & 3) * 256; + + timer_add(&vid->timer, vid_poll_200, vid, 1); + mem_mapping_add(&vid->mda.mapping, 0xb0000, 0x08000, + mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, 0, mda); + mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, + cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + io_sethandler(0x03d0, 16, vid_in_200, NULL, NULL, vid_out_200, NULL, NULL, vid); + io_sethandler(0x03b0, 0x000c, vid_in_200, NULL, NULL, vid_out_200, NULL, NULL, vid); + + overscan_x = overscan_y = 16; + + green = makecol(0x1C, 0x71, 0x31); + blue = makecol(0x0f, 0x21, 0x3f); + cgapal_rebuild(); + set_lcd_cols(0); + + timer_disable(&vid->cga.timer); + timer_disable(&vid->mda.timer); + timer_disable(&vid->timer); + if (vid->emulation == PC200_CGA || vid->emulation == PC200_TV) + timer_enable(&vid->cga.timer); + else if (vid->emulation == PC200_MDA) + timer_enable(&vid->mda.timer); + else + timer_enable(&vid->timer); + + ams->vid = vid; +} + + +static void +vid_close_200(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + free(vid->cga.vram); + free(vid->mda.vram); + + free(vid); +} + + +device_config_t vid_200_config[] = +{ + /* TODO: Should have options here for: + * + * > Display port (TTL or RF) + */ + { + "video_emulation", "Display type", CONFIG_SELECTION, "", PC200_CGA, + { + { + "CGA monitor", PC200_CGA + }, + { + "MDA monitor", PC200_MDA + }, + { + "Television", PC200_TV + }, + { + "" + } + } + }, + { + "display_type", "Monitor type", CONFIG_SELECTION, "", 0, + { + { + "RGB", 0 + }, + { + "RGB (no brown)", 4 + }, + { + "Green Monochrome", 1 + }, + { + "Amber Monochrome", 2 + }, + { + "White Monochrome", 3 + }, + { + "" + } + } + }, + { + "codepage", "Hardware font", CONFIG_SELECTION, "", 3, + { + { + "US English", 3 + }, + { + "Portugese", 2 + }, + { + "Norwegian", 1 + }, + { + "Greek", 0 + }, + { + "" + } + } + }, + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "German", 6 + }, + { + "French", 5 + }, + { + "Spanish", 4 + }, + { + "Danish", 3 + }, + { + "Swedish", 2 + }, + { + "Italian", 1 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_t vid_200_device = { + "Amstrad PC200 (video)", + 0, 0, + NULL, vid_close_200, NULL, + NULL, + vid_speed_changed_200, + NULL, + vid_200_config +}; + + +const device_t * +pc200_get_device(void) +{ + return(&vid_200_device); +} + + +device_config_t vid_ppc512_config[] = +{ + /* TODO: Should have options here for: + * + * > Display port (TTL or RF) + */ + { + "video_emulation", "Display type", CONFIG_SELECTION, "", PC200_LCDC, + { + { + "CGA monitor", PC200_CGA + }, + { + "MDA monitor", PC200_MDA + }, + { + "LCD (CGA mode)", PC200_LCDC + }, + { + "LCD (MDA mode)", PC200_LCDM + }, + { + "" + } + }, + }, + { + "display_type", "Monitor type", CONFIG_SELECTION, "", 0, + { + { + "RGB", 0 + }, + { + "RGB (no brown)", 4 + }, + { + "Green Monochrome", 1 + }, + { + "Amber Monochrome", 2 + }, + { + "White Monochrome", 3 + }, + { + "" + } + }, + }, + { + "codepage", "Hardware font", CONFIG_SELECTION, "", 3, + { + { + "US English", 3 + }, + { + "Portugese", 2 + }, + { + "Norwegian",1 + }, + { + "Greek", 0 + }, + { + "" + } + }, + }, + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "German", 6 + }, + { + "French", 5 + }, + { + "Spanish", 4 + }, + { + "Danish", 3 + }, + { + "Swedish", 2 + }, + { + "Italian", 1 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_t vid_ppc512_device = { + "Amstrad PPC512 (video)", + 0, 0, + NULL, vid_close_200, NULL, + NULL, + vid_speed_changed_200, + NULL, + vid_ppc512_config +}; + + +const device_t * +ppc512_get_device(void) +{ + return(&vid_ppc512_device); +} + + +device_config_t vid_pc2086_config[] = +{ + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_t vid_pc2086_device = { + "Amstrad PC2086", + 0, 0, + NULL, NULL, NULL, + NULL, + NULL, + NULL, + vid_pc2086_config +}; + + +const device_t * +pc2086_get_device(void) +{ + return(&vid_pc2086_device); +} + + +device_config_t vid_pc3086_config[] = +{ + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "Diagnostic mode", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_t vid_pc3086_device = { + "Amstrad PC3086", + 0, 0, + NULL, NULL, NULL, + NULL, + NULL, + NULL, + vid_pc3086_config +}; + + +const device_t * +pc3086_get_device(void) +{ + return(&vid_pc3086_device); +} + + +static void +ms_write(uint16_t addr, uint8_t val, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + if ((addr == 0x78) || (addr == 0x79)) + ams->mousex = 0; + else + ams->mousey = 0; +} + + +static uint8_t +ms_read(uint16_t addr, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + uint8_t ret; + + if ((addr == 0x78) || (addr == 0x79)) { + ret = ams->mousex; + ams->mousex = 0; + } else { + ret = ams->mousey; + ams->mousey = 0; + } + + return(ret); +} + + +static int +ms_poll(int x, int y, int z, int b, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + ams->mousex += x; + ams->mousey -= y; + + if ((b & 1) && !(ams->oldb & 1)) + keyboard_send(0x7e); + if (!(b & 1) && (ams->oldb & 1)) + keyboard_send(0xfe); + + if ((b & 2) && !(ams->oldb & 2)) + keyboard_send(0x7d); + if (!(b & 2) && (ams->oldb & 2)) + keyboard_send(0xfd); + + ams->oldb = b; + + return(0); +} + + +static void +kbd_adddata(uint16_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; +} + + +static void +kbd_adddata_ex(uint16_t val) +{ + kbd_adddata(val); + // kbd_adddata_process(val, kbd_adddata); +} + + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + amstrad_log("keyboard_amstrad : write %04X %02X %02X\n", port, val, ams->pb); + + switch (port) { + case 0x61: + /* + * PortB - System Control. + * + * 7 Enable Status-1/Disable Keyboard Code on Port A. + * 6 Enable incoming Keyboard Clock. + * 5 Prevent external parity errors from causing NMI. + * 4 Disable parity checking of on-board system Ram. + * 3 Undefined (Not Connected). + * 2 Enable Port C LSB / Disable MSB. (See 1.8.3) + * 1 Speaker Drive. + * 0 8253 GATE 2 (Speaker Modulate). + * + * This register is controlled by BIOS and/or ROS. + */ + amstrad_log("AMSkb: write PB %02x (%02x)\n", val, ams->pb); + if (!(ams->pb & 0x40) && (val & 0x40)) { /*Reset keyboard*/ + amstrad_log("AMSkb: reset keyboard\n"); + kbd_adddata(0xaa); + } + ams->pb = val; + ppi.pb = val; + + speaker_update(); + speaker_gated = val & 0x01; + speaker_enable = val & 0x02; + if (speaker_enable) + was_speaker_enable = 1; + pit_ctr_set_gate(&pit->counters[2], val & 0x01); + + if (val & 0x80) { + /* Keyboard enabled, so enable PA reading. */ + ams->pa = 0x00; + } + break; + + case 0x63: + break; + + case 0x64: + ams->stat1 = val; + break; + + case 0x65: + ams->stat2 = val; + break; + + case 0x66: + softresetx86(); + cpu_set_edx(); + break; + + default: + amstrad_log("AMSkb: bad keyboard write %04X %02X\n", port, val); + } +} + + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x60: + if (ams->pb & 0x80) { + /* + * PortA - System Status 1 + * + * 7 Always 0 (KBD7) + * 6 Second Floppy disk drive installed (KBD6) + * 5 DDM1 - Default Display Mode bit 1 (KBD5) + * 4 DDM0 - Default Display Mode bit 0 (KBD4) + * 3 Always 1 (KBD3) + * 2 Always 1 (KBD2) + * 1 8087 NDP installed (KBD1) + * 0 Always 1 (KBD0) + * + * DDM00 + * 00 unknown, external color? + * 01 Color,alpha,40x25, bright white on black. + * 10 Color,alpha,80x25, bright white on black. + * 11 External Monochrome,80x25. + * + * Following a reset, the hardware selects VDU mode + * 2. The ROS then sets the initial VDU state based + * on the DDM value. + */ + ret = (ams->stat1 | 0x0d) & 0x7f; + } else { + ret = ams->pa; + if (key_queue_start == key_queue_end) + ams->wantirq = 0; + else { + ams->key_waiting = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + ams->wantirq = 1; + } + } + break; + + case 0x61: + ret = ams->pb; + break; + + case 0x62: + /* + * PortC - System Status 2. + * + * 7 On-board system RAM parity error. + * 6 External parity error (I/OCHCK from expansion bus). + * 5 8253 PIT OUT2 output. + * 4 Undefined (Not Connected). + *------------------------------------------- + * LSB MSB (depends on PB2) + *------------------------------------------- + * 3 RAM3 Undefined + * 2 RAM2 Undefined + * 1 RAM1 Undefined + * 0 RAM0 RAM4 + * + * PC7 is forced to 0 when on-board system RAM parity + * checking is disabled by PB4. + * + * RAM4:0 + * 01110 512K bytes on-board. + * 01111 544K bytes (32K external). + * 10000 576K bytes (64K external). + * 10001 608K bytes (96K external). + * 10010 640K bytes (128K external or fitted on-board). + */ + if (ams->pb & 0x04) + ret = ams->stat2 & 0x0f; + else + ret = ams->stat2 >> 4; + ret |= (ppispeakon ? 0x20 : 0); + if (nmi) + ret |= 0x40; + break; + + default: + amstrad_log("AMDkb: bad keyboard read %04X\n", port); + } + + return(ret); +} + + +static void +kbd_poll(void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + timer_advance_u64(&ams->send_delay_timer, 1000 * TIMER_USEC); + + if (ams->wantirq) { + ams->wantirq = 0; + ams->pa = ams->key_waiting; + picint(2); + } + + if (key_queue_start != key_queue_end && !ams->pa) { + ams->key_waiting = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0x0f; + ams->wantirq = 1; + } +} + + +static void +ams_write(uint16_t port, uint8_t val, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + switch (port) { + case 0x0378: + case 0x0379: + case 0x037a: + lpt_write(port, val, &lpt_ports[0]); + break; + + case 0xdead: + ams->dead = val; + break; + } +} + + +static uint8_t +ams_read(uint16_t port, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x0378: + ret = lpt_read(port, &lpt_ports[0]); + break; + + case 0x0379: /* printer control, also set LK1-3. + * per John Elliott's site, this is xor'ed with 0x07 + * 7 English Language. + * 6 German Language. + * 5 French Language. + * 4 Spanish Language. + * 3 Danish Language. + * 2 Swedish Language. + * 1 Italian Language. + * 0 Diagnostic Mode. + */ + ret = (lpt_read(port, &lpt_ports[0]) & 0xf8) | ams->language; + break; + + case 0x037a: /* printer status */ + ret = lpt_read(port, &lpt_ports[0]) & 0x1f; + + switch(ams->type) { + case AMS_PC1512: + ret |= 0x20; + break; + + case AMS_PC200: + case AMS_PPC512: + if (video_is_cga()) + ret |= 0x80; + else if (video_is_mda()) + ret |= 0xc0; + + if (fdc_read(0x037f, ams->fdc) & 0x80) + ret |= 0x20; + break; + + case AMS_PC1640: + if (video_is_cga()) + ret |= 0x80; + else if (video_is_mda()) + ret |= 0xc0; + + switch (amstrad_latch) { + case AMSTRAD_NOLATCH: + ret &= ~0x20; + break; + case AMSTRAD_SW9: + ret &= ~0x20; + break; + case AMSTRAD_SW10: + ret |= 0x20; + break; + } + break; + + default: + break; + } + break; + + case 0x03de: + ret = 0x20; + break; + + case 0xdead: + ret = ams->dead; + break; + } + + return(ret); +} + + +static void +machine_amstrad_init(const machine_t *model, int type) +{ + amstrad_t *ams; + + ams = (amstrad_t *)malloc(sizeof(amstrad_t)); + memset(ams, 0x00, sizeof(amstrad_t)); + ams->type = type; + + device_add(&amstrad_nvr_device); + + machine_common_init(model); + + nmi_init(); + + lpt1_remove_ams(); + lpt2_remove(); + + io_sethandler(0x0378, 3, + ams_read, NULL, NULL, ams_write, NULL, NULL, ams); + io_sethandler(0xdead, 1, + ams_read, NULL, NULL, ams_write, NULL, NULL, ams); + + switch(type) { + case AMS_PC1512: + case AMS_PC1640: + case AMS_PC200: + case AMS_PPC512: + ams->fdc = device_add(&fdc_xt_device); + break; + + case AMS_PC2086: + case AMS_PC3086: + ams->fdc = device_add(&fdc_at_actlow_device); + break; + } + + ams->language = 7; + + if (gfxcard == VID_INTERNAL) switch(type) { + case AMS_PC1512: + loadfont(L"roms/machines/pc1512/40078", 8); + device_context(&vid_1512_device); + ams->language = device_get_config_int("language"); + vid_init_1512(ams); + device_context_restore(); + device_add_ex(&vid_1512_device, ams->vid); + break; + + case AMS_PPC512: + loadfont(L"roms/machines/ppc512/40109", 1); + device_context(&vid_ppc512_device); + ams->language = device_get_config_int("language"); + vid_init_200(ams); + device_context_restore(); + device_add_ex(&vid_ppc512_device, ams->vid); + break; + + case AMS_PC1640: + loadfont(L"roms/video/mda/mda.rom", 0); + device_context(&vid_1640_device); + ams->language = device_get_config_int("language"); + vid_init_1640(ams); + device_context_restore(); + device_add_ex(&vid_1640_device, ams->vid); + break; + + case AMS_PC200: + loadfont(L"roms/machines/pc200/40109", 1); + device_context(&vid_200_device); + ams->language = device_get_config_int("language"); + vid_init_200(ams); + device_context_restore(); + device_add_ex(&vid_200_device, ams->vid); + break; + + case AMS_PC2086: + device_context(&vid_pc2086_device); + ams->language = device_get_config_int("language"); + device_context_restore(); + device_add(¶dise_pvga1a_pc2086_device); + break; + + case AMS_PC3086: + device_context(&vid_pc3086_device); + ams->language = device_get_config_int("language"); + device_context_restore(); + device_add(¶dise_pvga1a_pc3086_device); + break; + } else if ((type == AMS_PC200) || (type == AMS_PPC512)) + io_sethandler(0x03de, 1, + ams_read, NULL, NULL, ams_write, NULL, NULL, ams); + + /* Initialize the (custom) keyboard/mouse interface. */ + ams->wantirq = 0; + io_sethandler(0x0060, 7, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, ams); + timer_add(&ams->send_delay_timer, kbd_poll, ams, 1); + keyboard_set_table(scancode_xt); + keyboard_send = kbd_adddata_ex; + keyboard_scan = 1; + + io_sethandler(0x0078, 2, + ms_read, NULL, NULL, ms_write, NULL, NULL, ams); + io_sethandler(0x007a, 2, + ms_read, NULL, NULL, ms_write, NULL, NULL, ams); + + if (mouse_type == MOUSE_TYPE_INTERNAL) { + /* Tell mouse driver about our internal mouse. */ + mouse_reset(); + mouse_set_poll(ms_poll, ams); + } + + if (joystick_type != 7) + device_add(&gameport_device); +} + + +int +machine_pc1512_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/pc1512/40044", + L"roms/machines/pc1512/40043", + 0x000fc000, 16384, 0); + ret &= rom_present(L"roms/machines/pc1512/40078"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC1512); + + return ret; +} + + +int +machine_pc1640_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/pc1640/40044.v3", + L"roms/machines/pc1640/40043.v3", + 0x000fc000, 16384, 0); + ret &= rom_present(L"roms/machines/pc1640/40100"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC1640); + + return ret; +} + + +int +machine_pc200_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/pc200/pc20v2.1", + L"roms/machines/pc200/pc20v2.0", + 0x000fc000, 16384, 0); + ret &= rom_present(L"roms/machines/pc200/40109"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC200); + + return ret; +} + + +int +machine_ppc512_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/ppc512/40107.v2", + L"roms/machines/ppc512/40108.v2", + 0x000fc000, 16384, 0); + ret &= rom_present(L"roms/machines/ppc512/40109"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PPC512); + + return ret; +} + + +int +machine_pc2086_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleavedr(L"roms/machines/pc2086/40179.ic129", + L"roms/machines/pc2086/40180.ic132", + 0x000fc000, 65536, 0); + ret &= rom_present(L"roms/machines/pc2086/40186.ic171"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC2086); + + return ret; +} + + +int +machine_pc3086_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linearr(L"roms/machines/pc3086/fc00.bin", + 0x000fc000, 65536, 0); + ret &= rom_present(L"roms/machines/pc3086/c000.bin"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC3086); + + return ret; +} diff --git a/src/machine/m_amstrad.h b/src/machine/m_amstrad.h new file mode 100644 index 000000000..d85c3375b --- /dev/null +++ b/src/machine/m_amstrad.h @@ -0,0 +1,26 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header of the emulation of the Amstrad series of PC's: + * PC1512, PC1640 and PC200, including their keyboard, mouse and + * video devices, as well as the PC2086 and PC3086 systems. + * + * Version: @(#)m_amstrad.h 1.0.0 2019/03/21 + * + * Authors: Sarah Walker, + * + * Copyright 2008-2019 Sarah Walker. + */ +extern int amstrad_latch; + +enum +{ + AMSTRAD_NOLATCH, + AMSTRAD_SW9, + AMSTRAD_SW10 +}; diff --git a/src/machine/m_at.c b/src/machine/m_at.c index d4bf80adb..773ac6126 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -1,8 +1,47 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Standard PC/AT implementation. + * + * Version: @(#)m_at.c 1.0.11 2019/11/15 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. +*/ #include #include #include #include #include "../86box.h" +#include "../timer.h" #include "../pic.h" #include "../pit.h" #include "../dma.h" @@ -14,29 +53,37 @@ #include "../game/gameport.h" #include "../keyboard.h" #include "../lpt.h" +#include "../rom.h" #include "../disk/hdc.h" #include "machine.h" void -machine_at_common_init(const machine_t *model) +machine_at_common_init_ex(const machine_t *model, int is_ibm) { machine_common_init(model); - pit_set_out_func(&pit, 1, pit_refresh_timer_at); + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at); pic2_init(); dma16_init(); - if (lpt_enabled) - lpt2_remove(); - - device_add(&at_nvr_device); + if (is_ibm) + device_add(&ibmat_nvr_device); + else + device_add(&at_nvr_device); if (joystick_type != 7) device_add(&gameport_device); } +void +machine_at_common_init(const machine_t *model) +{ + machine_at_common_init_ex(model, 0); +} + + void machine_at_init(const machine_t *model) { @@ -46,6 +93,19 @@ machine_at_init(const machine_t *model) } +static void +machine_at_ibm_common_init(const machine_t *model) +{ + machine_at_common_init_ex(model, 1); + + device_add(&keyboard_at_device); + + mem_remap_top(384); + + device_add(&fdc_at_device); +} + + void machine_at_ps2_init(const machine_t *model) { @@ -60,7 +120,16 @@ machine_at_common_ide_init(const machine_t *model) { machine_at_common_init(model); - device_add(&ide_isa_2ch_opt_device); + device_add(&ide_isa_device); +} + + +void +machine_at_ibm_common_ide_init(const machine_t *model) +{ + machine_at_common_init_ex(model, 1); + + device_add(&ide_isa_device); } @@ -69,7 +138,7 @@ machine_at_ide_init(const machine_t *model) { machine_at_init(model); - device_add(&ide_isa_2ch_opt_device); + device_add(&ide_isa_device); } @@ -78,32 +147,111 @@ machine_at_ps2_ide_init(const machine_t *model) { machine_at_ps2_init(model); - device_add(&ide_isa_2ch_opt_device); + device_add(&ide_isa_device); } -void -machine_at_top_remap_init(const machine_t *model) -{ - machine_at_init(model); - - mem_remap_top_384k(); -} - - -void -machine_at_ide_top_remap_init(const machine_t *model) -{ - machine_at_ide_init(model); - - mem_remap_top_384k(); -} - - -void +int machine_at_ibm_init(const machine_t *model) { - machine_at_top_remap_init(model); + int ret; - device_add(&fdc_at_device); + ret = bios_load_interleaved(L"roms/machines/ibmat/62x0820.u27", + L"roms/machines/ibmat/62x0821.u47", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; } + +//IBM AT machines with custom BIOSes +int +machine_at_ibmatquadtel_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmatquadtel/BIOS_30MAR90_U27_QUADTEL_ENH_286_BIOS_3.05.01_27256.BIN", + L"roms/machines/ibmatquadtel/BIOS_30MAR90_U47_QUADTEL_ENH_286_BIOS_3.05.01_27256.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; +} + +int +machine_at_ibmatami_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmatami/BIOS_5170_30APR89_U27_AMI_27256.BIN", + L"roms/machines/ibmatami/BIOS_5170_30APR89_U47_AMI_27256.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; +} + +int +machine_at_ibmatpx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmatpx/BIOS ROM - PhoenixBIOS A286 - Version 1.01 - Even.bin", + L"roms/machines/ibmatpx/BIOS ROM - PhoenixBIOS A286 - Version 1.01 - Odd.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; +} + +int +machine_at_ibmxt286_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmxt286/bios_5162_21apr86_u34_78x7460_27256.bin", + L"roms/machines/ibmxt286/bios_5162_21apr86_u35_78x7461_27256.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) +int +machine_at_open_at_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/open_at/bios.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; +} +#endif diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c new file mode 100644 index 000000000..35a969cc6 --- /dev/null +++ b/src/machine/m_at_286_386sx.c @@ -0,0 +1,410 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of 286 and 386SX machines. + * + * Version: @(#)m_at_286_386sx.c 1.0.2 2019/11/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../io.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../rom.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../disk/hdc.h" +#include "../video/video.h" +#include "../video/vid_et4000.h" +#include "../video/vid_oak_oti.h" +#include "../video/vid_paradise.h" +#include "machine.h" + + +static void +machine_at_headland_common_init(int ht386) +{ + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + if (ht386) + device_add(&headland_386_device); + else + device_add(&headland_device); +} + + +#if defined(DEV_BRANCH) && defined(USE_AMI386SX) +int +machine_at_headland_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami386/ami386.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + machine_at_headland_common_init(1); + + return ret; +} +#endif + + +int +machine_at_tg286m_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/tg286m/ami.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + machine_at_headland_common_init(0); + + return ret; +} + + +const device_t * +at_ama932j_get_device(void) +{ + return &oti067_ama932j_device; +} + + +int +machine_at_ama932j_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ama932j/ami.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + machine_at_headland_common_init(1); + + if (gfxcard == VID_INTERNAL) + device_add(&oti067_ama932j_device); + + return ret; +} + +int +machine_at_headlandpho_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/headlandpho/286-Headland-LO.BIN", + L"roms/machines/headlandpho/286-Headland-HI.BIN", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + machine_at_headland_common_init(1); + + return ret; +} + +int +machine_at_headlandquadtel_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/headlandquadtel/Amiht-l.BIN", + L"roms/machines/headlandquadtel/AMIHT-H.BIN", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + machine_at_headland_common_init(1); + + return ret; +} + +int +machine_at_iqs_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/iqs/286-Headland-IQS-LO.BIN", + L"roms/machines/iqs/286-Headland-IQS-HI.BIN", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + machine_at_headland_common_init(1); + + return ret; +} + +int +machine_at_neat_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/dtk386/3cto001.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_init(model); + + device_add(&neat_device); + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_neat_ami_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami286/amic206.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&neat_device); + device_add(&fdc_at_device); + + device_add(&keyboard_at_ami_device); + + return ret; +} + +#if defined(DEV_BRANCH) && defined(USE_MICRONICS386) +int +machine_at_micronics386_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/micronics386/386-Micronics 09-00021-LO.BIN", + L"roms/machines/micronics386/386-Micronics 09-00021-HI.BIN", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_init(model); + + device_add(&neat_device); + device_add(&fdc_at_device); + + return ret; +} +#endif + +static void +machine_at_scat_init(const machine_t *model, int is_v4) +{ + machine_at_init(model); + device_add(&fdc_at_device); + + if (is_v4) + device_add(&scat_4_device); + else + device_add(&scat_device); +} + + +static void +machine_at_scatsx_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + device_add(&scat_sx_device); +} + + +int +machine_at_award286_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/award286/award.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 0); + + return ret; +} + + +int +machine_at_gw286ct_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/gw286ct/2ctc001.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 1); + + return ret; +} + + +int +machine_at_super286tr_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/super286tr/hyundai_award286.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 0); + + return ret; +} + + +int +machine_at_spc4200p_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/spc4200p/u8.01", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 0); + + return ret; +} + + +int +machine_at_spc4216p_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/spc4216p/7101.u8", + L"roms/machines/spc4216p/ac64.u10", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 1); + + return ret; +} + + +int +machine_at_kmxc02_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/kmxc02/3ctm005.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scatsx_init(model); + + return ret; +} + +int +machine_at_deskmaster286_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/deskmaster286/SAMSUNG-DESKMASTER-28612-ROM.BIN", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 0); + + return ret; +} + +int +machine_at_wd76c10_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/megapc/41651-bios lo.u18", + L"roms/machines/megapc/211253-bios hi.u19", + 0x000f0000, 65536, 0x08000); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + device_add(&keyboard_ps2_quadtel_device); + + device_add(&wd76c10_device); + + if (gfxcard == VID_INTERNAL) + device_add(¶dise_wd90c11_megapc_device); + + return ret; +} diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c new file mode 100644 index 000000000..a9b913b5a --- /dev/null +++ b/src/machine/m_at_386dx_486.c @@ -0,0 +1,341 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of 386DX and 486 machines. + * + * Version: @(#)m_at_386dx_486.c 1.0.0 2019/05/16 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../io.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../pci.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../rom.h" +#include "../sio.h" +#include "../disk/hdc.h" +#include "../video/video.h" +#include "../video/vid_ht216.h" +#include "../intel_flash.h" +#include "../intel_sio.h" +#include "machine.h" + + +int +machine_at_pb410a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/pb410a/pb410a.080337.4abf.u25.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_ide_init(model); + + device_add(&keyboard_ps2_device); + + device_add(&acc3221_device); + device_add(&acc2168_device); + + if (gfxcard == VID_INTERNAL) + device_add(&ht216_32_pb410a_device); + + return ret; +} + + +static void +machine_at_ali1429_common_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + device_add(&ali1429_device); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); +} + + +int +machine_at_ali1429_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami486/ami486.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ali1429_common_init(model); + + return ret; +} + + +int +machine_at_winbios1429_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/win486/ali1429g.amw", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ali1429_common_init(model); + + return ret; +} + + +int +machine_at_opti495_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/award495/opt495s.awa", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + device_add(&opti495_device); + + device_add(&keyboard_at_device); + device_add(&fdc_at_device); + + return ret; +} + + +static void +machine_at_opti495_ami_common_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + device_add(&opti495_device); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); +} + + +int +machine_at_opti495_ami_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami495/opt495sx.ami", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_opti495_ami_common_init(model); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_MR495) +int +machine_at_opti495_mr_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/mr495/opt495sx.mr", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_opti495_ami_common_init(model); + + return ret; +} +#endif + + +static void +machine_at_sis_85c471_common_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + device_add(&fdc_at_device); + + device_add(&sis_85c471_device); +} + + +int +machine_at_ami471_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami471/SIS471BE.AMI", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c471_common_init(model); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_dtk486_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/dtk486/4siw005.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c471_common_init(model); + device_add(&keyboard_at_device); + + return ret; +} + + +int +machine_at_px471_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/px471/SIS471A1.PHO", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c471_common_init(model); + device_add(&keyboard_at_device); + + return ret; +} + + +int +machine_at_win471_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/win471/4sim001.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c471_common_init(model); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +static void +machine_at_sis_85c496_common_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&ide_pci_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x05, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&keyboard_ps2_pci_device); + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + device_add(&sis_85c496_device); +} + + +int +machine_at_r418_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/r418/r418i.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c496_common_init(model); + + device_add(&fdc37c665_device); + + return ret; +} + + +int +machine_at_alfredo_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/alfredo/1010AQ0_.BIO", + L"roms/machines/alfredo/1010AQ0_.BI1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sio_device); + device_add(&fdc37c663_device); + device_add(&intel_flash_bxt_ami_device); + + device_add(&i420tx_device); + + return ret; +} diff --git a/src/machine/m_at_4x0.c b/src/machine/m_at_4x0.c deleted file mode 100644 index 29833ab99..000000000 --- a/src/machine/m_at_4x0.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of the Intel PCISet chips from 430LX to 440FX. - * - * Version: @(#)m_at_430lx_nx.c 1.0.0 2018/05/09 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include "../86box.h" -#include "../mem.h" -#include "../memregs.h" -#include "../io.h" -#include "../rom.h" -#include "../pci.h" -#include "../device.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" -#include "../keyboard.h" -#include "../intel.h" -#include "../intel_flash.h" -#include "../intel_sio.h" -#include "../piix.h" -#include "../sio.h" -#include "../video/video.h" -#include "../video/vid_cl54xx.h" -#include "../video/vid_s3.h" -#include "machine.h" - - -enum -{ - INTEL_430LX, - INTEL_430NX, - INTEL_430FX, - INTEL_430HX, -#if defined(DEV_BRANCH) && defined(USE_I686) - INTEL_430VX, - INTEL_440FX -#else - INTEL_430VX -#endif -}; - -typedef struct -{ - uint8_t regs[256]; - int type; -} i4x0_t; - - -typedef struct -{ - int index; -} acerm3a_t; - - -static void -i4x0_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(); -} - - -static void -i4x0_write(int func, int addr, uint8_t val, void *priv) -{ - i4x0_t *dev = (i4x0_t *) 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*/ - if (dev->type >= INTEL_430FX) { - if (romset == ROM_PB640) - val &= 0x06; - else - val &= 0x02; - } else - val &= 0x42; - val |= 0x04; - break; - case 0x05: - if (dev->type >= INTEL_430FX) - val = 0; - else - val &= 0x01; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - if (dev->type >= INTEL_430HX) { - val &= 0x80; - val |= 0x02; - } else { - val = 0x02; - if (romset == ROM_PB640) - val |= 0x20; - } - break; - - case 0x59: /*PAM0*/ - if ((dev->regs[0x59] ^ val) & 0xf0) { - i4x0_map(0xf0000, 0x10000, val >> 4); - shadowbios = (val & 0x10); - } - break; - case 0x5a: /*PAM1*/ - if ((dev->regs[0x5a] ^ val) & 0x0f) - i4x0_map(0xc0000, 0x04000, val & 0xf); - if ((dev->regs[0x5a] ^ val) & 0xf0) - i4x0_map(0xc4000, 0x04000, val >> 4); - break; - case 0x5b: /*PAM2*/ - if ((dev->regs[0x5b] ^ val) & 0x0f) - i4x0_map(0xc8000, 0x04000, val & 0xf); - if ((dev->regs[0x5b] ^ val) & 0xf0) - i4x0_map(0xcc000, 0x04000, val >> 4); - break; - case 0x5c: /*PAM3*/ - if ((dev->regs[0x5c] ^ val) & 0x0f) - i4x0_map(0xd0000, 0x04000, val & 0xf); - if ((dev->regs[0x5c] ^ val) & 0xf0) - i4x0_map(0xd4000, 0x04000, val >> 4); - break; - case 0x5d: /*PAM4*/ - if ((dev->regs[0x5d] ^ val) & 0x0f) - i4x0_map(0xd8000, 0x04000, val & 0xf); - if ((dev->regs[0x5d] ^ val) & 0xf0) - i4x0_map(0xdc000, 0x04000, val >> 4); - break; - case 0x5e: /*PAM5*/ - if ((dev->regs[0x5e] ^ val) & 0x0f) - i4x0_map(0xe0000, 0x04000, val & 0xf); - if ((dev->regs[0x5e] ^ val) & 0xf0) - i4x0_map(0xe4000, 0x04000, val >> 4); - break; - case 0x5f: /*PAM6*/ - if ((dev->regs[0x5f] ^ val) & 0x0f) - i4x0_map(0xe8000, 0x04000, val & 0xf); - if ((dev->regs[0x5f] ^ val) & 0xf0) - i4x0_map(0xec000, 0x04000, val >> 4); - break; - case 0x72: /*SMRAM*/ - if ((dev->type >= INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x48)) - i4x0_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); - break; - } - - dev->regs[addr] = val; -} - - -static uint8_t -i4x0_read(int func, int addr, void *priv) -{ - i4x0_t *dev = (i4x0_t *) priv; - - if (func) - return 0xff; - - return dev->regs[addr]; -} - - -static void -i4x0_reset(void *priv) -{ - i4x0_t *i4x0 = (i4x0_t *)priv; - - i4x0_write(0, 0x59, 0x00, priv); - if (i4x0->type >= INTEL_430FX) - i4x0_write(0, 0x72, 0x02, priv); -} - - -static void -i4x0_close(void *p) -{ - i4x0_t *i4x0 = (i4x0_t *)p; - - free(i4x0); -} - - -static void -*i4x0_init(const device_t *info) -{ - i4x0_t *i4x0 = (i4x0_t *) malloc(sizeof(i4x0_t)); - memset(i4x0, 0, sizeof(i4x0_t)); - - i4x0->type = info->local; - - i4x0->regs[0x00] = 0x86; i4x0->regs[0x01] = 0x80; /*Intel*/ - switch(i4x0->type) { - case INTEL_430LX: - i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ - i4x0->regs[0x08] = 0x03; /*A3 stepping*/ - i4x0->regs[0x50] = 0x80; - i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ - break; - case INTEL_430NX: - i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ - i4x0->regs[0x08] = 0x10; /*A0 stepping*/ - i4x0->regs[0x50] = 0xA0; - i4x0->regs[0x52] = 0x44; /*256kb PLB cache*/ - i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; - break; - case INTEL_430FX: - i4x0->regs[0x02] = 0x2d; i4x0->regs[0x03] = 0x12; /*SB82437FX-66*/ - if (romset == ROM_PB640) - i4x0->regs[0x08] = 0x02; /*???? stepping*/ - else - i4x0->regs[0x08] = 0x00; /*A0 stepping*/ - i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ - break; - case INTEL_430HX: - i4x0->regs[0x02] = 0x50; i4x0->regs[0x03] = 0x12; /*82439HX*/ - i4x0->regs[0x08] = 0x00; /*A0 stepping*/ - i4x0->regs[0x51] = 0x20; - i4x0->regs[0x52] = 0xB5; /*512kb cache*/ - i4x0->regs[0x56] = 0x52; /*DRAM control*/ - i4x0->regs[0x59] = 0x40; - i4x0->regs[0x5A] = i4x0->regs[0x5B] = i4x0->regs[0x5C] = i4x0->regs[0x5D] = 0x44; - i4x0->regs[0x5E] = i4x0->regs[0x5F] = 0x44; - i4x0->regs[0x65] = i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; - i4x0->regs[0x68] = 0x11; - break; - case INTEL_430VX: - i4x0->regs[0x02] = 0x30; i4x0->regs[0x03] = 0x70; /*82437VX*/ - i4x0->regs[0x08] = 0x00; /*A0 stepping*/ - i4x0->regs[0x52] = 0x42; /*256kb PLB cache*/ - i4x0->regs[0x53] = 0x14; - i4x0->regs[0x56] = 0x52; /*DRAM control*/ - i4x0->regs[0x67] = 0x11; - i4x0->regs[0x69] = 0x03; - i4x0->regs[0x70] = 0x20; - i4x0->regs[0x74] = 0x0e; - i4x0->regs[0x78] = 0x23; - break; -#if defined(DEV_BRANCH) && defined(USE_I686) - case INTEL_440FX: - i4x0->regs[0x02] = 0x37; i4x0->regs[0x03] = 0x12; /*82441FX*/ - i4x0->regs[0x08] = 0x02; /*A0 stepping*/ - i4x0->regs[0x2c] = 0xf4; - i4x0->regs[0x2d] = 0x1a; - i4x0->regs[0x2f] = 0x11; - i4x0->regs[0x51] = 0x01; - i4x0->regs[0x53] = 0x80; - i4x0->regs[0x58] = 0x10; - i4x0->regs[0x5a] = i4x0->regs[0x5b] = i4x0->regs[0x5c] = i4x0->regs[0x5d] = 0x11; - i4x0->regs[0x5e] = 0x11; - i4x0->regs[0x5f] = 0x31; - break; -#endif - } - i4x0->regs[0x04] = 0x06; i4x0->regs[0x05] = 0x00; -#if defined(DEV_BRANCH) && defined(USE_I686) - if (i4x0->type == INTEL_440FX) - i4x0->regs[0x06] = 0x80; -#endif - if ((i4x0->type == INTEL_430FX) && (romset != ROM_PB640)) - i4x0->regs[0x07] = 0x82; -#if defined(DEV_BRANCH) && defined(USE_I686) - else if (i4x0->type != INTEL_440FX) -#else - else -#endif - i4x0->regs[0x07] = 0x02; - i4x0->regs[0x0b] = 0x06; - if (i4x0->type >= INTEL_430FX) - i4x0->regs[0x57] = 0x01; - else - i4x0->regs[0x57] = 0x31; - i4x0->regs[0x60] = i4x0->regs[0x61] = i4x0->regs[0x62] = i4x0->regs[0x63] = 0x02; - i4x0->regs[0x64] = 0x02; - if (i4x0->type >= INTEL_430FX) - i4x0->regs[0x72] = 0x02; - - pci_add_card(0, i4x0_read, i4x0_write, i4x0); - - return i4x0; -} - - -const device_t i430lx_device = -{ - "Intel 82434LX", - DEVICE_PCI, - INTEL_430LX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -const device_t i430nx_device = -{ - "Intel 82434NX", - DEVICE_PCI, - INTEL_430NX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -const device_t i430fx_device = -{ - "Intel SB82437FX-66", - DEVICE_PCI, - INTEL_430FX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -const device_t i430hx_device = -{ - "Intel 82439HX", - DEVICE_PCI, - INTEL_430HX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -const device_t i430vx_device = -{ - "Intel 82437VX", - DEVICE_PCI, - INTEL_430VX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -#if defined(DEV_BRANCH) && defined(USE_I686) -const device_t i440fx_device = -{ - "Intel 82441FX", - DEVICE_PCI, - INTEL_440FX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; -#endif - - -static void -acerm3a_out(uint16_t port, uint8_t val, void *p) -{ - acerm3a_t *dev = (acerm3a_t *) p; - - if (port == 0xea) - dev->index = val; -} - - -static uint8_t -acerm3a_in(uint16_t port, void *p) -{ - acerm3a_t *dev = (acerm3a_t *) p; - - if (port == 0xeb) { - switch (dev->index) { - case 2: - return 0xfd; - } - } - return 0xff; -} - - -static void -acerm3a_close(void *p) -{ - acerm3a_t *dev = (acerm3a_t *)p; - - free(dev); -} - - -static void -*acerm3a_init(const device_t *info) -{ - acerm3a_t *acerm3a = (acerm3a_t *) malloc(sizeof(acerm3a_t)); - memset(acerm3a, 0, sizeof(acerm3a_t)); - - io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, acerm3a); - - return acerm3a; -} - - -const device_t acerm3a_device = -{ - "Acer M3A Register", - 0, - 0, - acerm3a_init, - acerm3a_close, - NULL, - NULL, - NULL, - NULL, - NULL -}; - - -static void -machine_at_premiere_common_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&ide_pci_2ch_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_2); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); - pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&sio_device); - fdc37c665_init(); - intel_batman_init(); - - device_add(&intel_flash_bxt_ami_device); -} - - -void -machine_at_batman_init(const machine_t *model) -{ - machine_at_premiere_common_init(model); - - device_add(&i430lx_device); -} - - -void -machine_at_plato_init(const machine_t *model) -{ - machine_at_premiere_common_init(model); - - device_add(&i430nx_device); -} - - -void -machine_at_p54tp4xe_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - fdc37c665_init(); - - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_endeavor_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - pc87306_init(); - - device_add(&intel_flash_bxt_ami_device); - - if (gfxcard == GFX_INTERNAL) - device_add(&s3_phoenix_trio64_onboard_pci_device); -} - - -const device_t * -at_endeavor_get_device(void) -{ - return &s3_phoenix_trio64_onboard_pci_device; -} - - -void -machine_at_zappa_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - pc87306_init(); - - device_add(&intel_flash_bxt_ami_device); -} - - -void -machine_at_mb500n_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - fdc37c665_init(); - - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_president_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - w83877f_init(); - - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_thor_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - pc87306_init(); - - device_add(&intel_flash_bxt_ami_device); -} - - -void -machine_at_pb640_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_pb640_device); - pc87306_init(); - - device_add(&intel_flash_bxt_ami_device); - - if (gfxcard == GFX_INTERNAL) - device_add(&gd5440_onboard_pci_device); -} - - -const device_t * -at_pb640_get_device(void) -{ - return &gd5440_onboard_pci_device; -} - - -void -machine_at_acerm3a_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x1F, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x10, PCI_CARD_ONBOARD, 4, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - fdc37c932fr_init(); - device_add(&acerm3a_device); - - device_add(&intel_flash_bxb_device); -} - - -void -machine_at_acerv35n_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i430hx_device); - device_add(&piix3_device); - fdc37c932fr_init(); - device_add(&acerm3a_device); - - device_add(&intel_flash_bxb_device); -} - - -void -machine_at_ap53_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_ONBOARD, 1, 2, 3, 4); - device_add(&i430hx_device); - device_add(&piix3_device); - fdc37c669_init(); - - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_p55t2p4_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - w83877f_init(); - - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_p55t2s_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - pc87306_init(); - - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_p55tvp4_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - w83877f_init(); - - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_i430vx_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - um8669f_init(); - - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_p55va_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - fdc37c932fr_init(); - - device_add(&intel_flash_bxt_device); -} - - -#if defined(DEV_BRANCH) && defined(USE_I686) -void -machine_at_i440fx_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i440fx_device); - device_add(&piix3_device); - fdc37c665_init(); - - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_s1668_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440fx_device); - device_add(&piix3_device); - fdc37c665_init(); - - device_add(&intel_flash_bxt_device); -} -#endif diff --git a/src/machine/m_at_ali1429.c b/src/machine/m_at_ali1429.c deleted file mode 100644 index a0dc3ddf0..000000000 --- a/src/machine/m_at_ali1429.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include -#include -#include "../86box.h" -#include "../cpu/cpu.h" -#include "../io.h" -#include "../mem.h" -#include "../device.h" -#include "../keyboard.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" -#include "machine.h" - - -static int ali1429_index; -static uint8_t ali1429_regs[256]; - - -static void ali1429_recalc(void) -{ - int c; - - for (c = 0; c < 8; c++) - { - uint32_t base = 0xc0000 + (c << 15); - if (ali1429_regs[0x13] & (1 << c)) - { - switch (ali1429_regs[0x14] & 3) - { - case 0: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - } - else - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } - - flushmmucache(); -} - -void ali1429_write(uint16_t port, uint8_t val, void *priv) -{ - if (!(port & 1)) - ali1429_index = val; - else - { - ali1429_regs[ali1429_index] = val; - switch (ali1429_index) - { - case 0x13: - ali1429_recalc(); - break; - case 0x14: - shadowbios = val & 1; - shadowbios_write = val & 2; - ali1429_recalc(); - break; - } - } -} - -uint8_t ali1429_read(uint16_t port, void *priv) -{ - if (!(port & 1)) - return ali1429_index; - if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix) - return 0xff; /*Don't conflict with Cyrix config registers*/ - return ali1429_regs[ali1429_index]; -} - - -static void ali1429_reset(void) -{ - memset(ali1429_regs, 0xff, 256); -} - - -static void ali1429_init(void) -{ - io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, NULL); -} - - -void -machine_at_ali1429_init(const machine_t *model) -{ - ali1429_reset(); - - machine_at_common_ide_init(model); - - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); - - ali1429_init(); - - secondary_ide_check(); -} diff --git a/src/machine/m_at_commodore.c b/src/machine/m_at_commodore.c index e12e13970..348c43e36 100644 --- a/src/machine/m_at_commodore.c +++ b/src/machine/m_at_commodore.c @@ -1,55 +1,117 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Commodore PC3 system. + * + * Version: @(#)m_at_commodore.c 1.0.2 2018/11/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. +*/ #include #include #include #include #include "../86box.h" #include "../device.h" +#include "../timer.h" #include "../io.h" +#include "../mem.h" #include "../lpt.h" +#include "../rom.h" #include "../serial.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "machine.h" -static void cbm_io_write(uint16_t port, uint8_t val, void *p) -{ - 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: - serial_setup(1, 0x2f8, 3); - break; - case 0x8: - serial_setup(1, 0x3f8, 4); - break; - } -} +static serial_t *cmd_uart; -static void cbm_io_init() + +static void +cbm_io_write(uint16_t port, uint8_t val, void *p) { - io_sethandler(0x0230, 0x0001, NULL,NULL,NULL, cbm_io_write,NULL,NULL, NULL); + 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: + serial_setup(cmd_uart, 0x2f8, 3); + break; + case 0x8: + serial_setup(cmd_uart, 0x3f8, 4); + break; + } } -void +static void +cbm_io_init() +{ + io_sethandler(0x0230, 0x0001, NULL,NULL,NULL, cbm_io_write,NULL,NULL, NULL); +} + + +int machine_at_cmdpc_init(const machine_t *model) { - machine_at_ide_top_remap_init(model); - device_add(&fdc_at_device); + int ret; - cbm_io_init(); + ret = bios_load_interleaved(L"roms/machines/cmdpc30/commodore pc 30 iii even.bin", + L"roms/machines/cmdpc30/commodore pc 30 iii odd.bin", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + machine_at_init(model); + + mem_remap_top(384); + + device_add(&fdc_at_device); + cmd_uart = device_add(&i8250_device); + + cbm_io_init(); + + return ret; } diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 9497a8498..801de3412 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -8,7 +8,7 @@ * * Emulation of various Compaq PC's. * - * Version: @(#)m_at_compaq.c 1.0.5 2018/03/18 + * Version: @(#)m_at_compaq.c 1.0.6 2018/09/02 * * Authors: Sarah Walker, * Miran Grca, @@ -23,6 +23,7 @@ #include #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -33,6 +34,16 @@ #include "machine.h" +enum +{ + COMPAQ_PORTABLEII = 0 +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + , COMPAQ_PORTABLEIII, + COMPAQ_PORTABLEIII386 +#endif +}; + + /* Compaq Deskpro 386 remaps RAM from 0xA0000-0xFFFFF to 0xFA0000-0xFFFFFF */ static mem_mapping_t ram_mapping; @@ -97,10 +108,13 @@ write_raml(uint32_t addr, uint32_t val, void *priv) } -void -machine_at_compaq_init(const machine_t *model) +static void +machine_at_compaq_init(const machine_t *model, int type) { - machine_at_top_remap_init(model); + machine_at_init(model); + + mem_remap_top(384); + device_add(&fdc_at_device); mem_mapping_add(&ram_mapping, 0xfa0000, 0x60000, @@ -108,30 +122,74 @@ machine_at_compaq_init(const machine_t *model) write_ram, write_ramw, write_raml, 0xa0000+ram, MEM_MAPPING_INTERNAL, NULL); - switch(model->id) { -#ifdef PORTABLE3 - case ROM_DESKPRO_386: - if (hdc_current == 1) - device_add(&ide_isa_device); - break; -#endif - - case ROM_PORTABLE: + switch(type) { + case COMPAQ_PORTABLEII: break; - case ROM_PORTABLEII: +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + case COMPAQ_PORTABLEIII: break; -#ifdef PORTABLE3 - case ROM_PORTABLEIII: - machine_olim24_video_init(); - break; - - case ROM_PORTABLEIII386: - machine_olim24_video_init(); + case COMPAQ_PORTABLEIII386: if (hdc_current == 1) device_add(&ide_isa_device); break; #endif } } + + +int +machine_at_portableii_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/portableii/109740-001.rom", + L"roms/machines/portableii/109739-001.rom", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + machine_at_compaq_init(model, COMPAQ_PORTABLEII); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) +int +machine_at_portableiii_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/portableiii/109738-002.bin", + L"roms/machines/portableiii/109737-002.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_compaq_init(model, COMPAQ_PORTABLEIII); + + return ret; +} + + +int +machine_at_portableiii386_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/portableiii/109738-002.bin", + L"roms/machines/portableiii/109737-002.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_compaq_init(model, COMPAQ_PORTABLEIII386); + + return ret; +} +#endif diff --git a/src/machine/m_at_headland.c b/src/machine/m_at_headland.c deleted file mode 100644 index b8f707d4e..000000000 --- a/src/machine/m_at_headland.c +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include -#include -#include "../86box.h" -#include "../cpu/cpu.h" -#include "../cpu/x86.h" -#include "../io.h" -#include "../device.h" -#include "../keyboard.h" -#include "../mem.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "machine.h" - - -static int headland_index; -static uint8_t headland_regs[256]; - - -static void headland_write(uint16_t addr, uint8_t val, void *priv) -{ - uint8_t old_val; - - if (addr & 1) - { - old_val = headland_regs[headland_index]; - - if (headland_index == 0xc1 && !is486) val = 0; - headland_regs[headland_index] = val; - if (headland_index == 0x82) - { - shadowbios = val & 0x10; - shadowbios_write = !(val & 0x10); - if (shadowbios) - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); - else - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - } - else if (headland_index == 0x87) - { - if ((val & 1) && !(old_val & 1)) - softresetx86(); - } - } - else - headland_index = val; -} - - -static uint8_t headland_read(uint16_t addr, void *priv) -{ - if (addr & 1) - { - if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix) - return 0xff; /*Don't conflict with Cyrix config registers*/ - return headland_regs[headland_index]; - } - return headland_index; -} - - -static void headland_init(void) -{ - io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); -} - - -void -machine_at_headland_init(const machine_t *model) -{ - machine_at_common_ide_init(model); - - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); - - headland_init(); -} diff --git a/src/machine/m_at_neat.c b/src/machine/m_at_neat.c deleted file mode 100644 index 2f789b3a1..000000000 --- a/src/machine/m_at_neat.c +++ /dev/null @@ -1,109 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -/*This is the chipset used in the AMI 286 clone model*/ -#include -#include -#include -#include -#include "../86box.h" -#include "../device.h" -#include "../io.h" -#include "../keyboard.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "machine.h" - - -static uint8_t neat_regs[256]; -static int neat_index; -static int neat_emspage[4]; - - -static void neat_write(uint16_t port, uint8_t val, void *priv) -{ - switch (port) - { - case 0x22: - neat_index = val; - break; - - case 0x23: - neat_regs[neat_index] = val; - switch (neat_index) - { - case 0x6E: /*EMS page extension*/ - neat_emspage[3] = (neat_emspage[3] & 0x7F) | (( val & 3) << 7); - neat_emspage[2] = (neat_emspage[2] & 0x7F) | (((val >> 2) & 3) << 7); - neat_emspage[1] = (neat_emspage[1] & 0x7F) | (((val >> 4) & 3) << 7); - neat_emspage[0] = (neat_emspage[0] & 0x7F) | (((val >> 6) & 3) << 7); - break; - } - break; - - case 0x0208: case 0x0209: case 0x4208: case 0x4209: - case 0x8208: case 0x8209: case 0xC208: case 0xC209: - neat_emspage[port >> 14] = (neat_emspage[port >> 14] & 0x180) | (val & 0x7F); - break; - } -} - - -static uint8_t neat_read(uint16_t port, void *priv) -{ - switch (port) - { - case 0x22: - return neat_index; - - case 0x23: - return neat_regs[neat_index]; - } - return 0xff; -} - - -#if NOT_USED -static void neat_writeems(uint32_t addr, uint8_t val) -{ - ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)] = val; -} - - -static uint8_t neat_readems(uint32_t addr) -{ - return ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)]; -} -#endif - - -static void neat_init(void) -{ - io_sethandler(0x0022, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); - io_sethandler(0x0208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); - io_sethandler(0x4208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); - io_sethandler(0x8208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); - io_sethandler(0xc208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); -} - - -void -machine_at_neat_init(const machine_t *model) -{ - machine_at_init(model); - device_add(&fdc_at_device); - - neat_init(); -} - - -void -machine_at_neat_ami_init(const machine_t *model) -{ - machine_at_common_init(model); - - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); - - neat_init(); -} diff --git a/src/machine/m_at_scat.c b/src/machine/m_at_scat.c deleted file mode 100644 index c9af19fac..000000000 --- a/src/machine/m_at_scat.c +++ /dev/null @@ -1,1397 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of Chips&Technology's SCAT (82C235) chipset. - * - * Re-worked version based on the 82C235 datasheet and errata. - * - * Version: @(#)m_at_scat.c 1.0.15 2018/04/29 - * - * Authors: Original by GreatPsycho for PCem. - * Fred N. van Kempen, - * - * Copyright 2017,2018 Fred N. van Kempen. - */ -#include -#include -#include -#include -#include "../86box.h" -#include "../device.h" -#include "../cpu/cpu.h" -#include "../cpu/x86.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../keyboard.h" -#include "../io.h" -#include "../mem.h" -#include "../nmi.h" -#include "../rom.h" -#include "machine.h" - - -#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 -#define SCAT_VERSION 0x40 -#define SCAT_CLOCK_CONTROL 0x41 -#define SCAT_PERIPHERAL_CONTROL 0x44 -#define SCAT_MISCELLANEOUS_STATUS 0x45 -#define SCAT_POWER_MANAGEMENT 0x46 -#define SCAT_ROM_ENABLE 0x48 -#define SCAT_RAM_WRITE_PROTECT 0x49 -#define SCAT_SHADOW_RAM_ENABLE_1 0x4A -#define SCAT_SHADOW_RAM_ENABLE_2 0x4B -#define SCAT_SHADOW_RAM_ENABLE_3 0x4C -#define SCAT_DRAM_CONFIGURATION 0x4D -#define SCAT_EXTENDED_BOUNDARY 0x4E -#define SCAT_EMS_CONTROL 0x4F - -#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; - uint8_t regs_2x9; -} scat_t; - - -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_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_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 }; - - -static uint8_t scat_read(uint16_t port, void *priv); -static void scat_write(uint16_t port, uint8_t val, void *priv); - - -static 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; - } -} - - -static void -scat_shadow_state_update() -{ - int i, val; - - for (i = 0; i < 24; i++) { - 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); - } - - flushmmucache(); -} - - -static void -scat_set_xms_bound(uint8_t val) -{ - uint32_t max_xms_size = ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && ((val & 0x10) != 0)) || (scat_regs[SCAT_VERSION] >= 4) ? 0xFE0000 : 0xFC0000; - - switch (val & 0x0F) { - case 1: - scat_xms_bound = 0x100000; - break; - case 2: - scat_xms_bound = 0x140000; - break; - case 3: - scat_xms_bound = 0x180000; - break; - case 4: - scat_xms_bound = 0x200000; - break; - case 5: - scat_xms_bound = 0x300000; - break; - case 6: - scat_xms_bound = 0x400000; - break; - case 7: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x600000 : 0x500000; - break; - case 8: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x800000 : 0x700000; - break; - case 9: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xA00000 : 0x800000; - break; - case 10: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xC00000 : 0x900000; - break; - case 11: - 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 = max_xms_size; - break; - } - - 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 & 0x0F) == 0 || scat_xms_bound > 0x160000) - scat_xms_bound = 0x160000; - if (scat_xms_bound > 0x100000) - mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - if (scat_xms_bound < 0x160000) - mem_set_mem_state(scat_xms_bound, 0x160000 - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } else { - if (scat_xms_bound > max_xms_size) - scat_xms_bound = max_xms_size; - 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]); - } - } -} - - -static uint32_t -get_scat_addr(uint32_t addr, scat_t *p) -{ - 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; -} - - -static 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(); -} - - -static 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); - } - addr = get_scat_addr(0, NULL); - mem_mapping_set_exec(&scat_low_mapping[0], addr < (mem_size << 10) ? ram + addr : NULL); - addr = get_scat_addr(0xF0000, NULL); - 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); - } - - 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]); - } - } 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); -} - - -static void -scat_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t scat_reg_valid = 0, scat_shadow_update = 0, scat_map_update = 0, index; - uint32_t base_addr, virt_addr; - - switch (port) { - case 0x22: - scat_index = val; - break; - - 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: - if(val & 0x40) { - if(val & 1) { - 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 { - 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); - } - } 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: - /* TODO - Only use AUX parity disable bit for this version. - Other bits should be implemented later. */ - val &= (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x40 : 0x60; - scat_reg_valid = 1; - break; - case SCAT_DRAM_CONFIGURATION: - scat_map_update = 1; - - 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: - 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); - 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; - if (scat_shadow_update) - scat_shadow_state_update(); - if (scat_map_update) - scat_memmap_state_update(); - break; - - case 0x92: - if ((mem_a20_alt ^ val) & 2) { - mem_a20_alt = val & 2; - mem_a20_recalc(); - } - if ((~scat_port_92 & val) & 1) { - softresetx86(); - cpu_set_edx(); - } - scat_port_92 = val; - break; - - case 0x208: - case 0x218: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - 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_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: - case 0x219: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - 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 (scat_regs[SCAT_EMS_CONTROL] & 0x80) { - 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]); - } 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]); - } - flushmmucache(); - } - - if (scat_ems_reg_2xA & 0x80) - 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: - case 0x21A: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - scat_ems_reg_2xA = ((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? val : val & 0xc3; - break; - } -} - - -static uint8_t -scat_read(uint16_t port, void *priv) -{ - uint8_t val = 0xff, index; - switch (port) { - case 0x23: - switch (scat_index) { - case SCAT_MISCELLANEOUS_STATUS: - val = (scat_regs[scat_index] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5); - break; - case SCAT_DRAM_CONFIGURATION: - 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; - } - break; - - case 0x92: - val = scat_port_92; - break; - - case 0x208: - case 0x218: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - 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: - case 0x219: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - 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: - case 0x21A: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - val = scat_ems_reg_2xA; - break; - } - return val; -} - - -static 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 = ram[addr]; - - return val; -} - - -static 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)) - ram[addr] = val; -} - - -static uint16_t -mem_read_scatw(uint32_t addr, void *priv) -{ - uint16_t val = 0xffff; - scat_t *stat = (scat_t *)priv; - - addr = get_scat_addr(addr, stat); - if (addr < (mem_size << 10)) - val = *(uint16_t *)&ram[addr]; - - return val; -} - - -static void -mem_write_scatw(uint32_t addr, uint16_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)) - *(uint16_t *)&ram[addr] = val; -} - - -static uint32_t -mem_read_scatl(uint32_t addr, void *priv) -{ - uint32_t val = 0xffffffff; - scat_t *stat = (scat_t *)priv; - - addr = get_scat_addr(addr, stat); - if (addr < (mem_size << 10)) - val = *(uint32_t *)&ram[addr]; - - return val; -} - - -static void -mem_write_scatl(uint32_t addr, uint32_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)) - *(uint32_t *)&ram[addr] = val; -} - - -static void -scat_init() -{ - int i; - - io_sethandler(0x0022, 0x0002, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - io_sethandler(0x0092, 0x0001, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - - for (i = 0; i < 256; i++) - scat_regs[i] = 0xff; - - scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; - switch(romset) { - case ROM_GW286CT: - case ROM_SPC4216P: - 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; - 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] = cpu_waitstates == 1 ? 2 : 0x12; - scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; - scat_regs[SCAT_EMS_CONTROL] = 0; - 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, 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++) - 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); - - 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_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; - - 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) & 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 = (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(); -} - - -static 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(); -} - - -void -machine_at_scat_init(const machine_t *model) -{ - machine_at_init(model); - device_add(&fdc_at_device); - - scat_init(); -} - - -void -machine_at_scatsx_init(const machine_t *model) -{ - machine_at_common_init(model); - - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); - - scatsx_init(); -} diff --git a/src/machine/m_at_sis_85c471.c b/src/machine/m_at_sis_85c471.c deleted file mode 100644 index fc511d7c6..000000000 --- a/src/machine/m_at_sis_85c471.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * Emulation of the SiS 85c471 chip. - * - * SiS sis85c471 Super I/O Chip - * Used by DTK PKM-0038S E-2 - * - * Version: @(#)m_at_sis85c471.c 1.0.10 2018/03/18 - * - * Author: Miran Grca, - * - * Copyright 2015-2018 Miran Grca. - */ -#include -#include -#include -#include -#include "../86box.h" -#include "../io.h" -#include "../memregs.h" -#include "../device.h" -#include "../lpt.h" -#include "../serial.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "machine.h" - - -static int sis_85c471_curreg; -static uint8_t sis_85c471_regs[39]; - - -static void sis_85c471_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t x; - - if (index) - { - if ((val >= 0x50) && (val <= 0x76)) sis_85c471_curreg = val; - return; - } - else - { - if ((sis_85c471_curreg < 0x50) || (sis_85c471_curreg > 0x76)) return; - x = val ^ sis_85c471_regs[sis_85c471_curreg - 0x50]; - /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ - if (sis_85c471_curreg != 0x52) sis_85c471_regs[sis_85c471_curreg - 0x50] = val; - goto process_value; - } - return; - -process_value: - switch(sis_85c471_curreg) - { - case 0x73: -#if 0 - if (x & 0x40) - { - if (val & 0x40) - ide_pri_enable(); - else - ide_pri_disable(); - } -#endif - - if (x & 0x20) - { - if (val & 0x20) - { - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); - } - else - { - serial_remove(1); - serial_remove(2); - } - } - - if (x & 0x10) - { - if (val & 0x10) - lpt1_init(0x378); - else - lpt1_remove(); - } - - break; - } - sis_85c471_curreg = 0; -} - - -static uint8_t sis_85c471_read(uint16_t port, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t temp; - - if (index) - return sis_85c471_curreg; - else - if ((sis_85c471_curreg >= 0x50) && (sis_85c471_curreg <= 0x76)) - { - temp = sis_85c471_regs[sis_85c471_curreg - 0x50]; - sis_85c471_curreg = 0; - return temp; - } - else - return 0xFF; -} - - -static void sis_85c471_init(void) -{ - int i = 0; - - lpt2_remove(); - - sis_85c471_curreg = 0; - for (i = 0; i < 0x27; i++) - { - sis_85c471_regs[i] = 0; - } - sis_85c471_regs[9] = 0x40; - switch (mem_size) - { - case 0: - case 1: - sis_85c471_regs[9] |= 0; - break; - case 2: - case 3: - sis_85c471_regs[9] |= 1; - break; - case 4: - sis_85c471_regs[9] |= 2; - break; - case 5: - sis_85c471_regs[9] |= 0x20; - break; - case 6: - case 7: - sis_85c471_regs[9] |= 9; - break; - case 8: - case 9: - sis_85c471_regs[9] |= 4; - break; - case 10: - case 11: - sis_85c471_regs[9] |= 5; - break; - case 12: - case 13: - case 14: - case 15: - sis_85c471_regs[9] |= 0xB; - break; - case 16: - sis_85c471_regs[9] |= 0x13; - break; - case 17: - sis_85c471_regs[9] |= 0x21; - break; - case 18: - case 19: - sis_85c471_regs[9] |= 6; - break; - case 20: - case 21: - case 22: - case 23: - sis_85c471_regs[9] |= 0xD; - break; - case 24: - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - sis_85c471_regs[9] |= 0xE; - break; - case 32: - case 33: - case 34: - case 35: - sis_85c471_regs[9] |= 0x1B; - break; - case 36: - case 37: - case 38: - case 39: - sis_85c471_regs[9] |= 0xF; - break; - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - sis_85c471_regs[9] |= 0x17; - break; - case 48: - sis_85c471_regs[9] |= 0x1E; - break; - default: - if (mem_size < 64) - { - sis_85c471_regs[9] |= 0x1E; - } - else if ((mem_size >= 65) && (mem_size < 68)) - { - sis_85c471_regs[9] |= 0x22; - } - else - { - sis_85c471_regs[9] |= 0x24; - } - break; - } - - sis_85c471_regs[0x11] = 9; - sis_85c471_regs[0x12] = 0xFF; - sis_85c471_regs[0x23] = 0xF0; - sis_85c471_regs[0x26] = 1; - - io_sethandler(0x0022, 0x0002, sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, NULL); -} - - -void -machine_at_dtk486_init(const machine_t *model) -{ - machine_at_ide_init(model); - device_add(&fdc_at_device); - - memregs_init(); - sis_85c471_init(); - secondary_ide_check(); -} diff --git a/src/machine/m_at_sis_85c496.c b/src/machine/m_at_sis_85c496.c deleted file mode 100644 index ca8ffd732..000000000 --- a/src/machine/m_at_sis_85c496.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of the SiS 85c496/85c497 chip. - * - * Version: @(#)m_at_sis_85c496.c 1.0.1 2018/04/26 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include "../86box.h" -#include "../cpu/cpu.h" -#include "../device.h" -#include "../keyboard.h" -#include "../io.h" -#include "../pci.h" -#include "../mem.h" -#include "../memregs.h" -#include "../sio.h" -#include "../disk/hdc.h" -#include "machine.h" - - -typedef struct sis_85c496_t -{ - uint8_t pci_conf[256]; -} sis_85c496_t; - - -static void -sis_85c496_recalcmapping(sis_85c496_t *dev) -{ - int c; - uint32_t base; - - for (c = 0; c < 8; c++) { - base = 0xc0000 + (c << 15); - if (dev->pci_conf[0x44] & (1 << c)) { - switch (dev->pci_conf[0x45] & 3) { - case 0: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 1: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - } - } else - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } - - flushmmucache(); - shadowbios = (dev->pci_conf[0x44] & 0xf0); -} - - -static void -sis_85c496_write(int func, int addr, uint8_t val, void *p) -{ - sis_85c496_t *dev = (sis_85c496_t *) p; - - switch (addr) { - case 0x44: /*Shadow configure*/ - if ((dev->pci_conf[0x44] & val) ^ 0xf0) { - dev->pci_conf[0x44] = val; - sis_85c496_recalcmapping(dev); - } - break; - case 0x45: /*Shadow configure*/ - if ((dev->pci_conf[0x45] & val) ^ 0x01) { - dev->pci_conf[0x45] = val; - sis_85c496_recalcmapping(dev); - } - break; - - case 0xc0: - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, val & 0xf); - else - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - break; - case 0xc1: - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, val & 0xf); - else - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - break; - case 0xc2: - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, val & 0xf); - else - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - break; - case 0xc3: - 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) - dev->pci_conf[addr] = val; -} - - -static uint8_t -sis_85c496_read(int func, int addr, void *p) -{ - sis_85c496_t *dev = (sis_85c496_t *) p; - - return dev->pci_conf[addr]; -} - - -static void -sis_85c496_reset(void *priv) -{ - uint8_t val = 0; - - val = sis_85c496_read(0, 0x44, priv); /* Read current value of 0x44. */ - sis_85c496_write(0, 0x44, val & 0xf, priv); /* Turn off shadow BIOS but keep the lower 4 bits. */ -} - - -static void -sis_85c496_close(void *p) -{ - sis_85c496_t *sis_85c496 = (sis_85c496_t *)p; - - free(sis_85c496); -} - - -static void -*sis_85c496_init(const device_t *info) -{ - sis_85c496_t *sis496 = malloc(sizeof(sis_85c496_t)); - memset(sis496, 0, sizeof(sis_85c496_t)); - - sis496->pci_conf[0x00] = 0x39; /*SiS*/ - sis496->pci_conf[0x01] = 0x10; - sis496->pci_conf[0x02] = 0x96; /*496/497*/ - sis496->pci_conf[0x03] = 0x04; - - sis496->pci_conf[0x04] = 7; - sis496->pci_conf[0x05] = 0; - - sis496->pci_conf[0x06] = 0x80; - sis496->pci_conf[0x07] = 0x02; - - sis496->pci_conf[0x08] = 2; /*Device revision*/ - - sis496->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - sis496->pci_conf[0x0a] = 0x00; - sis496->pci_conf[0x0b] = 0x06; - - sis496->pci_conf[0x0e] = 0x00; /*Single function device*/ - - pci_add_card(5, sis_85c496_read, sis_85c496_write, sis496); - - return sis496; -} - - -const device_t sis_85c496_device = -{ - "SiS 85c496/85c497", - DEVICE_PCI, - 0, - sis_85c496_init, - sis_85c496_close, - sis_85c496_reset, - NULL, - NULL, - NULL, - NULL -}; - - -static void -machine_at_sis_85c496_common_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - device_add(&ide_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x05, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); - - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - - device_add(&sis_85c496_device); -} - - -void -machine_at_r418_init(const machine_t *model) -{ - machine_at_sis_85c496_common_init(model); - - fdc37c665_init(); -} diff --git a/src/machine/m_at_sis_85c50x.c b/src/machine/m_at_sis_85c50x.c deleted file mode 100644 index d64ffa48a..000000000 --- a/src/machine/m_at_sis_85c50x.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * Emulation of the SiS 50x PCI chips. - * - * Version: @(#)m_at_sis_85c50x.c 1.0.7 2018/04/29 - * - * Author: Miran Grca, - * - * Copyright 2015-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include "../86box.h" -#include "../io.h" -#include "../pci.h" -#include "../mem.h" -#include "machine.h" - - -typedef struct sis_85c501_t -{ - uint8_t pci_conf[256]; - uint8_t turbo_reg; -} sis_85c501_t; - -sis_85c501_t sis_85c501; - -typedef struct sis_85c503_t -{ - uint8_t pci_conf[256]; -} sis_85c503_t; - -sis_85c503_t sis_85c503; - -typedef struct sis_85c50x_t -{ - uint8_t isa_conf[12]; - uint8_t reg; -} sis_85c50x_isa_t; - -sis_85c50x_isa_t sis_85c50x_isa; - - -static void sis_85c501_recalcmapping(void) -{ - int c, d; - - for (c = 0; c < 1; c++) - { - for (d = 0; d < 4; d++) - { - uint32_t base = 0xe0000 + (d << 14); - if (sis_85c501.pci_conf[0x54 + c] & (1 << (d + 4))) - { - switch (sis_85c501.pci_conf[0x53] & 0x60) - { - case 0x00: - mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 0x20: - mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 0x40: - mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - case 0x60: - mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - } - } - else - mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } - } - - flushmmucache(); - shadowbios = 1; -} - - -static void sis_85c501_write(int func, int addr, uint8_t val, void *p) -{ - 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 &= 0x42; - val |= 0x04; - break; - case 0x05: - val &= 0x01; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val = 0x02; - break; - - case 0x54: /*Shadow configure*/ - if ((sis_85c501.pci_conf[0x54] & val) ^ 0xf0) - { - sis_85c501.pci_conf[0x54] = val; - sis_85c501_recalcmapping(); - } - break; - } - - sis_85c501.pci_conf[addr] = val; -} - - -static void sis_85c503_write(int func, int addr, uint8_t val, void *p) -{ - if (func > 0) - return; - - if (addr >= 0x0f && addr < 0x41) - 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 0x41: - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTA, val & 0xf); - break; - case 0x42: - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTC, val & 0xf); - break; - case 0x43: - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTB, val & 0xf); - break; - case 0x44: - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTD, val & 0xf); - break; - } - - sis_85c503.pci_conf[addr] = val; -} - - -static void sis_85c50x_isa_write(uint16_t port, uint8_t val, void *priv) -{ - if (port & 1) - { - if (sis_85c50x_isa.reg <= 0xB) sis_85c50x_isa.isa_conf[sis_85c50x_isa.reg] = val; - } - else - { - sis_85c50x_isa.reg = val; - } -} - - -static uint8_t sis_85c501_read(int func, int addr, void *p) -{ - if (func) - return 0xff; - - return sis_85c501.pci_conf[addr]; -} - - -static uint8_t sis_85c503_read(int func, int addr, void *p) -{ - if (func > 0) - return 0xff; - - return sis_85c503.pci_conf[addr]; -} - - -static uint8_t sis_85c50x_isa_read(uint16_t port, void *priv) -{ - if (port & 1) - { - if (sis_85c50x_isa.reg <= 0xB) - return sis_85c50x_isa.isa_conf[sis_85c50x_isa.reg]; - else - return 0xff; - } - else - { - return sis_85c50x_isa.reg; - } -} - -static void sis_85c501_reset(void) -{ - memset(&sis_85c501, 0, sizeof(sis_85c501_t)); - sis_85c501.pci_conf[0x00] = 0x39; /*SiS*/ - sis_85c501.pci_conf[0x01] = 0x10; - sis_85c501.pci_conf[0x02] = 0x06; /*501/502*/ - sis_85c501.pci_conf[0x03] = 0x04; - - sis_85c501.pci_conf[0x04] = 7; - sis_85c501.pci_conf[0x05] = 0; - - sis_85c501.pci_conf[0x06] = 0x80; - sis_85c501.pci_conf[0x07] = 0x02; - - sis_85c501.pci_conf[0x08] = 0; /*Device revision*/ - - sis_85c501.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - sis_85c501.pci_conf[0x0a] = 0x00; - sis_85c501.pci_conf[0x0b] = 0x06; - - sis_85c501.pci_conf[0x0e] = 0x00; /*Single function device*/ - - sis_85c501.pci_conf[0x50] = 0xbc; - sis_85c501.pci_conf[0x51] = 0xfb; - sis_85c501.pci_conf[0x52] = 0xad; - sis_85c501.pci_conf[0x53] = 0xfe; - - shadowbios = 1; -} - -static void sis_85c501_init(void) -{ - pci_add_card(0, sis_85c501_read, sis_85c501_write, NULL); - - sis_85c501_reset(); - - pci_reset_handler.pci_master_reset = NULL; -} - -static void sis_85c503_reset(void) -{ - memset(&sis_85c503, 0, sizeof(sis_85c503_t)); - sis_85c503.pci_conf[0x00] = 0x39; /*SiS*/ - sis_85c503.pci_conf[0x01] = 0x10; - sis_85c503.pci_conf[0x02] = 0x08; /*503*/ - sis_85c503.pci_conf[0x03] = 0x00; - - sis_85c503.pci_conf[0x04] = 7; - sis_85c503.pci_conf[0x05] = 0; - - sis_85c503.pci_conf[0x06] = 0x80; - sis_85c503.pci_conf[0x07] = 0x02; - - sis_85c503.pci_conf[0x08] = 0; /*Device revision*/ - - sis_85c503.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - sis_85c503.pci_conf[0x0a] = 0x01; - sis_85c503.pci_conf[0x0b] = 0x06; - - sis_85c503.pci_conf[0x0e] = 0x00; /*Single function device*/ - - sis_85c503.pci_conf[0x41] = sis_85c503.pci_conf[0x42] = sis_85c503.pci_conf[0x43] = sis_85c503.pci_conf[0x44] = 0x80; -} - -static void sis_85c503_init(int card) -{ - - pci_add_card(card, sis_85c503_read, sis_85c503_write, NULL); - - sis_85c503_reset(); - - trc_init(); - - port_92_reset(); - - port_92_add(); - - pci_reset_handler.pci_set_reset = sis_85c503_reset; -} - - -static void sis_85c50x_isa_init(void) -{ - memset(&sis_85c50x_isa, 0, sizeof(sis_85c50x_isa_t)); - - io_sethandler(0x22, 0x0002, sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, NULL); -} diff --git a/src/machine/m_at_socket4_5.c b/src/machine/m_at_socket4_5.c new file mode 100644 index 000000000..de6312eeb --- /dev/null +++ b/src/machine/m_at_socket4_5.c @@ -0,0 +1,390 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Socket 4 and 5 machines. + * + * Version: @(#)m_at_socket4_5.c 1.0.1 2019/10/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../keyboard.h" +#include "../intel_flash.h" +#include "../intel_sio.h" +#include "../piix.h" +#include "../sio.h" +#include "../video/video.h" +#include "../video/vid_cl54xx.h" +#include "../video/vid_s3.h" +#include "machine.h" + + +static void +machine_at_premiere_common_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sio_zb_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_ami_device); +} + + +static void +machine_at_award_common_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 03 = Slot 1 */ + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 05 = Slot 3 */ + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 06 = Slot 4 */ + pci_register_slot(0x07, PCI_CARD_SCSI, 1, 2, 3, 4); /* 07 = SCSI */ + pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&fdc_at_device); + device_add(&keyboard_ps2_pci_device); + device_add(&sio_device); + device_add(&intel_flash_bxt_device); +} + + +int +machine_at_batman_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/revenge/1009af2_.bio", + L"roms/machines/revenge/1009af2_.bi1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model); + + device_add(&i430lx_device); + + return ret; +} + +int +machine_at_ambradp60_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/ambradp60/1004AF1P.BIO", + L"roms/machines/ambradp60/1004AF1P.BI1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model); + + device_add(&i430lx_device); + + return ret; +} + +int +machine_at_586mc1_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/586mc1/IS.34", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_award_common_init(model); + + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_plato_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/plato/1016ax1_.bio", + L"roms/machines/plato/1016ax1_.bi1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model); + + device_add(&i430nx_device); + + return ret; +} + +int +machine_at_ambradp90_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/ambradp90/1002AX1P.BIO", + L"roms/machines/ambradp90/1002AX1P.BI1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model); + + device_add(&i430nx_device); + + return ret; +} + +int +machine_at_430nx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/430nx/IP.20", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_award_common_init(model); + + device_add(&i430nx_device); + + return ret; +} + + +int +machine_at_p54tp4xe_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p54tp4xe/t15i0302.awd", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + /* Award BIOS, SMC FDC37C665. */ + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_endeavor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/endeavor/1006cb0_.bio", + L"roms/machines/endeavor/1006cb0_.bi1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_phoenix_trio64_onboard_pci_device); + + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +const device_t * +at_endeavor_get_device(void) +{ + return &s3_phoenix_trio64_onboard_pci_device; +} + + +int +machine_at_zappa_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/zappa/1006bs0_.bio", + L"roms/machines/zappa/1006bs0_.bi1", 0x20000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_mb500n_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/mb500n/031396s.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_president_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/president/bios.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877f_president_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_VECTRA54) +int +machine_at_vectra54_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/vectra54/GT0724.22", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c932qf_device); + device_add(&intel_flash_bxt_device); + + return ret; +} +#endif diff --git a/src/machine/m_at_socket7_s7.c b/src/machine/m_at_socket7_s7.c new file mode 100644 index 000000000..377a37bd5 --- /dev/null +++ b/src/machine/m_at_socket7_s7.c @@ -0,0 +1,453 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Socket 7 and Super Socket 7 machines. + * + * Version: @(#)m_at_socket7_s7.c 1.0.1 2019/10/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../keyboard.h" +#include "../intel_flash.h" +#include "../intel_sio.h" +#include "../piix.h" +#include "../sio.h" +#include "../video/video.h" +#include "../video/vid_cl54xx.h" +#include "../video/vid_s3.h" +#include "machine.h" + + +static void +machine_at_thor_common_init(const machine_t *model, int mr) +{ + machine_at_common_init_ex(model, mr); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); +} + + +int +machine_at_thor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/thor/1006cn0_.bio", + L"roms/machines/thor/1006cn0_.bi1", 0x20000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 0); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) +int +machine_at_mrthor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/mrthor/mr_atx.bio", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 1); + + return ret; +} +#endif + + +int +machine_at_pb640_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/pb640/1007CP0R.BIO", + L"roms/machines/pb640/1007CP0R.BI1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_pb640_device); + device_add(&piix_pb640_device); + device_add(&ide_isa_2ch_device); + + if (gfxcard == VID_INTERNAL) + device_add(&gd5440_onboard_pci_device); + + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +const device_t * +at_pb640_get_device(void) +{ + return &gd5440_onboard_pci_device; +} + + +int +machine_at_acerm3a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/acerm3a/r01-b3.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x10, PCI_CARD_ONBOARD, 4, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c932fr_device); + device_add(&acerm3a_device); + + device_add(&intel_flash_bxb_device); + + return ret; +} + + +int +machine_at_acerv35n_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/acerv35n/v35nd1s1.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c932fr_device); + device_add(&acerm3a_device); + + device_add(&intel_flash_bxb_device); + + return ret; +} + + +int +machine_at_ap53_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ap53/ap53r2c0.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_ONBOARD, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c669_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_p55t2p4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p55t2p4/0207_j2.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_p55t2s_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p55t2s/s6y08t.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +int +machine_at_tc430hx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined2(L"roms/machines/tc430hx/1007dh0_.bio", + L"roms/machines/tc430hx/1007dh0_.bi1", + L"roms/machines/tc430hx/1007dh0_.bi2", + L"roms/machines/tc430hx/1007dh0_.bi3", + L"roms/machines/tc430hx/1007dh0_.rcv", + 0x3a000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxtw_ami_device); + + return ret; +} +#endif + + +int +machine_at_p55tvp4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p55tvp4/tv5i0204.awd", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_i430vx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/430vx/55xwuq0e.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&um8669f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_p55va_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p55va/va021297.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c932fr_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_j656vxd_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/j656vxd/J656VXD.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c669_device); + device_add(&intel_flash_bxt_device); + + return ret; +} diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c new file mode 100644 index 000000000..18e4355c0 --- /dev/null +++ b/src/machine/m_at_socket8.c @@ -0,0 +1,107 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Socket 8 machines. + * + * Version: @(#)m_at_socket8.c 1.0.0 2019/05/16 + * + * Authors: Miran Grca, + * + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../keyboard.h" +#include "../intel_flash.h" +#include "../intel_sio.h" +#include "../piix.h" +#include "../sio.h" +#include "../video/video.h" +#include "../video/vid_cl54xx.h" +#include "../video/vid_s3.h" +#include "machine.h" + + +#if defined(DEV_BRANCH) && defined(USE_I686) + + +int +machine_at_i440fx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/440fx/ntmaw501.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i440fx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_s1668_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/tpatx/s1668p.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i440fx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +#endif diff --git a/src/machine/m_at_t3100e.c b/src/machine/m_at_t3100e.c index 6f62b7cf7..8f69fc951 100644 --- a/src/machine/m_at_t3100e.c +++ b/src/machine/m_at_t3100e.c @@ -117,7 +117,7 @@ * bit 2 set for single-pixel LCD font * bits 0,1 for display font * - * Version: @(#)m_at_t3100e.c 1.0.5 2018/04/29 + * Version: @(#)m_at_t3100e.c 1.0.6 2018/10/22 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -153,11 +153,13 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../io.h" #include "../mouse.h" #include "../mem.h" #include "../device.h" #include "../keyboard.h" +#include "../rom.h" #include "../cpu/cpu.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" @@ -215,13 +217,11 @@ void t3100e_ems_out(uint16_t addr, uint8_t val, void *p); #ifdef ENABLE_T3100E_LOG int t3100e_do_log = ENABLE_T3100E_LOG; -#endif static void t3100e_log(const char *fmt, ...) { -#ifdef ENABLE_T3100E_LOG va_list ap; if (t3100e_do_log) @@ -230,8 +230,10 @@ t3100e_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define t3100e_log(fmt, ...) +#endif /* Given a memory address (which ought to be in the page frame at 0xD0000), @@ -734,8 +736,16 @@ static void upper_write_raml(uint32_t addr, uint32_t val, void *priv) -void machine_at_t3100e_init(const machine_t *model) +int machine_at_t3100e_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/t3100e/t3100e.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + int pg; memset(&t3100e_ems, 0, sizeof(t3100e_ems)); @@ -779,4 +789,6 @@ void machine_at_t3100e_init(const machine_t *model) mem_mapping_disable(&t3100e_ems.upper_mapping); device_add(&t3100e_device); + + return ret; } diff --git a/src/machine/m_at_t3100e_vid.c b/src/machine/m_at_t3100e_vid.c index 55abf3149..683789a20 100644 --- a/src/machine/m_at_t3100e_vid.c +++ b/src/machine/m_at_t3100e_vid.c @@ -22,15 +22,15 @@ * 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 * - * Version: @(#)m_at_t3100e_vid.c 1.0.6 2018/04/29 + * Version: @(#)m_at_t3100e_vid.c 1.0.8 2019/10/01 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. * * 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 @@ -71,6 +71,9 @@ #define T3100E_XSIZE 640 #define T3100E_YSIZE 400 +/*Very rough estimate*/ +#define VID_CLOCK (double)(651 * 416 * 60) + /* Mapping of attributes to colours */ static uint32_t amber, black; @@ -117,7 +120,7 @@ typedef struct t3100e_t int internal; /* Using internal display? */ uint8_t attrmap; /* Attribute mapping register */ - int dispontime, dispofftime; + uint64_t dispontime, dispofftime; int linepos, displine; int vc; @@ -128,6 +131,8 @@ typedef struct t3100e_t uint8_t *vram; } t3100e_t; +static video_timings_t timing_t3100e = {VIDEO_ISA, 8,16,32, 8,16,32}; + void t3100e_recalctimings(t3100e_t *t3100e); void t3100e_write(uint32_t addr, uint8_t val, void *p); @@ -199,7 +204,7 @@ void t3100e_write(uint32_t addr, uint8_t val, void *p) egawrites++; t3100e->vram[addr & 0x7fff] = val; - cycles -= 4; + sub_cycles(4); } @@ -208,7 +213,7 @@ uint8_t t3100e_read(uint32_t addr, void *p) { t3100e_t *t3100e = (t3100e_t *)p; egareads++; - cycles -= 4; + sub_cycles(4); return t3100e->vram[addr & 0x7fff]; } @@ -228,8 +233,8 @@ void t3100e_recalctimings(t3100e_t *t3100e) disptime = 651; _dispontime = 640; _dispofftime = disptime - _dispontime; - t3100e->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - t3100e->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + t3100e->dispontime = (uint64_t)(_dispontime * (cpuclock / VID_CLOCK) * (double)(1ull << 32)); + t3100e->dispofftime = (uint64_t)(_dispofftime * (cpuclock / VID_CLOCK) * (double)(1ull << 32)); } @@ -523,7 +528,7 @@ void t3100e_poll(void *p) if (!t3100e->linepos) { - t3100e->cga.vidtime += t3100e->dispofftime; + timer_advance_u64(&t3100e->cga.timer, t3100e->dispofftime); t3100e->cga.cgastat |= 1; t3100e->linepos = 1; if (t3100e->dispon) @@ -570,19 +575,22 @@ void t3100e_poll(void *p) { t3100e->cga.cgastat &= ~1; } - t3100e->cga.vidtime += t3100e->dispontime; + 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) + if ((T3100E_XSIZE != xsize) || (T3100E_YSIZE != ysize) || video_force_resize_get()) { xsize = T3100E_XSIZE; ysize = T3100E_YSIZE; if (xsize < 64) xsize = 656; if (ysize < 32) ysize = 200; set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); } video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); @@ -707,14 +715,17 @@ void *t3100e_init(const device_t *info) { t3100e_t *t3100e = malloc(sizeof(t3100e_t)); memset(t3100e, 0, sizeof(t3100e_t)); + loadfont(L"roms/machines/t3100e/t3100e_font.bin", 5); cga_init(&t3100e->cga); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t3100e); t3100e->internal = 1; /* 32k video RAM */ t3100e->vram = malloc(0x8000); - timer_add(t3100e_poll, &t3100e->cga.vidtime, TIMER_ALWAYS_ENABLED, t3100e); + 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); diff --git a/src/machine/m_at_wd76c10.c b/src/machine/m_at_wd76c10.c deleted file mode 100644 index 670edb6d9..000000000 --- a/src/machine/m_at_wd76c10.c +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include -#include -#include "../86box.h" -#include "../device.h" -#include "../io.h" -#include "../keyboard.h" -#include "../mem.h" -#include "../serial.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../video/vid_paradise.h" -#include "machine.h" - - -static uint16_t wd76c10_0092; -static uint16_t wd76c10_2072; -static uint16_t wd76c10_2872; -static uint16_t wd76c10_5872; - - -static fdc_t *wd76c10_fdc; - - -static uint16_t -wd76c10_read(uint16_t port, void *priv) -{ - switch (port) - { - case 0x0092: - return wd76c10_0092; - - case 0x2072: - return wd76c10_2072; - - case 0x2872: - return wd76c10_2872; - - case 0x5872: - return wd76c10_5872; - } - return 0; -} - - -static void -wd76c10_write(uint16_t port, uint16_t val, void *priv) -{ - switch (port) - { - case 0x0092: - wd76c10_0092 = val; - - mem_a20_alt = val & 2; - mem_a20_recalc(); - break; - - case 0x2072: - wd76c10_2072 = val; - - serial_remove(1); - if (!(val & 0x10)) - { - switch ((val >> 5) & 7) - { - case 1: serial_setup(1, 0x3f8, 4); break; - case 2: serial_setup(1, 0x2f8, 4); break; - case 3: serial_setup(1, 0x3e8, 4); break; - case 4: serial_setup(1, 0x2e8, 4); break; - default: serial_remove(1); break; - } - } - serial_remove(2); - if (!(val & 0x01)) - { - switch ((val >> 1) & 7) - { - case 1: serial_setup(2, 0x3f8, 3); break; - case 2: serial_setup(2, 0x2f8, 3); break; - case 3: serial_setup(2, 0x3e8, 3); break; - case 4: serial_setup(2, 0x2e8, 3); break; - default: serial_remove(1); break; - } - } - break; - - case 0x2872: - wd76c10_2872 = val; - - fdc_remove(wd76c10_fdc); - if (!(val & 1)) - fdc_set_base(wd76c10_fdc, 0x03f0); - break; - - case 0x5872: - wd76c10_5872 = val; - break; - } -} - - -static uint8_t -wd76c10_readb(uint16_t port, void *priv) -{ - if (port & 1) - return wd76c10_read(port & ~1, priv) >> 8; - return wd76c10_read(port, priv) & 0xff; -} - - -static void -wd76c10_writeb(uint16_t port, uint8_t val, void *priv) -{ - uint16_t temp = wd76c10_read(port, priv); - if (port & 1) - wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv); - else - wd76c10_write(port , (temp & 0xff00) | val, priv); -} - - -static void wd76c10_init(void) -{ - io_sethandler(0x0092, 2, - wd76c10_readb, wd76c10_read, NULL, - wd76c10_writeb, wd76c10_write, NULL, NULL); - io_sethandler(0x2072, 2, - wd76c10_readb, wd76c10_read, NULL, - wd76c10_writeb, wd76c10_write, NULL, NULL); - io_sethandler(0x2872, 2, - wd76c10_readb, wd76c10_read, NULL, - wd76c10_writeb, wd76c10_write, NULL, NULL); - io_sethandler(0x5872, 2, - wd76c10_readb, wd76c10_read, NULL, - wd76c10_writeb, wd76c10_write, NULL, NULL); -} - - -void -machine_at_wd76c10_init(const machine_t *model) -{ - machine_at_common_ide_init(model); - - device_add(&keyboard_ps2_quadtel_device); - wd76c10_fdc = device_add(&fdc_at_device); - - wd76c10_init(); - - device_add(¶dise_wd90c11_megapc_device); -} diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c index 7e08d3109..04e464726 100644 --- a/src/machine/m_europc.c +++ b/src/machine/m_europc.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of the Schneider EuroPC system. * @@ -68,7 +68,7 @@ * * WARNING THIS IS A WORK-IN-PROGRESS MODULE. USE AT OWN RISK. * - * Version: @(#)europc.c 1.0.6 2018/04/29 + * Version: @(#)europc.c 1.0.12 2019/11/15 * * Author: Fred N. van Kempen, * @@ -77,37 +77,7 @@ * Schneider's schematics and technical manuals, and the * input from people with real EuroPC hardware. * - * Copyright 2017,2018 Fred N. van Kempen. - * - * 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 entire - * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT - * HOLDER 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. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -119,8 +89,10 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../nmi.h" #include "../mem.h" +#include "../pit.h" #include "../rom.h" #include "../device.h" #include "../nvr.h" @@ -163,6 +135,8 @@ typedef struct { nvr_t nvr; /* NVR */ uint8_t nvr_stat; uint8_t nvr_addr; + + void * mouse; } europc_t; @@ -171,13 +145,11 @@ static europc_t europc; #ifdef ENABLE_EUROPC_LOG int europc_do_log = ENABLE_EUROPC_LOG; -#endif static void europc_log(const char *fmt, ...) { -#ifdef ENABLE_EUROPC_LOG va_list ap; if (europc_do_log) @@ -186,8 +158,10 @@ europc_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define europc_log(fmt, ...) +#endif /* @@ -280,7 +254,7 @@ rtc_start(nvr_t *nvr) struct tm tm; /* Initialize the internal and chip times. */ - if (enable_sync) { + if (time_sync & TIME_SYNC_ENABLED) { /* Use the internal clock's time. */ nvr_time_get(&tm); rtc_time_set(nvr->regs, &tm); @@ -590,22 +564,14 @@ europc_boot(const device_t *info) * with values set by the user. */ b = (sys->nvr.regs[MRTC_CONF_D] & ~0x17); - switch(gfxcard) { - case GFX_CGA: /* Color, CGA */ - case GFX_COLORPLUS: /* Color, Hercules ColorPlus */ - b |= 0x12; /* external video, CGA80 */ - break; + video_reset(gfxcard); + if (video_is_cga()) + b |= 0x12; /* external video, CGA80 */ + else if (video_is_mda()) + b |= 0x03; /* external video, mono */ + else + b |= 0x10; /* external video, special */ - case GFX_MDA: /* Monochrome, MDA */ - case GFX_HERCULES: /* Monochrome, Hercules */ - case GFX_INCOLOR: /* Color, ? */ - b |= 0x03; /* external video, mono */ - break; - - default: /* EGA, VGA etc */ - b |= 0x10; /* external video, special */ - - } sys->nvr.regs[MRTC_CONF_D] = b; /* Update the memory size. */ @@ -644,12 +610,13 @@ europc_boot(const device_t *info) /* Set up game port. */ b = (sys->nvr.regs[MRTC_CONF_C] & 0xfc); - if (mouse_type == MOUSE_TYPE_LOGIBUS) { - b |= 0x01; /* enable port as MOUSE */ - } else if (joystick_type != 7) { + if (mouse_type == MOUSE_TYPE_INTERNAL) { + sys->mouse = device_add(&mouse_logibus_onboard_device); + mouse_bus_set_irq(sys->mouse, 2); + /* Configure the port for (Bus Mouse Compatible) Mouse. */ + b |= 0x01; + } else if (joystick_type != 7) b |= 0x02; /* enable port as joysticks */ - device_add(&gameport_device); - } sys->nvr.regs[MRTC_CONF_C] = b; #if 0 @@ -738,18 +705,26 @@ const device_t europc_device = { * allows it to reset (dev init) and configured by the * user. */ -void +int machine_europc_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/europc/50145", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + machine_common_init(model); + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + nmi_init(); /* Clear the machine state. */ memset(&europc, 0x00, sizeof(europc_t)); europc.jim = 0x0250; - mem_add_bios(); - /* This is machine specific. */ europc.nvr.size = model->nvrmask + 1; europc.nvr.irq = -1; @@ -764,4 +739,6 @@ machine_europc_init(const machine_t *model) /* Enable and set up the mainboard device. */ device_add(&europc_device); + + return ret; } diff --git a/src/machine/m_olivetti_m24.c b/src/machine/m_olivetti_m24.c index 57a28d7ea..694fec24c 100644 --- a/src/machine/m_olivetti_m24.c +++ b/src/machine/m_olivetti_m24.c @@ -8,15 +8,15 @@ * * Emulation of the Olivetti M24. * - * Version: @(#)m_olivetti_m24.c 1.0.14 2018/04/26 + * Version: @(#)m_olivetti_m24.c 1.0.21 2019/11/15 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -25,17 +25,18 @@ #include #include #include "../86box.h" +#include "../timer.h" #include "../io.h" #include "../pic.h" #include "../pit.h" #include "../ppi.h" #include "../nmi.h" #include "../mem.h" -#include "../timer.h" #include "../device.h" #include "../nvr.h" #include "../keyboard.h" #include "../mouse.h" +#include "../rom.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../game/gameport.h" @@ -70,13 +71,13 @@ typedef struct { int linepos, displine; int sc, vc; int con, coff, cursoron, blink; - int64_t vsynctime; + int vsynctime; int vadj; int lineff; uint16_t ma, maback; int dispon; - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; /* Keyboard stuff. */ @@ -93,8 +94,11 @@ typedef struct { /* Mouse stuff. */ int mouse_mode; int x, y, b; + pc_timer_t send_delay_timer; } olim24_t; +static video_timings_t timing_m24 = {VIDEO_ISA, 8,16,32, 8,16,32}; + static uint8_t crtcmask[32] = { 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, @@ -110,13 +114,11 @@ static int key_queue_start = 0, #ifdef ENABLE_M24VID_LOG int m24vid_do_log = ENABLE_M24VID_LOG; -#endif static void m24_log(const char *fmt, ...) { -#ifdef ENABLE_M24VID_LOG va_list ap; if (m24vid_do_log) { @@ -125,9 +127,12 @@ m24_log(const char *fmt, ...) va_end(ap); fflush(stdlog); } +} +#else +#define m24_log(fmt, ...) #endif -} - + + static void recalc_timings(olim24_t *m24) { @@ -144,8 +149,8 @@ recalc_timings(olim24_t *m24) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST / 2; _dispofftime *= CGACONST / 2; - m24->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - m24->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + m24->dispontime = (uint64_t)(_dispontime); + m24->dispofftime = (uint64_t)(_dispofftime); } @@ -231,10 +236,12 @@ static void vid_write(uint32_t addr, uint8_t val, void *priv) { olim24_t *m24 = (olim24_t *)priv; + int offset; 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; + offset = ((timer_get_remaining_u64(&m24->timer) / CGACONST) * 4) & 0xfc; + m24->charbuffer[offset] = m24->vram[addr & 0x7fff]; + m24->charbuffer[offset | 1] = m24->vram[addr & 0x7fff]; } @@ -253,7 +260,7 @@ vid_poll(void *priv) olim24_t *m24 = (olim24_t *)priv; uint16_t ca = (m24->crtc[15] | (m24->crtc[14] << 8)) & 0x3fff; int drawcursor; - int x, c; + int x, c, xs_temp, ys_temp; int oldvc; uint8_t chr, attr; uint16_t dat, dat2; @@ -262,7 +269,7 @@ vid_poll(void *priv) int oldsc; if (!m24->linepos) { - m24->vidtime += m24->dispofftime; + timer_advance_u64(&m24->timer, m24->dispofftime); m24->stat |= 1; m24->linepos = 1; oldsc = m24->sc; @@ -276,17 +283,17 @@ vid_poll(void *priv) for (c = 0; c < 8; c++) { if ((m24->cgamode & 0x12) == 0x12) { - buffer->line[m24->displine][c] = 0; + ((uint32_t *)buffer32->line[m24->displine])[c] = 0; if (m24->cgamode & 1) - buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = 0; + ((uint32_t *)buffer32->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 + (m24->crtc[1] << 4) + 8] = 0; } else { - buffer->line[m24->displine][c] = (m24->cgacol & 15) + 16; + ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->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 + (m24->crtc[1] << 4) + 8] = (m24->cgacol & 15) + 16; } } if (m24->cgamode & 1) { @@ -305,10 +312,10 @@ vid_poll(void *priv) } 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] ^ 15; } else { for (c = 0; c < 8; c++) - buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + ((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++; } @@ -329,12 +336,12 @@ vid_poll(void *priv) 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] ^ 15; } else { for (c = 0; c < 8; c++) - buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = - buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + ((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)) { @@ -358,8 +365,8 @@ vid_poll(void *priv) m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + 1 + m24->base]; m24->ma++; for (c = 0; c < 8; c++) { - buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = - buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + ((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; } } @@ -376,15 +383,15 @@ vid_poll(void *priv) dat = (m24->vram[((m24->ma << 1) & 0x1fff) + dat2] << 8) | m24->vram[((m24->ma << 1) & 0x1fff) + dat2 + 1]; m24->ma++; for (c = 0; c < 16; c++) { - buffer->line[m24->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } } } else { cols[0] = ((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15) + 16; - if (m24->cgamode & 1) hline(buffer, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]); - else hline(buffer, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]); + if (m24->cgamode & 1) 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) @@ -398,7 +405,7 @@ vid_poll(void *priv) m24->displine++; if (m24->displine >= 720) m24->displine = 0; } else { - m24->vidtime += m24->dispontime; + timer_advance_u64(&m24->timer, m24->dispontime); if (m24->dispon) m24->stat &= ~1; m24->linepos = 0; m24->lineff ^= 1; @@ -455,21 +462,36 @@ vid_poll(void *priv) else x = (m24->crtc[1] << 4) + 16; m24->lastline++; - if ((x != xsize) || ((m24->lastline - m24->firstline) != ysize) || video_force_resize_get()) { - xsize = x; - ysize = m24->lastline - m24->firstline; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, ysize + 16); - if (video_force_resize_get()) - video_force_resize_set(0); + xs_temp = x; + ys_temp = (m24->lastline - m24->firstline); + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xsize < 64) xs_temp = 656; + if (ysize < 32) ys_temp = 200; + if (!enable_overscan) + xs_temp -= 16; + + if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan) { + video_blit_memtoscreen_8(0, m24->firstline - 8, 0, (m24->lastline - m24->firstline) + 16, + xsize, (m24->lastline - m24->firstline) + 16); + } else + video_blit_memtoscreen_8(8, m24->firstline, 0, (m24->lastline - m24->firstline), + xsize, (m24->lastline - m24->firstline)); } - video_blit_memtoscreen_8(0, m24->firstline - 8, 0, (m24->lastline - m24->firstline) + 16, xsize, (m24->lastline - m24->firstline) + 16); frames++; - video_res_x = xsize - 16; + video_res_x = xsize; video_res_y = ysize; if (m24->cgamode & 1) { video_res_x /= 8; @@ -522,7 +544,7 @@ kbd_poll(void *priv) { olim24_t *m24 = (olim24_t *)priv; - keyboard_delay += (1000LL * TIMER_USEC); + timer_advance_u64(&m24->send_delay_timer, 1000 * TIMER_USEC); if (m24->wantirq) { m24->wantirq = 0; picint(2); @@ -631,15 +653,12 @@ kbd_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); + pit_ctr_set_gate(&pit->counters[2], val & 1); break; } } @@ -800,9 +819,39 @@ const device_t m24_device = { }; -void +static void +kbd_reset(void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + + /* Initialize the keyboard. */ + m24->status = STAT_LOCK | STAT_CD; + m24->wantirq = 0; + keyboard_scan = 1; + m24->param = m24->param_total = 0; + m24->mouse_mode = 0; + m24->scan[0] = 0x1c; + m24->scan[1] = 0x53; + m24->scan[2] = 0x01; + m24->scan[3] = 0x4b; + m24->scan[4] = 0x4d; + m24->scan[5] = 0x48; + m24->scan[6] = 0x50; +} + + +int machine_olim24_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_low.bin", + L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_high.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + olim24_t *m24; m24 = (olim24_t *)malloc(sizeof(olim24_t)); @@ -814,37 +863,35 @@ machine_olim24_init(const machine_t *model) io_sethandler(0x0066, 2, m24_read, NULL, NULL, NULL, NULL, NULL, m24); /* Initialize the video adapter. */ + // loadfont(L"roms/machines/olivetti_m24/ATT-FONT-DUMPED-VERIFIED.BIN", 1); + loadfont(L"roms/machines/olivetti_m24/m24 graphics board go380 258 pqbq.bin", 1); m24->vram = malloc(0x8000); overscan_x = overscan_y = 16; mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, m24); io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); - timer_add(vid_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24); + timer_add(&m24->timer, vid_poll, m24, 1); device_add_ex(&m24_device, m24); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_m24); + cga_palette = 0; + cgapal_rebuild(); /* Initialize the keyboard. */ - m24->status = STAT_LOCK | STAT_CD; - m24->scan[0] = 0x1c; - m24->scan[1] = 0x53; - m24->scan[2] = 0x01; - m24->scan[3] = 0x4b; - m24->scan[4] = 0x4d; - m24->scan[5] = 0x48; - m24->scan[6] = 0x50; io_sethandler(0x0060, 2, kbd_read, NULL, NULL, kbd_write, NULL, NULL, m24); io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, m24); - keyboard_set_table(scancode_xt); keyboard_send = kbd_adddata_ex; - keyboard_scan = 1; - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, m24); + kbd_reset(m24); + timer_add(&m24->send_delay_timer, kbd_poll, m24, 1); /* Tell mouse driver about our internal mouse. */ mouse_reset(); mouse_set_poll(ms_poll, m24); + keyboard_set_table(scancode_xt); + if (joystick_type != 7) device_add(&gameport_device); @@ -852,23 +899,6 @@ machine_olim24_init(const machine_t *model) device_add(&at_nvr_device); nmi_init(); -} - -void machine_olim24_video_init(void) { - olim24_t *m24; - - m24 = (olim24_t *)malloc(sizeof(olim24_t)); - memset(m24, 0x00, sizeof(olim24_t)); - - /* Initialize the video adapter. */ - m24->vram = malloc(0x8000); - overscan_x = overscan_y = 16; - mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, - vid_read, NULL, NULL, - vid_write, NULL, NULL, NULL, 0, m24); - io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); - io_sethandler(0x13c6, 1, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); - io_sethandler(0x23c6, 1, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); - timer_add(vid_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24); - device_add_ex(&m24_device, m24); + + return ret; } diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 52979f72e..a5ff9cc8b 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -8,15 +8,15 @@ * * Emulation of the IBM PCjr. * - * Version: @(#)m_pcjr.c 1.0.8 2018/04/29 + * Version: @(#)m_pcjr.c 1.0.14 2019/11/15 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -27,15 +27,17 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" #include "../io.h" #include "../nmi.h" #include "../pic.h" #include "../pit.h" #include "../mem.h" -#include "../timer.h" #include "../device.h" #include "../serial.h" #include "../keyboard.h" +#include "../rom.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../sound/sound.h" @@ -76,10 +78,11 @@ typedef struct { int sc, vc; int dispon; int con, coff, cursoron, blink; - int64_t vsynctime; + int vsynctime; int vadj; uint16_t ma, maback; - int64_t dispontime, dispofftime, vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; int composite; @@ -90,8 +93,11 @@ typedef struct { int serial_pos; uint8_t pa; uint8_t pb; + pc_timer_t send_delay_timer; } pcjr_t; +static video_timings_t timing_dram = {VIDEO_BUS, 0,0,0, 0,0,0}; /*No additional waitstates*/ + static uint8_t crtcmask[32] = { 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, @@ -133,8 +139,8 @@ recalc_timings(pcjr_t *pcjr) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST; _dispofftime *= CGACONST; - pcjr->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - pcjr->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + pcjr->dispontime = (uint64_t)(_dispontime); + pcjr->dispofftime = (uint64_t)(_dispofftime); } @@ -238,7 +244,7 @@ vid_poll(void *p) pcjr_t *pcjr = (pcjr_t *)p; uint16_t ca = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; int drawcursor; - int x, c; + int x, c, xs_temp, ys_temp; int oldvc; uint8_t chr, attr; uint16_t dat; @@ -246,7 +252,7 @@ vid_poll(void *p) int oldsc; if (! pcjr->linepos) { - pcjr->vidtime += pcjr->dispofftime; + timer_advance_u64(&pcjr->timer, pcjr->dispofftime); pcjr->stat &= ~1; pcjr->linepos = 1; oldsc = pcjr->sc; @@ -263,11 +269,14 @@ vid_poll(void *p) pcjr->lastline = pcjr->displine; cols[0] = (pcjr->array[2] & 0xf) + 16; for (c = 0; c < 8; c++) { - buffer->line[pcjr->displine][c] = cols[0]; - if (pcjr->array[0] & 1) - buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 3) + 8] = cols[0]; - else - buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 4) + 8] = cols[0]; + ((uint32_t *)buffer32->line[pcjr->displine])[c] = cols[0]; + if (pcjr->array[0] & 1) { + buffer32->line[(pcjr->displine << 1)][c + (pcjr->crtc[1] << 3) + 8] = + buffer32->line[(pcjr->displine << 1) + 1][c + (pcjr->crtc[1] << 3) + 8] = cols[0]; + } else { + buffer32->line[(pcjr->displine << 1)][c + (pcjr->crtc[1] << 4) + 8] = + buffer32->line[(pcjr->displine << 1) + 1][c + (pcjr->crtc[1] << 4) + 8] = cols[0]; + } } switch (pcjr->addr_mode) { @@ -288,14 +297,18 @@ vid_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; + buffer32->line[(pcjr->displine << 1)][(x << 3) + 8] = buffer32->line[(pcjr->displine << 1)][(x << 3) + 9] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + 8] = buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + 9] = + pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer32->line[(pcjr->displine << 1)][(x << 3) + 10] = buffer32->line[(pcjr->displine << 1)][(x << 3) + 11] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + 10] = buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + 11] = + pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer32->line[(pcjr->displine << 1)][(x << 3) + 12] = buffer32->line[(pcjr->displine << 1)][(x << 3) + 13] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + 12] = buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + 13] = + pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer32->line[(pcjr->displine << 1)][(x << 3) + 14] = buffer32->line[(pcjr->displine << 1)][(x << 3) + 15] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + 14] = buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + 15] = + pcjr->array[(dat & pcjr->array[1]) + 16] + 16; } break; case 0x12: /*160x200x16*/ @@ -303,22 +316,26 @@ vid_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; + buffer32->line[(pcjr->displine << 1)][(x << 4) + 8] = buffer32->line[(pcjr->displine << 1)][(x << 4) + 9] = + buffer32->line[(pcjr->displine << 1)][(x << 4) + 10] = buffer32->line[(pcjr->displine << 1)][(x << 4) + 11] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 8] = buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 9] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 10] = buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 11] = + pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer32->line[(pcjr->displine << 1)][(x << 4) + 12] = buffer32->line[(pcjr->displine << 1)][(x << 4) + 13] = + buffer32->line[(pcjr->displine << 1)][(x << 4) + 14] = buffer32->line[(pcjr->displine << 1)][(x << 4) + 15] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 12] = buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 13] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 14] = buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 15] = + pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer32->line[(pcjr->displine << 1)][(x << 4) + 16] = buffer32->line[(pcjr->displine << 1)][(x << 4) + 17] = + buffer32->line[(pcjr->displine << 1)][(x << 4) + 18] = buffer32->line[(pcjr->displine << 1)][(x << 4) + 19] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 16] = buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 17] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 18] = buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 19] = + pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer32->line[(pcjr->displine << 1)][(x << 4) + 20] = buffer32->line[(pcjr->displine << 1)][(x << 4) + 21] = + buffer32->line[(pcjr->displine << 1)][(x << 4) + 22] = buffer32->line[(pcjr->displine << 1)][(x << 4) + 23] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 20] = buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 21] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 22] = buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + 23] = + pcjr->array[(dat & pcjr->array[1]) + 16] + 16; } break; case 0x03: /*640x200x4*/ @@ -329,7 +346,8 @@ vid_poll(void *p) for (c = 0; c < 8; c++) { chr = (dat >> 7) & 1; chr |= ((dat >> 14) & 2); - buffer->line[pcjr->displine][(x << 3) + 8 + c] = pcjr->array[(chr & pcjr->array[1]) + 16] + 16; + buffer32->line[(pcjr->displine << 1)][(x << 3) + 8 + c] = buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + 8 + c] = + pcjr->array[(chr & pcjr->array[1]) + 16] + 16; dat <<= 1; } } @@ -349,15 +367,22 @@ vid_poll(void *p) cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16] + 16; } if (pcjr->sc & 8) { - for (c = 0; c < 8; c++) - buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[0]; + for (c = 0; c < 8; c++) { + buffer32->line[(pcjr->displine << 1)][(x << 3) + c + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(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]; + for (c = 0; c < 8; c++) { + buffer32->line[(pcjr->displine << 1)][(x << 3) + c + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } } if (drawcursor) { - for (c = 0; c < 8; c++) - buffer->line[pcjr->displine][(x << 3) + c + 8] ^= 15; + for (c = 0; c < 8; c++) { + buffer32->line[(pcjr->displine << 1)][(x << 3) + c + 8] ^= 15; + buffer32->line[(pcjr->displine << 1) + 1][(x << 3) + c + 8] ^= 15; + } } pcjr->ma++; } @@ -378,17 +403,26 @@ vid_poll(void *p) } 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]; + for (c = 0; c < 8; c++) { + buffer32->line[(pcjr->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(pcjr->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(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]; + for (c = 0; c < 8; c++) { + buffer32->line[(pcjr->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(pcjr->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(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; + for (c = 0; c < 16; c++) { + buffer32->line[(pcjr->displine << 1)][(x << 4) + c + 8] ^= 15; + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + c + 8] ^= 15; + } } } break; @@ -402,8 +436,10 @@ vid_poll(void *p) pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; pcjr->ma++; for (c = 0; c < 8; c++) { - buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = - buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + buffer32->line[(pcjr->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(pcjr->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } @@ -416,7 +452,9 @@ vid_poll(void *p) pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; pcjr->ma++; for (c = 0; c < 16; c++) { - buffer->line[pcjr->displine][(x << 4) + c + 8] = cols[dat >> 15]; + buffer32->line[(pcjr->displine << 1)][(x << 4) + c + 8] = + buffer32->line[(pcjr->displine << 1) + 1][(x << 4) + c + 8] = + cols[dat >> 15]; dat <<= 1; } } @@ -424,21 +462,29 @@ vid_poll(void *p) } } else { if (pcjr->array[3] & 4) { - if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, (pcjr->array[2] & 0xf) + 16); - else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, (pcjr->array[2] & 0xf) + 16); + if (pcjr->array[0] & 1) { + hline(buffer32, 0, (pcjr->displine << 1), (pcjr->crtc[1] << 3) + 16, (pcjr->array[2] & 0xf) + 16); + hline(buffer32, 0, (pcjr->displine << 1) + 1, (pcjr->crtc[1] << 3) + 16, (pcjr->array[2] & 0xf) + 16); + } else { + hline(buffer32, 0, (pcjr->displine << 1), (pcjr->crtc[1] << 4) + 16, (pcjr->array[2] & 0xf) + 16); + hline(buffer32, 0, (pcjr->displine << 1) + 1, (pcjr->crtc[1] << 4) + 16, (pcjr->array[2] & 0xf) + 16); + } } else { cols[0] = pcjr->array[0 + 16] + 16; - if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, cols[0]); - else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, cols[0]); + if (pcjr->array[0] & 1) { + hline(buffer32, 0, (pcjr->displine << 1), (pcjr->crtc[1] << 3) + 16, cols[0]); + hline(buffer32, 0, (pcjr->displine << 1) + 1, (pcjr->crtc[1] << 3) + 16, cols[0]); + } else { + hline(buffer32, 0, (pcjr->displine << 1), (pcjr->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, (pcjr->displine << 1) + 1, (pcjr->crtc[1] << 4) + 16, cols[0]); + } } } if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; else x = (pcjr->crtc[1] << 4) + 16; if (pcjr->composite) { - for (c = 0; c < x; c++) - buffer32->line[pcjr->displine][c] = buffer->line[pcjr->displine][c] & 0xf; - - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[pcjr->displine]); + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[(pcjr->displine << 1)]); + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[(pcjr->displine << 1) + 1]); } pcjr->sc = oldsc; if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) { @@ -448,7 +494,7 @@ vid_poll(void *p) if (pcjr->displine >= 360) pcjr->displine = 0; } else { - pcjr->vidtime += pcjr->dispontime; + timer_advance_u64(&pcjr->timer, pcjr->dispontime); if (pcjr->dispon) pcjr->stat |= 1; pcjr->linepos = 0; @@ -499,24 +545,44 @@ vid_poll(void *p) if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; else x = (pcjr->crtc[1] << 4) + 16; pcjr->lastline++; - if ((x != xsize) || ((pcjr->lastline - pcjr->firstline) != ysize) || video_force_resize_get()) { - xsize = x; - ysize = pcjr->lastline - pcjr->firstline; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, (ysize << 1) + 16); - if (video_force_resize_get()) - video_force_resize_set(0); + xs_temp = x; + ys_temp = (pcjr->lastline - pcjr->firstline) << 1; + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xs_temp < 64) xs_temp = 656; + if (ys_temp < 32) ys_temp = 400; + if (!enable_overscan) + xs_temp -= 16; + + if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan) { + if (pcjr->composite) + video_blit_memtoscreen(0, (pcjr->firstline - 4) << 1, 0, ((pcjr->lastline - pcjr->firstline) + 8) << 1, + xsize, ((pcjr->lastline - pcjr->firstline) + 8) << 1); + else + video_blit_memtoscreen_8(0, (pcjr->firstline - 4) << 1, 0, ((pcjr->lastline - pcjr->firstline) + 8) << 1, + xsize, ((pcjr->lastline - pcjr->firstline) + 8) << 1); + } else { + if (pcjr->composite) + video_blit_memtoscreen(8, pcjr->firstline << 1, 0, (pcjr->lastline - pcjr->firstline) << 1, + xsize, (pcjr->lastline - pcjr->firstline) << 1); + else + video_blit_memtoscreen_8(8, pcjr->firstline << 1, 0, (pcjr->lastline - pcjr->firstline) << 1, + xsize, (pcjr->lastline - pcjr->firstline) << 1); + } } - 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, 0, (pcjr->lastline - pcjr->firstline) + 8, xsize, (pcjr->lastline - pcjr->firstline) + 8); - frames++; - video_res_x = xsize - 16; + video_res_x = xsize; video_res_y = ysize; } pcjr->firstline = 1000; @@ -539,6 +605,9 @@ kbd_write(uint16_t port, uint8_t val, void *priv) { pcjr_t *pcjr = (pcjr_t *)priv; + if ((port >= 0xa0) && (port <= 0xa7)) + port = 0xa0; + switch (port) { case 0x60: pcjr->pa = val; @@ -547,15 +616,12 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0x61: pcjr->pb = val; - timer_process(); - timer_update_outstanding(); - speaker_update(); speaker_gated = val & 1; speaker_enable = val & 2; if (speaker_enable) was_speaker_enable = 1; - pit_set_gate(&pit, 2, val & 1); + pit_ctr_set_gate(&pit->counters[2], val & 1); sn76489_mute = speaker_mute = 1; switch (val & 0x60) { case 0x00: @@ -570,7 +636,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0xa0: nmi_mask = val & 0x80; - pit_set_using_timer(&pit, 1, !(val & 0x20)); + pit_ctr_set_using_timer(&pit->counters[1], !(val & 0x20)); break; } } @@ -582,6 +648,9 @@ kbd_read(uint16_t port, void *priv) pcjr_t *pcjr = (pcjr_t *)priv; uint8_t ret = 0xff; + if ((port >= 0xa0) && (port <= 0xa7)) + port = 0xa0; + switch (port) { case 0x60: ret = pcjr->pa; @@ -617,7 +686,7 @@ kbd_poll(void *priv) pcjr_t *pcjr = (pcjr_t *)priv; int c, p = 0, key; - keyboard_delay += (220LL * TIMER_USEC); + timer_advance_u64(&pcjr->send_delay_timer, 220 * TIMER_USEC); if (key_queue_start != key_queue_end && !pcjr->serial_pos && !pcjr->latched) { @@ -731,47 +800,64 @@ pcjr_get_device(void) } -void +int machine_pcjr_init(const machine_t *model) { int display_type; pcjr_t *pcjr; + int ret; + + ret = bios_load_linear(L"roms/machines/ibmpcjr/bios.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + pcjr = malloc(sizeof(pcjr_t)); memset(pcjr, 0x00, sizeof(pcjr_t)); pcjr->memctrl = -1; display_type = machine_get_config_int("display_type"); pcjr->composite = (display_type != PCJR_RGB); - pic_init(); - pit_init(); - pit_set_out_func(&pit, 0, pit_irq0_timer_pcjr); + pic_init_pcjr(); + pit_common_init(0, pit_irq0_timer_pcjr, NULL); - if (serial_enabled[0]) - serial_setup(1, 0x2f8, 3); + cpu_set(); /* Initialize the video controller. */ + loadfont(L"roms/video/mda/mda.rom", 0); mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, pcjr); io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, pcjr); - timer_add(vid_poll, &pcjr->vidtime, TIMER_ALWAYS_ENABLED, pcjr); + timer_add(&pcjr->timer, vid_poll, pcjr, 1); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); device_add_ex(&pcjr_device, pcjr); + cga_palette = 0; + cgapal_rebuild(); /* Initialize the keyboard. */ + keyboard_scan = 1; key_queue_start = key_queue_end = 0; io_sethandler(0x0060, 4, kbd_read, NULL, NULL, kbd_write, NULL, NULL, pcjr); io_sethandler(0x00a0, 8, kbd_read, NULL, NULL, kbd_write, NULL, NULL, pcjr); - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, pcjr); + timer_add(&pcjr->send_delay_timer, kbd_poll, pcjr, 1); keyboard_set_table(scancode_xt); keyboard_send = kbd_adddata_ex; - device_add(&sn76489_device); + /* Technically it's the SN76496N, but the NCR 8496 is a drop-in replacement for it. */ + device_add(&ncr8496_device); nmi_mask = 0x80; device_add(&fdc_pcjr_device); + + device_add(&i8250_pcjr_device); + serial_set_next_inst(2); /* So that serial_standalone_init() won't do anything. */ + + return ret; } diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 46086b9a6..2bfd6e7f7 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -22,21 +22,15 @@ * The reserved 384K is remapped to the top of extended memory. * If this is not done then you get an error on startup. * - * NOTES: Floppy does not seem to work. --FvK - * The "ROM DOS" shell does not seem to work. We do have the - * correct BIOS images now, and they do load, but they do not - * boot. Sometimes, they do, and then it shows an "Incorrect - * DOS" error message?? --FvK - * - * Version: @(#)m_ps1.c 1.0.9 2018/04/26 + * Version: @(#)m_ps1.c 1.0.17 2019/11/15 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -45,6 +39,7 @@ #include #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../io.h" #include "../dma.h" #include "../pic.h" @@ -52,7 +47,6 @@ #include "../mem.h" #include "../nmi.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "../nvr.h" #include "../game/gameport.h" @@ -74,7 +68,9 @@ typedef struct { sn76489_t sn76489; uint8_t status, ctrl; - int64_t timer_latch, timer_count, timer_enable; + uint64_t timer_latch; + pc_timer_t timer_count; + int timer_enable; uint8_t fifo[2048]; int fifo_read_idx, fifo_write_idx; int fifo_threshold; @@ -98,6 +94,8 @@ typedef struct { ps1_190; int ps1_e0_addr; uint8_t ps1_e0_regs[256]; + + serial_t *uart; } ps1_t; @@ -175,8 +173,10 @@ snd_write(uint16_t port, uint8_t val, void *priv) case 3: /* timer reload value */ snd->timer_latch = val; - snd->timer_count = (int64_t) ((0xff-val) * TIMER_USEC); - snd->timer_enable = (val != 0); + if (val) + timer_set_delay_u64(&snd->timer_count, ((0xff-val) * TIMER_USEC)); + else + timer_disable(&snd->timer_count); break; case 4: /* almost empty */ @@ -211,8 +211,8 @@ snd_callback(void *priv) snd->status |= 0x10; /*ADC data ready*/ update_irq_status(snd); - - snd->timer_count += snd->timer_latch * TIMER_USEC; + + timer_advance_u64(&snd->timer_count, snd->timer_latch * TIMER_USEC); } @@ -244,7 +244,7 @@ snd_init(const device_t *info) io_sethandler(0x0200, 1, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); io_sethandler(0x0202, 6, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); - timer_add(snd_callback, &snd->timer_count, &snd->timer_enable, snd); + timer_add(&snd->timer_count, snd_callback, snd, 0); sound_add_handler(snd_get_buffer, snd); @@ -278,13 +278,13 @@ recalc_memory(ps1_t *ps) mem_set_mem_state(0x00000, 0x80000, (ps->ps1_e0_regs[0] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : - (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); /* Enable 512-640K */ mem_set_mem_state(0x80000, 0x20000, (ps->ps1_e0_regs[1] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : - (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); } @@ -328,9 +328,9 @@ ps1_write(uint16_t port, uint8_t val, void *priv) case 0x0102: lpt1_remove(); if (val & 0x04) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps->uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_remove(1); + serial_remove(ps->uart); if (val & 0x10) { switch ((val >> 5) & 3) { case 0: @@ -447,6 +447,8 @@ ps1_setup(int model) io_sethandler(0x0190, 1, ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + ps->uart = device_add_inst(&ns16450_device, 1); + lpt1_remove(); lpt1_init(0x3bc); @@ -457,9 +459,6 @@ ps1_setup(int model) lpt2_remove(); - serial_remove(1); - serial_remove(2); - /* Enable the PS/1 VGA controller. */ if (model == 2011) device_add(&ps1vga_device); @@ -474,7 +473,7 @@ ps1_setup(int model) if (hdc_current == 1) { priv = device_add(&ps1_hdc_device); - ps1_hdc_inform(priv, ps); + ps1_hdc_inform(priv, &ps->ps1_91); } } @@ -489,7 +488,7 @@ ps1_setup(int model) #endif /* Initialize the video controller. */ - if (gfxcard == GFX_INTERNAL) + if (gfxcard == VID_INTERNAL) device_add(&ibm_ps1_2121_device); device_add(&fdc_at_ps1_device); @@ -499,11 +498,13 @@ ps1_setup(int model) device_add(&snd_device); } +#if defined(DEV_BRANCH) && defined(USE_PS1M2133) if (model == 2133) { device_add(&fdc_at_device); device_add(&ide_isa_device); } +#endif } @@ -512,16 +513,16 @@ ps1_common_init(const machine_t *model) { machine_common_init(model); - mem_remap_top_384k(); + mem_remap_top(384); - pit_set_out_func(&pit, 1, pit_refresh_timer_at); + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at); dma16_init(); pic2_init(); device_add(&ps_nvr_device); - device_add(&keyboard_ps2_device); + device_add(&keyboard_ps2_ps1_device); /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ if (joystick_type != 7) @@ -529,40 +530,62 @@ ps1_common_init(const machine_t *model) } -/* Set the Card Selected Flag */ -void -ps1_set_feedback(void *priv) -{ - ps1_t *ps = (ps1_t *)priv; - - ps->ps1_91 |= 0x01; -} - - -void +int machine_ps1_m2011_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/ibmps1es/f80000.bin", + 0x000e0000, 131072, 0x60000); + + if (bios_only || !ret) + return ret; + ps1_common_init(model); ps1_setup(2011); + + return ret; } -void +int machine_ps1_m2121_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/ibmps1_2121/fc0000.bin", + 0x000e0000, 131072, 0x20000); + + if (bios_only || !ret) + return ret; + ps1_common_init(model); ps1_setup(2121); + + return ret; } -void +#if defined(DEV_BRANCH) && defined(USE_PS1M2133) +int machine_ps1_m2133_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/ibmps1_2133/ps1_2133_52g2974_rom.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + ps1_common_init(model); ps1_setup(2133); nmi_mask = 0x80; + + return ret; } +#endif diff --git a/src/machine/m_ps1_hdc.c b/src/machine/m_ps1_hdc.c index 096e720b6..5c10ca69b 100644 --- a/src/machine/m_ps1_hdc.c +++ b/src/machine/m_ps1_hdc.c @@ -43,14 +43,14 @@ * Type table with the main code, so the user can only select * items from that list... * - * Version: @(#)m_ps1_hdc.c 1.0.6 2018/04/29 + * Version: @(#)m_ps1_hdc.c 1.0.8 2019/03/08 * * Author: Fred N. van Kempen, * * Based on my earlier HD20 driver for the EuroPC. * Thanks to Marco Bortolin for the help and feedback !! * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -93,11 +93,11 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../io.h" #include "../dma.h" #include "../pic.h" #include "../device.h" -#include "../timer.h" #include "../disk/hdc.h" #include "../disk/hdd.h" #include "../plat.h" @@ -105,7 +105,7 @@ #include "machine.h" -#define HDC_TIME (200*TIMER_USEC) +#define HDC_TIME (50*TIMER_USEC) #define HDC_TYPE_USER 47 /* user drive type */ @@ -387,10 +387,11 @@ typedef struct { status, /* Status register (ASR) */ intstat; /* Interrupt Status register (ISR) */ - void *sys; /* handle to system board */ + uint8_t *reg_91; /* handle to system board's register 0x91 */ /* Controller state. */ - int64_t callback; + uint64_t callback; + pc_timer_t timer; int8_t state, /* controller state */ reset; /* reset state counter */ @@ -474,13 +475,11 @@ static const geom_t ibm_type_table[] = { #ifdef ENABLE_PS1_HDC_LOG int ps1_hdc_do_log = ENABLE_PS1_HDC_LOG; -#endif static void ps1_hdc_log(const char *fmt, ...) { -#ifdef ENABLE_PS1_HDC_LOG va_list ap; if (ps1_hdc_do_log) @@ -489,9 +488,26 @@ ps1_hdc_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define ps1_hdc_log(fmt, ...) +#endif +static void +hdc_set_callback(hdc_t *dev, uint64_t callback) +{ + if (!dev) { + return; + } + + if (callback) { + dev->callback = callback; + timer_set_delay_u64(&dev->timer, dev->callback); + } else { + dev->callback = 0; + timer_disable(&dev->timer); + } +} /* FIXME: we should use the disk/hdd_table.c code with custom tables! */ static int @@ -635,7 +651,7 @@ do_format(hdc_t *dev, drive_t *drive, ccb_t *ccb) /* Enable for PIO or DMA, as needed. */ #if NOT_USED if (dev->ctrl & ACR_DMA_EN) - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); else #endif dev->status |= ASR_DATA_REQ; @@ -655,7 +671,7 @@ do_format(hdc_t *dev, drive_t *drive, ccb_t *ccb) dev->buf_idx++; } dev->state = STATE_RDONE; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); break; case STATE_RDONE: @@ -813,20 +829,20 @@ do_send: dev->buf_idx = 0; if (no_data) { /* Delay a bit, no actual transfer. */ - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } else { if (dev->ctrl & ACR_DMA_EN) { /* DMA enabled. */ dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } else { /* No DMA, do PIO. */ dev->status |= (ASR_DATA_REQ|ASR_DIR); /* Copy from sector to data. */ memcpy(dev->data, - dev->sector_buf, - (128<ssb.sect_size)); + dev->sector_buf, + dev->buf_len); dev->buf_ptr = dev->data; } } @@ -853,7 +869,7 @@ do_send: } } dev->state = STATE_SDONE; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); break; case STATE_SDONE: @@ -941,12 +957,12 @@ do_recv: dev->buf_idx = 0; if (no_data) { /* Delay a bit, no actual transfer. */ - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } else { if (dev->ctrl & ACR_DMA_EN) { /* DMA enabled. */ dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } else { /* No DMA, do PIO. */ dev->buf_ptr = dev->data; @@ -976,14 +992,15 @@ do_recv: } } dev->state = STATE_RDONE; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); break; case STATE_RDONE: /* Copy from data to sector if PIO. */ if (! (dev->ctrl & ACR_DMA_EN)) - memcpy(dev->sector_buf, dev->data, - (128<ssb.sect_size)); + memcpy(dev->sector_buf, + dev->data, + dev->buf_len); /* Get address of sector to write. */ if (get_sector(dev, drive, &addr)) { @@ -1100,7 +1117,7 @@ hdc_read(uint16_t port, void *priv) uint8_t ret = 0xff; /* TRM: tell system board we are alive. */ - ps1_set_feedback(dev->sys); + *dev->reg_91 |= 0x01; switch (port & 7) { case 0: /* DATA register */ @@ -1143,7 +1160,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv) hdc_t *dev = (hdc_t *)priv; /* TRM: tell system board we are alive. */ - ps1_set_feedback(dev->sys); + *dev->reg_91 |= 0x01; switch (port & 7) { case 0: /* DATA register */ @@ -1176,7 +1193,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv) dev->status |= ASR_BUSY; /* Schedule command execution. */ - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } } } @@ -1303,7 +1320,7 @@ ps1_hdc_init(const device_t *info) hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); /* Create a timer for command delays. */ - timer_add(hdc_callback, &dev->callback, &dev->callback, dev); + timer_add(&dev->timer, hdc_callback, dev, 0); return(dev); } @@ -1356,9 +1373,9 @@ const device_t ps1_hdc_device = { * agree that the current solution is nasty. */ void -ps1_hdc_inform(void *priv, void *arg) +ps1_hdc_inform(void *priv, uint8_t *reg_91) { hdc_t *dev = (hdc_t *)priv; - dev->sys = arg; + dev->reg_91 = reg_91; } diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 213e06b50..a713278d9 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -4,6 +4,7 @@ #include #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../io.h" #include "../dma.h" #include "../pic.h" @@ -14,14 +15,17 @@ #include "../nvr.h" #include "../keyboard.h" #include "../lpt.h" +#include "../port_92.h" #include "../serial.h" +#include "../disk/hdc.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../video/vid_vga.h" #include "machine.h" -static uint8_t ps2_94, ps2_102, ps2_103, ps2_104, ps2_105, ps2_190; +static uint8_t ps2_91, ps2_94, ps2_102, ps2_103, ps2_104, ps2_105, ps2_190; +static serial_t *ps2_uart; static struct @@ -38,7 +42,9 @@ static uint8_t ps2_read(uint16_t port, void *p) switch (port) { case 0x91: - return 0; + temp = ps2_91; + ps2_91 = 0; + return temp; case 0x94: return ps2_94; case 0x102: @@ -51,7 +57,8 @@ static uint8_t ps2_read(uint16_t port, void *p) return ps2_105; case 0x190: return ps2_190; - + +#ifdef FIXME case 0x322: temp = ps2_hd.status; break; @@ -59,7 +66,8 @@ static uint8_t ps2_read(uint16_t port, void *p) temp = ps2_hd.int_status; ps2_hd.int_status &= ~0x02; break; - +#endif + default: temp = 0xff; break; @@ -78,9 +86,9 @@ static void ps2_write(uint16_t port, uint8_t val, void *p) case 0x102: lpt1_remove(); if (val & 0x04) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2_uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_remove(1); + serial_remove(ps2_uart); if (val & 0x10) { switch ((val >> 5) & 3) @@ -110,7 +118,8 @@ static void ps2_write(uint16_t port, uint8_t val, void *p) case 0x190: ps2_190 = val; break; - + +#ifdef FIXME case 0x322: ps2_hd.ctrl = val; if (val & 0x80) @@ -121,6 +130,7 @@ static void ps2_write(uint16_t port, uint8_t val, void *p) if (ps2_hd.attention) ps2_hd.status = 0x14; break; +#endif } } @@ -131,33 +141,57 @@ static void ps2board_init(void) io_sethandler(0x0094, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); io_sethandler(0x0102, 0x0004, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); io_sethandler(0x0190, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); +#ifdef FIXME 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); - - port_92_reset(); +#endif - port_92_add(); + device_add(&port_92_device); ps2_190 = 0; + ps2_uart = device_add_inst(&ns16450_device, 1); + lpt1_init(0x3bc); memset(&ps2_hd, 0, sizeof(ps2_hd)); } -void +int machine_ps2_m30_286_init(const machine_t *model) { + void *priv; + + int ret; + + ret = bios_load_linear(L"roms/machines/ibmps2_m30_286/33f5381a.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_common_init(model); + + mem_remap_top(384); + device_add(&fdc_at_ps1_device); - pit_set_out_func(&pit, 1, pit_refresh_timer_at); + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_at); dma16_init(); - device_add(&keyboard_ps2_device); + device_add(&keyboard_ps2_ps2_device); device_add(&ps_nvr_device); pic2_init(); ps2board_init(); device_add(&ps1vga_device); + + /* Enable the builtin HDC. */ + if (hdc_current == 1) { + priv = device_add(&ps1_hdc_device); + + ps1_hdc_inform(priv, &ps2_91); + } + + return ret; } diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index d0c02a579..7eb011931 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -1,3 +1,41 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of MCA-based PS/2 machines. + * + * Version: @(#)m_ps2_mca.c 1.0.6 2019/11/01 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. +*/ #include #include #include @@ -5,8 +43,14 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#ifdef USE_NEW_DYNAREC +#include "../cpu_new/cpu.h" +#include "../cpu_new/x86.h" +#else #include "../cpu/cpu.h" #include "../cpu/x86.h" +#endif +#include "../timer.h" #include "../io.h" #include "../dma.h" #include "../pic.h" @@ -23,6 +67,7 @@ #include "../keyboard.h" #include "../lpt.h" #include "../mouse.h" +#include "../port_92.h" #include "../serial.h" #include "../video/video.h" #include "../video/vid_vga.h" @@ -59,6 +104,8 @@ static struct uint8_t mem_2mb_pos_regs[8]; int pending_cache_miss; + + serial_t *uart; } ps2; /*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any @@ -100,22 +147,22 @@ static int ps2_cache_valid[65536/8]; #ifdef ENABLE_PS2_MCA_LOG int ps2_mca_do_log = ENABLE_PS2_MCA_LOG; -#endif static void -ps2_mca_log(const char *format, ...) +ps2_mca_log(const char *fmt, ...) { -#ifdef ENABLE_PS2_MCA_LOG va_list ap; if (ps2_mca_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define ps2_mca_log(fmt, ...) +#endif static uint8_t ps2_read_cache_ram(uint32_t addr, void *priv) @@ -343,16 +390,14 @@ static void model_50_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(1); + serial_remove(ps2.uart); if (val & 0x04) { if (val & 0x08) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); } - else - serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) @@ -399,16 +444,14 @@ static void model_55sx_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(1); + serial_remove(ps2.uart); if (val & 0x04) { if (val & 0x08) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); } - else - serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) @@ -447,14 +490,14 @@ static void model_55sx_write(uint16_t port, uint8_t val) } else { - mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); mem_mapping_enable(&ps2.shadow_mapping); } if ((ps2.option[1] & 1) && !(ps2.option[3] & 0x20)) mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); else - mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_EXTANY | MEM_WRITE_EXTANY); break; case 0x106: ps2.subaddr_lo = val; @@ -475,16 +518,14 @@ static void model_70_type3_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(1); + serial_remove(ps2.uart); if (val & 0x04) { if (val & 0x08) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); } - else - serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) @@ -525,16 +566,14 @@ static void model_80_write(uint16_t port, uint8_t val) break; case 0x102: lpt1_remove(); - serial_remove(1); + serial_remove(ps2.uart); if (val & 0x04) { if (val & 0x08) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(ps2.uart, SERIAL1_ADDR, SERIAL1_IRQ); else - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + serial_setup(ps2.uart, SERIAL2_ADDR, SERIAL2_IRQ); } - else - serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) @@ -577,7 +616,17 @@ uint8_t ps2_mca_read(uint16_t port, void *p) switch (port) { case 0x91: - fatal("Read 91 setup=%02x adapter=%02x\n", ps2.setup, ps2.adapter_setup); + // fatal("Read 91 setup=%02x adapter=%02x\n", ps2.setup, ps2.adapter_setup); + if (!(ps2.setup & PS2_SETUP_IO)) + temp = 0x00; + else if (!(ps2.setup & PS2_SETUP_VGA)) + temp = 0x00; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + temp = 0x00; + else + temp = !mca_feedb(); + temp |= 0xfe; + break; case 0x94: temp = ps2.setup; break; @@ -737,10 +786,8 @@ static void ps2_mca_board_common_init() io_sethandler(0x0094, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); io_sethandler(0x0096, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); io_sethandler(0x0100, 0x0008, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); - - port_92_reset(); - port_92_add(); + device_add(&port_92_device); ps2.setup = 0xff; @@ -765,6 +812,11 @@ static void ps2_mem_expansion_write(int port, uint8_t val, void *p) mem_mapping_disable(&ps2.expansion_mapping); } +static uint8_t ps2_mem_expansion_feedb(void *p) +{ + return (ps2.mem_pos_regs[2] & 1); +} + static void ps2_mca_mem_fffc_init(int start_mb) { uint32_t planar_size, expansion_start; @@ -810,7 +862,7 @@ static void ps2_mca_mem_fffc_init(int start_mb) break; } - mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL); + mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, ps2_mem_expansion_feedb, NULL); mem_mapping_add(&ps2.expansion_mapping, expansion_start, (mem_size - (start_mb << 10)) << 10, @@ -830,9 +882,10 @@ static void ps2_mca_board_model_50_init() { ps2_mca_board_common_init(); - mem_remap_top_384k(); + mem_remap_top(384); mca_init(4); - + device_add(&keyboard_ps2_mca_2_device); + ps2.planar_read = model_50_read; ps2.planar_write = model_50_write; @@ -842,8 +895,8 @@ static void ps2_mca_board_model_50_init() ps2_mca_mem_fffc_init(2); } - if (gfxcard == GFX_INTERNAL) - device_add(&ps1vga_device); + if (gfxcard == VID_INTERNAL) + device_add(&ps1vga_mca_device); } static void ps2_mca_board_model_55sx_init() @@ -864,7 +917,7 @@ static void ps2_mca_board_model_55sx_init() NULL); - mem_remap_top_256k(); + mem_remap_top(256); ps2.option[3] = 0x10; memset(ps2.memory_bank, 0xf0, 8); @@ -903,12 +956,13 @@ static void ps2_mca_board_model_55sx_init() } mca_init(4); - + device_add(&keyboard_ps2_mca_device); + ps2.planar_read = model_55sx_read; ps2.planar_write = model_55sx_write; - if (gfxcard == GFX_INTERNAL) - device_add(&ps1vga_device); + if (gfxcard == VID_INTERNAL) + device_add(&ps1vga_mca_device); } static void mem_encoding_update() @@ -918,7 +972,7 @@ static void mem_encoding_update() ps2.split_addr = ((uint32_t) (ps2.mem_regs[0] & 0xf)) << 20; if (ps2.mem_regs[1] & 2) { - mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); ps2_mca_log("PS/2 Model 80-111: ROM space enabled\n"); } else { mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); @@ -1019,10 +1073,13 @@ static void mem_encoding_write_cached(uint16_t addr, uint8_t val, void *p) ps2.pending_cache_miss = 1; if ((val & 0x21) == 0x01 && (old & 0x21) != 0x01) ps2_cache_clean(); +#if 1 + // FIXME: Look into this!!! if (val & 0x01) ram_mid_mapping.flags |= MEM_MAPPING_ROM; else ram_mid_mapping.flags &= ~MEM_MAPPING_ROM; +#endif break; } ps2_mca_log("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]); @@ -1047,7 +1104,8 @@ static void ps2_mca_board_model_70_type34_init(int is_type4) ps2.split_addr = mem_size * 1024; mca_init(4); - + device_add(&keyboard_ps2_mca_device); + ps2.planar_read = model_70_type3_read; ps2.planar_write = model_70_type3_write; @@ -1115,8 +1173,8 @@ static void ps2_mca_board_model_70_type34_init(int is_type4) ps2_mca_mem_fffc_init(8); } - if (gfxcard == GFX_INTERNAL) - device_add(&ps1vga_device); + if (gfxcard == VID_INTERNAL) + device_add(&ps1vga_mca_device); } static void ps2_mca_board_model_80_type2_init(int is486) @@ -1125,6 +1183,7 @@ static void ps2_mca_board_model_80_type2_init(int is486) ps2.split_addr = mem_size * 1024; mca_init(8); + device_add(&keyboard_ps2_mca_device); ps2.planar_read = model_80_read; ps2.planar_write = model_80_write; @@ -1185,8 +1244,8 @@ static void ps2_mca_board_model_80_type2_init(int is486) ps2_mca_mem_fffc_init(4); } - if (gfxcard == GFX_INTERNAL) - device_add(&ps1vga_device); + if (gfxcard == VID_INTERNAL) + device_add(&ps1vga_mca_device); } @@ -1198,64 +1257,117 @@ machine_ps2_common_init(const machine_t *model) dma16_init(); ps2_dma_init(); - device_add(&keyboard_ps2_mca_device); device_add(&ps_nvr_device); pic2_init(); pit_ps2_init(); nmi_mask = 0x80; + + ps2.uart = device_add_inst(&ns16550_device, 1); } -void +int machine_ps2_model_50_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m50/90x7420.zm13", + L"roms/machines/ibmps2_m50/90x7429.zm18", + 0x000f0000, 131072, 0); + ret &= bios_load_aux_interleaved(L"roms/machines/ibmps2_m50/90x7423.zm14", + L"roms/machines/ibmps2_m50/90x7426.zm16", + 0x000e0000, 65536, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_50_init(); + + return ret; } -void +int machine_ps2_model_55sx_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m55sx/33f8146.zm41", + L"roms/machines/ibmps2_m55sx/33f8145.zm40", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_55sx_init(); + + return ret; } -void + +int machine_ps2_model_70_type3_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m70_type3/70-a_even.bin", + L"roms/machines/ibmps2_m70_type3/70-a_odd.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_70_type34_init(0); + + return ret; } -void + +#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) +int machine_ps2_model_70_type4_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m70_type4/70-b_even.bin", + L"roms/machines/ibmps2_m70_type4/70-b_odd.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_70_type34_init(1); -} -void + return ret; +} +#endif + + +int machine_ps2_model_80_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m80/15f6637.bin", + L"roms/machines/ibmps2_m80/15f6639.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_80_type2_init(0); + + return ret; } - - -#ifdef WALTJE -void -machine_ps2_model_80_486_init(const machine_t *model) -{ - machine_ps2_common_init(model); - - ps2_mca_board_model_80_type2_init(1); -} -#endif diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index d159d63c8..3dbc65748 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -8,13 +8,13 @@ * * Emulation of Tandy models 1000, 1000HX and 1000SL2. * - * Version: @(#)m_tandy.c 1.0.7 2018/04/29 + * Version: @(#)m_tandy.c 1.0.11 2019/12/28 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -25,12 +25,12 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../io.h" #include "../pit.h" #include "../nmi.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "../nvr.h" #include "../floppy/fdd.h" @@ -45,8 +45,17 @@ #include "machine.h" -#define TANDY_RGB 0 -#define TANDY_COMPOSITE 1 +enum { + TANDY_RGB = 0, + TANDY_COMPOSITE +}; + + +enum { + TYPE_TANDY = 0, + TYPE_TANDY1000HX, + TYPE_TANDY1000SL2 +}; enum { @@ -65,7 +74,7 @@ typedef struct { int crtcreg; int array_index; - uint8_t array[32]; + uint8_t array[256]; int memctrl; uint8_t mode, col; uint8_t stat; @@ -82,13 +91,13 @@ typedef struct { int con, coff, cursoron, blink; - int64_t vsynctime; + int vsynctime; int vadj; uint16_t ma, maback; - int64_t dispontime, - dispofftime, - vidtime; + uint64_t dispontime, + dispofftime; + pc_timer_t timer; int firstline, lastline; @@ -96,7 +105,6 @@ typedef struct { } t1kvid_t; typedef struct { - int romset; wchar_t *path; int state; @@ -122,264 +130,266 @@ typedef struct { t1kvid_t *vid; } tandy_t; +static video_timings_t timing_dram = {VIDEO_BUS, 0,0,0, 0,0,0}; /*No additional waitstates*/ + static const scancode scancode_tandy[512] = { - { {-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} }, { {0x56, -1}, {0xd6, -1} }, - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*054*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*058*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*05c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*060*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*064*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*068*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*06c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*070*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*074*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*078*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*07c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*080*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*084*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*088*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*08c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*090*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*094*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*098*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*09c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0ac*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0bc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0cc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0dc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0ec*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0fc*/ - { {-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*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*110*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*114*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*118*/ - { {0x57, -1}, {0xd7, -1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*11c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*120*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*124*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*128*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*12c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*130*/ - { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, - { {-1}, {-1} }, { {0x37, -1}, {0xb7, -1} }, /*134*/ - { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*138*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*13c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*140*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*144*/ - { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, - { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*148*/ - { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, - { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*14c*/ - { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, - { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*150*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*154*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*158*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*15c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*160*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*164*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*168*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*16c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*170*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*174*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*148*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*17c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*180*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*184*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*18c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*190*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*194*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*198*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*19c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1ac*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1bc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1cc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1dc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1ec*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} } /*1fc*/ + { {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} }, { {0x56, 0}, {0xd6, 0} }, + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*054*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*058*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*05c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*060*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*064*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*068*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*06c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*070*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*074*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*078*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*07c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*080*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*084*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*088*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*08c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*090*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*094*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*098*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*09c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0ac*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0bc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0cc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0dc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0ec*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0fc*/ + { {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*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*110*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*114*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*118*/ + { {0x57, 0}, {0xd7, 0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*11c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*120*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*124*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*128*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*12c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*130*/ + { {0}, {0} }, { {0x35, 0}, {0xb5, 0} }, + { {0}, {0} }, { {0x37, 0}, {0xb7, 0} }, /*134*/ + { {0x38, 0}, {0xb8, 0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*138*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*13c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*140*/ + { {0}, {0} }, { {0}, {0} }, + { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, /*144*/ + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, + { {0}, {0} }, { {0x4b, 0}, {0xcb, 0} }, /*148*/ + { {0}, {0} }, { {0x4d, 0}, {0xcd, 0} }, + { {0}, {0} }, { {0x4f, 0}, {0xcf, 0} }, /*14c*/ + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, + { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, /*150*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*154*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*158*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*15c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*160*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*164*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*168*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*16c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*170*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*174*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*148*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*17c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*180*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*184*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*88*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*18c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*190*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*194*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*198*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*19c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1ac*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1bc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1cc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1dc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1ec*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} } /*1fc*/ }; static uint8_t crtcmask[32] = { 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, @@ -402,13 +412,11 @@ static void vid_out(uint16_t addr, uint8_t val, void *priv); #ifdef ENABLE_TANDY_LOG int tandy_do_log = ENABLE_TANDY_LOG; -#endif static void tandy_log(const char *fmt, ...) { -#ifdef ENABLE_TANDY_LOG va_list ap; if (tandy_do_log) @@ -417,8 +425,10 @@ tandy_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define tandy_log(fmt, ...) +#endif static void @@ -459,8 +469,8 @@ recalc_timings(tandy_t *dev) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST; _dispofftime *= CGACONST; - vid->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - vid->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + vid->dispontime = (uint64_t)(_dispontime); + vid->dispofftime = (uint64_t)(_dispofftime); } @@ -648,7 +658,7 @@ vid_poll(void *priv) t1kvid_t *vid = dev->vid; uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; int drawcursor; - int x, c; + int x, c, xs_temp, ys_temp; int oldvc; uint8_t chr, attr; uint16_t dat; @@ -657,13 +667,12 @@ vid_poll(void *priv) int oldsc; if (! vid->linepos) { - vid->vidtime += vid->dispofftime; + timer_advance_u64(&vid->timer, vid->dispofftime); vid->stat |= 1; vid->linepos = 1; oldsc = vid->sc; if ((vid->crtc[8] & 3) == 3) vid->sc = (vid->sc << 1) & 7; - if (vid->dispon) { if (vid->displine < vid->firstline) { vid->firstline = vid->displine; @@ -673,61 +682,96 @@ vid_poll(void *priv) cols[0] = (vid->array[2] & 0xf) + 16; for (c = 0; c < 8; c++) { if (vid->array[3] & 4) { - buffer->line[vid->displine][c] = cols[0]; - if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = cols[0]; - else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = cols[0]; + buffer32->line[(vid->displine << 1)][c] = buffer32->line[(vid->displine << 1) + 1][c] = cols[0]; + if (vid->mode & 1) { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 3) + 8] = + buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = cols[0]; + } else { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 4) + 8] = + buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = cols[0]; + } } else if ((vid->mode & 0x12) == 0x12) { - buffer->line[vid->displine][c] = 0; - if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; - else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; + buffer32->line[(vid->displine << 1)][c] = buffer32->line[(vid->displine << 1) + 1][c] = 0; + if (vid->mode & 1) { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 3) + 8] = + buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = 0; + } else { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 4) + 8] = + buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = 0; + } } else { - buffer->line[vid->displine][c] = (vid->col & 15) + 16; - if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; - else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; + buffer32->line[(vid->displine << 1)][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->col & 15) + 16; + if (vid->mode & 1) { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 3) + 8] = + buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; + } else { + buffer32->line[(vid->displine << 1)][c + (vid->crtc[1] << 4) + 8] = + buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; + } } } - - if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ + if (dev->is_sl2 && (vid->array[5] & 1)) { /*640x200x16*/ + for (x = 0; x < vid->crtc[1]*2; x++) { + dat = (vid->vram[(vid->ma << 1) & 0xffff] << 8) | + vid->vram[((vid->ma << 1) + 1) & 0xffff]; + vid->ma++; + buffer32->line[(vid->displine << 1)][(x << 2) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 8] = + vid->array[((dat >> 12) & 0xf) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 2) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 9] = + vid->array[((dat >> 8) & 0xf) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 2) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 10] = + vid->array[((dat >> 4) & 0xf) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 2) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 11] = + vid->array[(dat & 0xf) + 16] + 16; + } + } else if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ for (x = 0; x < vid->crtc[1]; x++) { dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; vid->ma++; - buffer->line[vid->displine][(x << 3) + 8] = - buffer->line[vid->displine][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 10] = - buffer->line[vid->displine][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 12] = - buffer->line[vid->displine][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 14] = - buffer->line[vid->displine][(x << 3) + 15] = vid->array[(dat & vid->array[1]) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8] = + buffer32->line[(vid->displine << 1)][(x << 3) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 9] = + vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 3) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 10] = + buffer32->line[(vid->displine << 1)][(x << 3) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 11] = + vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 3) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 12] = + buffer32->line[(vid->displine << 1)][(x << 3) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 13] = + vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 3) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 14] = + buffer32->line[(vid->displine << 1)][(x << 3) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 15] = + vid->array[(dat & vid->array[1]) + 16] + 16; } } else if (vid->array[3] & 0x10) { /*160x200x16*/ for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | - vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + if (dev->is_sl2) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + } else { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + } vid->ma++; - buffer->line[vid->displine][(x << 4) + 8] = - buffer->line[vid->displine][(x << 4) + 9] = - buffer->line[vid->displine][(x << 4) + 10] = - buffer->line[vid->displine][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 12] = - buffer->line[vid->displine][(x << 4) + 13] = - buffer->line[vid->displine][(x << 4) + 14] = - buffer->line[vid->displine][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 16] = - buffer->line[vid->displine][(x << 4) + 17] = - buffer->line[vid->displine][(x << 4) + 18] = - buffer->line[vid->displine][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 20] = - buffer->line[vid->displine][(x << 4) + 21] = - buffer->line[vid->displine][(x << 4) + 22] = - buffer->line[vid->displine][(x << 4) + 23] = vid->array[(dat & vid->array[1]) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 8] = + buffer32->line[(vid->displine << 1)][(x << 4) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 9] = + buffer32->line[(vid->displine << 1)][(x << 4) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 10] = + buffer32->line[(vid->displine << 1)][(x << 4) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 11] = + vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 4) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 12] = + buffer32->line[(vid->displine << 1)][(x << 4) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 13] = + buffer32->line[(vid->displine << 1)][(x << 4) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 14] = + buffer32->line[(vid->displine << 1)][(x << 4) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 15] = + vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 4) + 16] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 16] = + buffer32->line[(vid->displine << 1)][(x << 4) + 17] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 17] = + buffer32->line[(vid->displine << 1)][(x << 4) + 18] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 18] = + buffer32->line[(vid->displine << 1)][(x << 4) + 19] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 19] = + vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + buffer32->line[(vid->displine << 1)][(x << 4) + 20] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 20] = + buffer32->line[(vid->displine << 1)][(x << 4) + 21] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 21] = + buffer32->line[(vid->displine << 1)][(x << 4) + 22] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 22] = + buffer32->line[(vid->displine << 1)][(x << 4) + 23] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 23] = + vid->array[(dat & vid->array[1]) + 16] + 16; } } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ for (x = 0; x < vid->crtc[1]; x++) { @@ -735,9 +779,10 @@ vid_poll(void *priv) vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; vid->ma++; for (c = 0; c < 8; c++) { - chr = (dat >> 7) & 1; - chr |= ((dat >> 14) & 2); - buffer->line[vid->displine][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; + chr = (dat >> 6) & 2; + chr |= ((dat >> 15) & 1); + buffer32->line[(vid->displine << 1)][(x << 3) + 8 + c] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8 + c] = + vid->array[(chr & vid->array[1]) + 16] + 16; dat <<= 1; } } @@ -750,21 +795,27 @@ vid_poll(void *priv) cols[1] = vid->array[ ((attr & 15) & vid->array[1]) + 16] + 16; cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; + cols[1] = cols[0]; } else { cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; } if (vid->sc & 8) { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[0]; + for (c = 0; c < 8; c++) { + buffer32->line[(vid->displine << 1)][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = + cols[0]; + } } else { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + for (c = 0; c < 8; c++) { + buffer32->line[(vid->displine << 1)][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } } if (drawcursor) { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] ^= 15; + for (c = 0; c < 8; c++) { + buffer32->line[(vid->displine << 1)][(x << 3) + c + 8] ^= 15; + buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] ^= 15; + } } vid->ma++; } @@ -785,365 +836,25 @@ vid_poll(void *priv) vid->ma++; if (vid->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + cols[0]; } else { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + for (c = 0; c < 8; c++) { + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } } if (drawcursor) { - for (c = 0; c < 16; c++) - buffer->line[vid->displine][(x << 4) + c + 8] ^= 15; - } - } - } else if (! (vid->mode& 16)) { - cols[0] = (vid->col & 15) | 16; - col = (vid->col & 16) ? 24 : 16; - if (vid->mode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; - } else if (vid->col & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; - } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; - } - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | - vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 8; c++) { - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; - dat <<= 2; - } - } - } else { - cols[0] = 0; - cols[1] = vid->array[(vid->col & vid->array[1]) + 16] + 16; - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | - vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 16; c++) { - buffer->line[vid->displine][(x << 4) + c + 8] = cols[dat >> 15]; - dat <<= 1; - } - } - } - } else { - if (vid->array[3] & 4) { - if (vid->mode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); - } else { - cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; - if (vid->mode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); - else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); - } - } - - if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 16; - else - x = (vid->crtc[1] << 4) + 16; - if (vid->composite) { - for (c = 0; c < x; c++) - buffer32->line[vid->displine][c] = buffer->line[vid->displine][c] & 0xf; - - Composite_Process(vid->mode, 0, x >> 2, buffer32->line[vid->displine]); - } - vid->sc = oldsc; - if (vid->vc == vid->crtc[7] && !vid->sc) - vid->stat |= 8; - vid->displine++; - if (vid->displine >= 360) - vid->displine = 0; - } else { - vid->vidtime += vid->dispontime; - if (vid->dispon) - vid->stat &= ~1; - vid->linepos = 0; - if (vid->vsynctime) { - vid->vsynctime--; - if (! vid->vsynctime) - vid->stat &= ~8; - } - if (vid->sc == (vid->crtc[11] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[11] & 31) >> 1))) { - vid->con = 0; - vid->coff = 1; - } - if (vid->vadj) { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; - vid->vadj--; - if (! vid->vadj) { - vid->dispon = 1; - vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; - vid->sc = 0; - } - } else if (vid->sc == vid->crtc[9] || ((vid->crtc[8] & 3) == 3 && vid->sc == (vid->crtc[9] >> 1))) { - vid->maback = vid->ma; - vid->sc = 0; - oldvc = vid->vc; - vid->vc++; - vid->vc &= 127; - if (vid->vc == vid->crtc[6]) - vid->dispon = 0; - if (oldvc == vid->crtc[4]) { - vid->vc = 0; - vid->vadj = vid->crtc[5]; - if (! vid->vadj) - vid->dispon = 1; - if (! vid->vadj) - vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; - if ((vid->crtc[10] & 0x60) == 0x20) - vid->cursoron = 0; - else - vid->cursoron = vid->blink & 16; - } - if (vid->vc == vid->crtc[7]) { - vid->dispon = 0; - vid->displine = 0; - vid->vsynctime = 16; - if (vid->crtc[7]) { - if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 16; - else - x = (vid->crtc[1] << 4) + 16; - vid->lastline++; - if ((x != xsize) || ((vid->lastline - vid->firstline) != ysize) || video_force_resize_get()) { - xsize = x; - ysize = vid->lastline - vid->firstline; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, (ysize << 1) + 16); - if (video_force_resize_get()) - video_force_resize_set(0); - } - if (vid->composite) - video_blit_memtoscreen(0, vid->firstline-4, 0, (vid->lastline - vid->firstline) + 8, xsize, (vid->lastline - vid->firstline) + 8); - else - video_blit_memtoscreen_8(0, vid->firstline-4, 0, (vid->lastline - vid->firstline) + 8, xsize, (vid->lastline - vid->firstline) + 8); - - frames++; - - video_res_x = xsize - 16; - video_res_y = ysize; - if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ - video_res_x /= 2; - video_bpp = 4; - } else if (vid->array[3] & 0x10) { /*160x200x16*/ - video_res_x /= 4; - video_bpp = 4; - } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ - video_bpp = 2; - } else if (vid->mode & 1) { - video_res_x /= 8; - video_res_y /= vid->crtc[9] + 1; - video_bpp = 0; - } else if (! (vid->mode & 2)) { - video_res_x /= 16; - video_res_y /= vid->crtc[9] + 1; - video_bpp = 0; - } else if (! (vid->mode & 16)) { - video_res_x /= 2; - video_bpp = 2; - } else { - video_bpp = 1; - } - } - vid->firstline = 1000; - vid->lastline = 0; - vid->blink++; - } - } else { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; - } - if ((vid->sc == (vid->crtc[10] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[10] & 31) >> 1)))) - vid->con = 1; - } -} - - -static void -vid_poll_sl(void *priv) -{ - tandy_t *dev = (tandy_t *)priv; - t1kvid_t *vid = dev->vid; - uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x, c; - int oldvc; - uint8_t chr, attr; - uint16_t dat; - int cols[4]; - int col; - int oldsc; - - if (! vid->linepos) { - vid->vidtime += vid->dispofftime; - vid->stat |= 1; - vid->linepos = 1; - oldsc = vid->sc; - if ((vid->crtc[8] & 3) == 3) - vid->sc = (vid->sc << 1) & 7; - if (vid->dispon) { - if (vid->displine < vid->firstline) { - vid->firstline = vid->displine; - video_wait_for_buffer(); - } - vid->lastline = vid->displine; - cols[0] = (vid->array[2] & 0xf) + 16; - for (c = 0; c < 8; c++) { - if (vid->array[3] & 4) { - buffer->line[vid->displine][c] = cols[0]; - if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = cols[0]; - else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = cols[0]; - } else if ((vid->mode & 0x12) == 0x12) { - buffer->line[vid->displine][c] = 0; - if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; - else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; - } else { - buffer->line[vid->displine][c] = (vid->col & 15) + 16; - if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; - else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; - } - } - if (vid->array[5] & 1) { /*640x200x16*/ - for (x = 0; x < vid->crtc[1]*2; x++) { - dat = (vid->vram[(vid->ma << 1) & 0xffff] << 8) | - vid->vram[((vid->ma << 1) + 1) & 0xffff]; - vid->ma++; - buffer->line[vid->displine][(x << 2) + 8] = vid->array[((dat >> 12) & 0xf)/*vid->array[1])*/ + 16] + 16; - buffer->line[vid->displine][(x << 2) + 9] = vid->array[((dat >> 8) & 0xf)/*vid->array[1])*/ + 16] + 16; - buffer->line[vid->displine][(x << 2) + 10] = vid->array[((dat >> 4) & 0xf)/*vid->array[1])*/ + 16] + 16; - buffer->line[vid->displine][(x << 2) + 11] = vid->array[(dat & 0xf)/*vid->array[1])*/ + 16] + 16; - } - } else if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | - vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; - vid->ma++; - buffer->line[vid->displine][(x << 3) + 8] = - buffer->line[vid->displine][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 10] = - buffer->line[vid->displine][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 12] = - buffer->line[vid->displine][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 14] = - buffer->line[vid->displine][(x << 3) + 15] = vid->array[(dat & vid->array[1]) + 16] + 16; - } - } else if (vid->array[3] & 0x10) { /*160x200x16*/ - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | - vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - vid->ma++; - buffer->line[vid->displine][(x << 4) + 8] = - buffer->line[vid->displine][(x << 4) + 9] = - buffer->line[vid->displine][(x << 4) + 10] = - buffer->line[vid->displine][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 12] = - buffer->line[vid->displine][(x << 4) + 13] = - buffer->line[vid->displine][(x << 4) + 14] = - buffer->line[vid->displine][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 16] = - buffer->line[vid->displine][(x << 4) + 17] = - buffer->line[vid->displine][(x << 4) + 18] = - buffer->line[vid->displine][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 20] = - buffer->line[vid->displine][(x << 4) + 21] = - buffer->line[vid->displine][(x << 4) + 22] = - buffer->line[vid->displine][(x << 4) + 23] = vid->array[(dat & vid->array[1]) + 16] + 16; - } - } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | - vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 8; c++) { - chr = (dat >> 7) & 1; - chr |= ((dat >> 14) & 2); - buffer->line[vid->displine][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; - dat <<= 1; - } - } - } else if (vid->mode & 1) { - for (x = 0; x < vid->crtc[1]; x++) { - chr = vid->vram[ (vid->ma << 1) & 0x3fff]; - attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->mode & 0x20) { - cols[1] = vid->array[ ((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; - } - if (vid->sc & 8) { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[0]; - } else { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } - if (drawcursor) { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] ^= 15; - } - vid->ma++; - } - } else if (! (vid->mode & 2)) { - for (x = 0; x < vid->crtc[1]; x++) { - chr = vid->vram[ (vid->ma << 1) & 0x3fff]; - attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->mode & 0x20) { - cols[1] = vid->array[ ((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; - } - vid->ma++; - if (vid->sc & 8) { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; - } else { - for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } - if (drawcursor) { - for (c = 0; c < 16; c++) - buffer->line[vid->displine][(x << 4) + c + 8] ^= 15; + for (c = 0; c < 16; c++) { + buffer32->line[(vid->displine << 1)][(x << 4) + c + 8] ^= 15; + buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] ^= 15; + } } } } else if (! (vid->mode & 16)) { - cols[0] = (vid->col & 15) | 16; - col = (vid->col & 16) ? 24 : 16; + cols[0] = (vid->col & 15); + col = (vid->col & 16) ? 8 : 0; if (vid->mode & 4) { cols[1] = col | 3; cols[2] = col | 4; @@ -1157,14 +868,18 @@ vid_poll_sl(void *priv) cols[2] = col | 4; cols[3] = col | 6; } - + cols[0] = vid->array[(cols[0] & vid->array[1]) + 16] + 16; + cols[1] = vid->array[(cols[1] & vid->array[1]) + 16] + 16; + cols[2] = vid->array[(cols[2] & vid->array[1]) + 16] + 16; + cols[3] = vid->array[(cols[3] & vid->array[1]) + 16] + 16; for (x = 0; x < vid->crtc[1]; x++) { dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; vid->ma++; for (c = 0; c < 8; c++) { - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(vid->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[dat >> 14]; dat <<= 2; } } @@ -1176,23 +891,30 @@ vid_poll_sl(void *priv) vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; vid->ma++; for (c = 0; c < 16; c++) { - buffer->line[vid->displine][(x << 4) + c + 8] = cols[dat >> 15]; + buffer32->line[(vid->displine << 1)][(x << 4) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] = + cols[dat >> 15]; dat <<= 1; } } } } else { if (vid->array[3] & 4) { - if (vid->mode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + if (vid->mode & 1) { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + } else { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + } } else { cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; - if (vid->mode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); - else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); + if (vid->mode & 1) { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, cols[0]); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, cols[0]); + } else { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, cols[0]); + } } } @@ -1200,15 +922,18 @@ vid_poll_sl(void *priv) x = (vid->crtc[1] << 3) + 16; else x = (vid->crtc[1] << 4) + 16; + if (!dev->is_sl2 && vid->composite) { + Composite_Process(vid->mode, 0, x >> 2, buffer32->line[(vid->displine << 1)]); + Composite_Process(vid->mode, 0, x >> 2, buffer32->line[(vid->displine << 1) + 1]); + } vid->sc = oldsc; - if (vid->vc == vid->crtc[7] && !vid->sc) vid->stat |= 8; vid->displine++; if (vid->displine >= 360) vid->displine = 0; } else { - vid->vidtime += vid->dispontime; + timer_advance_u64(&vid->timer, vid->dispontime); if (vid->dispon) vid->stat &= ~1; vid->linepos = 0; @@ -1228,7 +953,7 @@ vid_poll_sl(void *priv) vid->vadj--; if (! vid->vadj) { vid->dispon = 1; - if (vid->array[5] & 1) + if (dev->is_sl2 && (vid->array[5] & 1)) vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); else vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; @@ -1239,7 +964,10 @@ vid_poll_sl(void *priv) vid->sc = 0; oldvc = vid->vc; vid->vc++; - vid->vc &= 255; + if (dev->is_sl2) + vid->vc &= 255; + else + vid->vc &= 127; if (vid->vc == vid->crtc[6]) vid->dispon = 0; if (oldvc == vid->crtc[4]) { @@ -1248,7 +976,7 @@ vid_poll_sl(void *priv) if (! vid->vadj) vid->dispon = 1; if (! vid->vadj) { - if (vid->array[5] & 1) + if (dev->is_sl2 && (vid->array[5] & 1)) vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); else vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; @@ -1268,30 +996,54 @@ vid_poll_sl(void *priv) else x = (vid->crtc[1] << 4) + 16; vid->lastline++; - if ((x != xsize) || ((vid->lastline - vid->firstline) != ysize) || video_force_resize_get()) { - xsize = x; - ysize = vid->lastline - vid->firstline; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, (ysize << 1) + 16); - if (video_force_resize_get()) - video_force_resize_set(0); + xs_temp = x; + ys_temp = (vid->lastline - vid->firstline) << 1; + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xs_temp < 64) xs_temp = 656; + if (ys_temp < 32) ys_temp = 400; + if (!enable_overscan) + xs_temp -= 16; + + if (((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan) { + if (!dev->is_sl2 && vid->composite) + video_blit_memtoscreen(0, (vid->firstline - 4) << 1, 0, ((vid->lastline - vid->firstline) + 8) << 1, + xsize, ((vid->lastline - vid->firstline) + 8) << 1); + else + video_blit_memtoscreen_8(0, (vid->firstline - 4) << 1, 0, ((vid->lastline - vid->firstline) + 8) << 1, + xsize, ((vid->lastline - vid->firstline) + 8) << 1); + } else { + if (!dev->is_sl2 && vid->composite) + video_blit_memtoscreen(8, vid->firstline << 1, 0, (vid->lastline - vid->firstline) << 1, + xsize, (vid->lastline - vid->firstline) << 1); + else + video_blit_memtoscreen_8(8, vid->firstline << 1, 0, (vid->lastline - vid->firstline) << 1, + xsize, (vid->lastline - vid->firstline) << 1); + } } - video_blit_memtoscreen_8(0, vid->firstline-4, 0, (vid->lastline - vid->firstline) + 8, xsize, (vid->lastline - vid->firstline) + 8); - frames++; - video_res_x = xsize - 16; + + video_res_x = xsize; video_res_y = ysize; if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ video_res_x /= 2; - video_bpp = 4; + video_bpp = 4; } else if (vid->array[3] & 0x10) { /*160x200x16*/ video_res_x /= 4; video_bpp = 4; } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ - video_bpp = 2; + video_bpp = 2; } else if (vid->mode & 1) { video_res_x /= 8; video_res_y /= vid->crtc[9] + 1; @@ -1352,6 +1104,8 @@ vid_init(tandy_t *dev) vid->memctrl = -1; dev->vid = vid; + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); + display_type = machine_get_config_int("display_type"); vid->composite = (display_type != TANDY_RGB); @@ -1363,13 +1117,9 @@ vid_init(tandy_t *dev) overscan_x = overscan_y = 16; io_sethandler(0x0065, 1, vid_in,NULL,NULL, vid_out,NULL,NULL, dev); - - timer_add(vid_poll_sl, &vid->vidtime, TIMER_ALWAYS_ENABLED, dev); - } else { + } else vid->b8000_mask = 0x3fff; - - timer_add(vid_poll, &vid->vidtime, TIMER_ALWAYS_ENABLED, dev); - } + timer_add(&vid->timer, vid_poll, dev, 1); mem_mapping_add(&vid->mapping, 0xb8000, 0x08000, vid_read,NULL,NULL, vid_write,NULL,NULL, NULL, 0, dev); io_sethandler(0x03d0, 16, @@ -1529,13 +1279,13 @@ eep_init(const device_t *info) eep = (t1keep_t *)malloc(sizeof(t1keep_t)); memset(eep, 0x00, sizeof(t1keep_t)); - eep->romset = romset; - switch (romset) { - case ROM_TANDY1000HX: + + switch (info->local) { + case TYPE_TANDY1000HX: eep->path = L"tandy1000hx.bin"; break; - case ROM_TANDY1000SL2: + case TYPE_TANDY1000SL2: eep->path = L"tandy1000sl2.bin"; break; @@ -1569,9 +1319,18 @@ eep_close(void *priv) } -static const device_t eep_device = { - "Tandy 1000 EEPROM", - 0, 0, +static const device_t eep_1000hx_device = { + "Tandy 1000HX EEPROM", + 0, TYPE_TANDY1000HX, + eep_init, eep_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +static const device_t eep_1000sl2_device = { + "Tandy 1000SL2 EEPROM", + 0, TYPE_TANDY1000SL2, eep_init, eep_close, NULL, NULL, NULL, NULL, NULL @@ -1712,8 +1471,8 @@ init_rom(tandy_t *dev) } -void -machine_tandy1k_init(const machine_t *model) +static void +machine_tandy1k_init(const machine_t *model, int type) { tandy_t *dev; @@ -1738,8 +1497,8 @@ machine_tandy1k_init(const machine_t *model) device_add(&fdc_xt_device); - switch(romset) { - case ROM_TANDY: + switch(type) { + case TYPE_TANDY: io_sethandler(0x00a0, 1, tandy_read,NULL,NULL,tandy_write,NULL,NULL,dev); vid_init(dev); @@ -1747,16 +1506,16 @@ machine_tandy1k_init(const machine_t *model) device_add(&sn76489_device); break; - case ROM_TANDY1000HX: + case TYPE_TANDY1000HX: io_sethandler(0x00a0, 1, tandy_read,NULL,NULL,tandy_write,NULL,NULL,dev); vid_init(dev); device_add_ex(&vid_device, dev); device_add(&ncr8496_device); - device_add(&eep_device); + device_add(&eep_1000hx_device); break; - case ROM_TANDY1000SL2: + case TYPE_TANDY1000SL2: dev->is_sl2 = 1; init_rom(dev); io_sethandler(0xffe8, 8, @@ -1764,7 +1523,7 @@ machine_tandy1k_init(const machine_t *model) vid_init(dev); device_add_ex(&vid_device_sl, dev); device_add(&pssj_device); - device_add(&eep_device); + device_add(&eep_1000sl2_device); } if (joystick_type != 7) @@ -1779,3 +1538,55 @@ tandy1k_eeprom_read(void) { return(eep_data_out); } + + +int +machine_tandy_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linearr(L"roms/machines/tandy/tandy1t1.020", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_tandy1k_init(model, TYPE_TANDY); + + return ret; +} + + +int +machine_tandy1000hx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/tandy1000hx/v020000.u12", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_tandy1k_init(model, TYPE_TANDY1000HX); + + return ret; +} + + +int +machine_tandy1000sl2_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/tandy1000sl2/8079047.hu1", + L"roms/machines/tandy1000sl2/8079048.hu2", + 0x000f0000, 65536, 0x18000); + + if (bios_only || !ret) + return ret; + + machine_tandy1k_init(model, TYPE_TANDY1000SL2); + + return ret; +} diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 3878c98b1..22a01c882 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -4,26 +4,266 @@ #include #include "../86box.h" #include "../nmi.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../device.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../game/gameport.h" +#include "../ibm_5161.h" #include "../keyboard.h" +#include "../rom.h" #include "machine.h" -void -machine_xt_init(const machine_t *model) +static void +machine_xt_common_init(const machine_t *model) { machine_common_init(model); - pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); - device_add(&keyboard_xt_device); device_add(&fdc_xt_device); nmi_init(); if (joystick_type != 7) device_add(&gameport_device); } + + +int +machine_pc_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ibmpc/BIOS_5150_24APR81_U33.BIN", + 0x000fe000, 40960, 0); + if (ret) { + bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U29 - 5700019.bin", + 0x000f6000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U30 - 5700027.bin", + 0x000f8000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U31 - 5700035.bin", + 0x000fa000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U32 - 5700043.bin", + 0x000fc000, 8192, 0); + } + + if (bios_only || !ret) + return ret; + + device_add(&keyboard_pc_device); + + machine_xt_common_init(model); + + return ret; +} + + +int +machine_pc82_init(const machine_t *model) +{ + int ret, ret2; + + ret = bios_load_linear(L"roms/machines/ibmpc82/pc102782.bin", + 0x000fe000, 40960, 0); + if (ret) { + ret2 = bios_load_aux_linear(L"roms/machines/ibmpc82/ibm-basic-1.10.rom", + 0x000f6000, 32768, 0); + if (!ret2) { + bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.f6", + 0x000f6000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.f8", + 0x000f8000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.fa", + 0x000fa000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.fc", + 0x000fc000, 8192, 0); + } + } + + if (bios_only || !ret) + return ret; + + device_add(&keyboard_pc82_device); + device_add(&ibm_5161_device); + + machine_xt_common_init(model); + + return ret; +} + + +static void +machine_xt_init_ex(const machine_t *model) +{ + device_add(&keyboard_xt_device); + + machine_xt_common_init(model); +} + + +int +machine_xt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ibmxt/xt.rom", + 0x000f0000, 65536, 0); + if (!ret) { + ret = bios_load_linear(L"roms/machines/ibmxt/1501512.u18", + 0x000fe000, 65536, 0x6000); + if (ret) { + bios_load_aux_linear(L"roms/machines/ibmxt/1501512.u18", + 0x000f8000, 24576, 0); + bios_load_aux_linear(L"roms/machines/ibmxt/5000027.u19", + 0x000f0000, 32768, 0); + } + } + + if (bios_only || !ret) + return ret; + + machine_xt_init_ex(model); + + device_add(&ibm_5161_device); + + return ret; +} + + +int +machine_genxt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/genxt/pcxt.rom", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_init_ex(model); + + return ret; +} + + +int +machine_xt86_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", + 0x000fe000, 65536, 0x6000); + if (ret) { + bios_load_aux_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", + 0x000f8000, 24576, 0); + bios_load_aux_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U19_62X0819_68X4370_27256_F000.BIN", + 0x000f0000, 32768, 0); + } + + if (bios_only || !ret) + return ret; + + device_add(&keyboard_xt86_device); + device_add(&ibm_5161_device); + + machine_xt_common_init(model); + + return ret; +} + + +static void +machine_xt_clone_init(const machine_t *model) +{ + device_add(&keyboard_xt86_device); + + machine_xt_common_init(model); +} + + +int +machine_xt_amixt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/amixt/ami_8088_bios_31jan89.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_dtk_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/dtk/dtk_erso_2.42_2764.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_jukopc_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/jukopc/000o001.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_open_xt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/open_xt/pcxt31.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_pxxt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/pxxt/000p001.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return 1; +} diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c index 751e45da8..6af9079fa 100644 --- a/src/machine/m_xt_compaq.c +++ b/src/machine/m_xt_compaq.c @@ -8,14 +8,14 @@ * * Emulation of various Compaq XT-class PC's. * - * Version: @(#)m_xt_compaq.c 1.0.4 2018/03/18 + * Version: @(#)m_xt_compaq.c 1.0.5 2019/11/15 * * Authors: Sarah Walker, * Miran Grca, * TheCollector1995, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -24,6 +24,7 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../nmi.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" @@ -36,23 +37,29 @@ #include "machine.h" -void +int machine_xt_compaq_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/portable/compaq portable plus 100666-001 rev c u47.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + machine_common_init(model); - pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); - device_add(&keyboard_xt_device); + device_add(&keyboard_xt_compaq_device); device_add(&fdc_xt_device); nmi_init(); if (joystick_type != 7) device_add(&gameport_device); - switch(model->id) { - case ROM_PORTABLE: - lpt1_remove(); - lpt1_init(0x03bc); - break; - } + lpt1_remove(); + lpt1_init(0x03bc); + + return ret; } diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index fe5d86606..0b06a238b 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -7,21 +7,31 @@ #include "../cpu/cpu.h" #include "../io.h" #include "../mem.h" +#include "../nmi.h" +#include "../timer.h" +#include "../pit.h" #include "../rom.h" #include "machine.h" +#include "../device.h" +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../keyboard.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 int laserxt_is_lxt3 = 0; 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); + addr = (!laserxt_is_lxt3 ? 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; @@ -56,14 +66,6 @@ static void laserxt_write(uint16_t port, uint8_t val, void *priv) { laserxt_ems_baseaddr_index |= (laserxt_emscontrol[i] & 0x80) >> (7 - i); } - if(laserxt_ems_baseaddr_index < 3) - { - mem_mapping_disable(&romext_mapping); - } - else - { - mem_mapping_enable(&romext_mapping); - } 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); @@ -107,7 +109,7 @@ static uint8_t mem_read_laserxtems(uint32_t addr, void *priv) } -static void laserxt_init(void) +static void laserxt_init(int is_lxt3) { int i; @@ -117,7 +119,7 @@ static void laserxt_init(void) 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)); + mem_mapping_set_addr(&ram_low_mapping, 0, !is_lxt3 ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)); } for (i = 0; i < 4; i++) @@ -127,14 +129,52 @@ static void laserxt_init(void) 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(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + laserxt_is_lxt3 = is_lxt3; } -void +int machine_xt_laserxt_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/ltxt/27c64.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + machine_xt_init(model); - laserxt_init(); + laserxt_init(0); + + return ret; +} + + +int +machine_xt_lxt3_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/lxt3/27c64d.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_common_init(model); + + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + + device_add(&keyboard_xt_lxt3_device); + device_add(&fdc_xt_device); + nmi_init(); + if (joystick_type != 7) + device_add(&gameport_device); + + laserxt_init(1); + + return ret; } diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index 2b5d33186..3471b0c12 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -51,15 +51,15 @@ * NOTE: Still need to figure out a way to load/save ConfigSys and * HardRAM stuff. Needs to be linked in to the NVR code. * - * Version: @(#)m_xt_t1000.c 1.0.6 2018/04/29 + * Version: @(#)m_xt_t1000.c 1.0.14 2019/11/15 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2018 Miran Grca. - * Copyright 2018 Sarah Walker. + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2018,2019 Miran Grca. + * Copyright 2018,2019 Sarah Walker. * * 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 @@ -90,6 +90,7 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../nmi.h" #include "../mem.h" @@ -145,7 +146,7 @@ typedef struct { /* CONFIG.SYS drive. */ uint8_t t1000_nvram[160]; - uint8_t t1200_nvram[160]; + uint8_t t1200_nvram[2048]; /* System control registers */ uint8_t sys_ctl[16]; @@ -172,6 +173,7 @@ typedef struct { fdc_t *fdc; nvr_t nvr; + int is_t1200; } t1000_t; @@ -180,13 +182,11 @@ static t1000_t t1000; #ifdef ENABLE_T1000_LOG int t1000_do_log = ENABLE_T1000_LOG; -#endif static void t1000_log(const char *fmt, ...) { -#ifdef ENABLE_TANDY_LOG va_list ap; if (t1000_do_log) @@ -195,8 +195,10 @@ t1000_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define t1000_log(fmt, ...) +#endif /* Set the chip time. */ @@ -258,7 +260,7 @@ tc8521_start(nvr_t *nvr) struct tm tm; /* Initialize the internal and chip times. */ - if (enable_sync) { + if (time_sync & TIME_SYNC_ENABLED) { /* Use the internal clock's time. */ nvr_time_get(&tm); tc8521_time_set(nvr->regs, &tm); @@ -419,7 +421,7 @@ ems_set_hardram(t1000_t *sys, uint8_t val) #if 0 t1000_log("EMS base set to %02x\n", val); #endif - sys->ems_pages = 48 - 4 * sys->ems_base; + sys->ems_pages = ((mem_size - 512) / 16) - 4 * sys->ems_base; if (sys->ems_pages < 0) sys->ems_pages = 0; /* Recalculate EMS mappings */ @@ -446,9 +448,9 @@ ems_set_port(t1000_t *sys, uint8_t val) { int n; -#if 0 +#if 0 t1000_log("ems_set_port(%d)", val & 0x0f); -#endif +#endif if (sys->ems_port) { for (n = 0; n <= 0xc000; n += 0x4000) { io_removehandler(sys->ems_port+n, 1, @@ -600,7 +602,7 @@ read_ctl(uint16_t addr, void *priv) case 0x0f: /* Detect EMS board */ switch (sys->sys_ctl[0x0e]) { case 0x50: - if (mem_size > 512) break; + if (mem_size > 512) ret = (0x90 | sys->ems_port_index); break; @@ -648,11 +650,20 @@ write_ctl(uint16_t addr, uint8_t val, void *priv) 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) + if (sys->is_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 (sys->is_t1200) + { + t1000_video_enable(val & 0x01 ? 0 : 1); + } + break; + case 0x0f: /* EMS control */ switch (sys->sys_ctl[0x0e]) { case 0x50: @@ -837,13 +848,22 @@ t1000_get_device(void) } -void +int machine_xt_t1000_init(const machine_t *model) { FILE *f; int pg; + int ret; + + ret = bios_load_linear(L"roms/machines/t1000/t1000.rom", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + memset(&t1000, 0x00, sizeof(t1000)); + t1000.is_t1200 = 0; t1000.turbo = 0xff; t1000.ems_port_index = 7; /* EMS disabled */ @@ -897,14 +917,20 @@ machine_xt_t1000_init(const machine_t *model) machine_common_init(model); - pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); device_add(&keyboard_xt_device); t1000.fdc = device_add(&fdc_xt_device); nmi_init(); tc8521_init(&t1000.nvr, model->nvrmask + 1); - device_add(&t1000_video_device); + t1000_nvr_load(); + nvr_set_ven_save(t1000_nvr_save); + + if (gfxcard == VID_INTERNAL) + device_add(&t1000_video_device); + + return ret; } @@ -915,12 +941,21 @@ t1200_get_device(void) } -void +int machine_xt_t1200_init(const machine_t *model) { int pg; + int ret; + + ret = bios_load_linear(L"roms/machines/t1200/t1200_019e.ic15.bin", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + memset(&t1000, 0x00, sizeof(t1000)); + t1000.is_t1200 = 1; t1000.ems_port_index = 7; /* EMS disabled */ /* Load the T1200 CGA Font ROM. */ @@ -950,14 +985,20 @@ machine_xt_t1200_init(const machine_t *model) write_t1200_nvram, NULL, NULL, NULL, 0, &t1000); - pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); device_add(&keyboard_xt_device); - t1000.fdc = device_add(&fdc_xt_device); + t1000.fdc = device_add(&fdc_xt_t1x00_device); nmi_init(); tc8521_init(&t1000.nvr, model->nvrmask + 1); - device_add(&t1200_video_device); + t1200_nvr_load(); + nvr_set_ven_save(t1200_nvr_save); + + if (gfxcard == VID_INTERNAL) + device_add(&t1200_video_device); + + return ret; } @@ -1002,7 +1043,7 @@ t1200_state_load(void) { FILE *f; - memset(t1000.t1200_nvram, 0x1a, sizeof(t1000.t1200_nvram)); + memset(t1000.t1200_nvram, 0, sizeof(t1000.t1200_nvram)); f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"rb"); if (f != NULL) { fread(t1000.t1200_nvram, sizeof(t1000.t1200_nvram), 1, f); diff --git a/src/machine/m_xt_t1000.h b/src/machine/m_xt_t1000.h index 3a345fcbc..d76b792e1 100644 --- a/src/machine/m_xt_t1000.h +++ b/src/machine/m_xt_t1000.h @@ -8,7 +8,7 @@ * * Definitions for the Toshiba T1000/T1200 machines. * - * Version: @(#)m_xt_t1000.h 1.0.4 2018/03/19 + * Version: @(#)m_xt_t1000.h 1.0.5 2018/08/15 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -45,6 +45,7 @@ extern const device_t t1200_video_device; extern void t1000_video_options_set(uint8_t options); +extern void t1000_video_enable(uint8_t enabled); extern void t1000_display_set(uint8_t internal); extern void t1000_syskey(uint8_t amask, uint8_t omask, uint8_t xmask); diff --git a/src/machine/m_xt_t1000_vid.c b/src/machine/m_xt_t1000_vid.c index 01b184fde..1e2d62e13 100644 --- a/src/machine/m_xt_t1000_vid.c +++ b/src/machine/m_xt_t1000_vid.c @@ -9,15 +9,15 @@ * Implementation of the Toshiba T1000 plasma display, which * has a fixed resolution of 640x200 pixels. * - * Version: @(#)m_xt_t1000_vid.c 1.0.7 2018/04/29 + * Version: @(#)m_xt_t1000_vid.c 1.0.12 2019/10/01 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2018 Miran Grca. - * Copyright 2018 Sarah Walker. + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2018,2019 Miran Grca. + * Copyright 2018,2019 Sarah Walker. * * 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 @@ -64,6 +64,8 @@ static uint32_t blinkcols[256][2]; static uint32_t normcols[256][2]; static uint8_t language; +static video_timings_t timing_t1000 = {VIDEO_ISA, 8,16,32, 8,16,32}; + /* Video options set by the motherboard; they will be picked up by the card * on the next poll. @@ -72,6 +74,7 @@ static uint8_t language; * Bit 0: Thin font */ static uint8_t st_video_options; +static uint8_t st_enabled = 1; static int8_t st_display_internal = -1; void t1000_video_options_set(uint8_t options) @@ -80,6 +83,11 @@ void t1000_video_options_set(uint8_t options) st_video_options |= language; } +void t1000_video_enable(uint8_t enabled) +{ + st_enabled = enabled; +} + void t1000_display_set(uint8_t internal) { st_display_internal = (int8_t)internal; @@ -104,7 +112,7 @@ typedef struct t1000_t int internal; /* Using internal display? */ uint8_t attrmap; /* Attribute mapping register */ - int dispontime, dispofftime; + uint64_t dispontime, dispofftime; int linepos, displine; int vc; @@ -186,14 +194,14 @@ static void t1000_write(uint32_t addr, uint8_t val, void *p) egawrites++; t1000->vram[addr & 0x3fff] = val; - cycles -= 4; + sub_cycles(4); } static uint8_t t1000_read(uint32_t addr, void *p) { t1000_t *t1000 = (t1000_t *)p; egareads++; - cycles -= 4; + sub_cycles(4); return t1000->vram[addr & 0x3fff]; } @@ -213,8 +221,8 @@ static void t1000_recalctimings(t1000_t *t1000) disptime = 651; _dispontime = 640; _dispofftime = disptime - _dispontime; - t1000->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - t1000->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + t1000->dispontime = (uint64_t)(_dispontime * xt_cpu_multi); + t1000->dispofftime = (uint64_t)(_dispofftime * xt_cpu_multi); } /* Draw a row of text in 80-column mode */ @@ -457,12 +465,19 @@ static void t1000_poll(void *p) { t1000_t *t1000 = (t1000_t *)p; - if (t1000->video_options != st_video_options) + 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) @@ -478,7 +493,7 @@ static void t1000_poll(void *p) if (!t1000->linepos) { - t1000->cga.vidtime += t1000->dispofftime; + timer_advance_u64(&t1000->cga.timer, t1000->dispofftime); t1000->cga.cgastat |= 1; t1000->linepos = 1; if (t1000->dispon) @@ -525,19 +540,22 @@ static void t1000_poll(void *p) { t1000->cga.cgastat &= ~1; } - t1000->cga.vidtime += t1000->dispontime; + 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) + if ((T1000_XSIZE != xsize) || (T1000_YSIZE != ysize) || video_force_resize_get()) { xsize = T1000_XSIZE; ysize = T1000_YSIZE; if (xsize < 64) xsize = 656; if (ysize < 32) ysize = 200; set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); } video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); @@ -660,14 +678,17 @@ static void *t1000_init(const device_t *info) { t1000_t *t1000 = malloc(sizeof(t1000_t)); memset(t1000, 0, sizeof(t1000_t)); + loadfont(L"roms/machines/t1000/t1000font.bin", 8); cga_init(&t1000->cga); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t1000); t1000->internal = 1; /* 16k video RAM */ t1000->vram = malloc(0x4000); - timer_add(t1000_poll, &t1000->cga.vidtime, TIMER_ALWAYS_ENABLED, t1000); + 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); @@ -684,7 +705,7 @@ static void *t1000_init(const device_t *info) t1000->enabled = 1; t1000->video_options = 0x01; language = device_get_config_int("display_language") ? 2 : 0; - return t1000; + return t1000; } static void t1000_close(void *p) diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index 13d1c20b8..101e8a0ae 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -3,6 +3,7 @@ #include #include #include "../86box.h" +#include "../timer.h" #include "../pic.h" #include "../pit.h" #include "../dma.h" @@ -15,7 +16,9 @@ #include "../game/gameport.h" #include "../keyboard.h" #include "../lpt.h" +#include "../rom.h" #include "../disk/hdc.h" +#include "../video/video.h" #include "machine.h" #include "../cpu/cpu.h" @@ -29,52 +32,54 @@ typedef struct xi8088_t int bios_128kb; } xi8088_t; -static xi8088_t xi8088; -uint8_t xi8088_turbo_get() +static xi8088_t xi8088; + + +uint8_t +xi8088_turbo_get() { - return xi8088.turbo; + 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"); - int c = cpu; - cpu = 0; /* 8088/4.77 */ - cpu_set(); - cpu = c; - } - else - { - pclog("Xi8088 turbo on\n"); - cpu_set(); - } +void +xi8088_turbo_set(uint8_t value) +{ + int c; + + if (!xi8088.turbo_setting) + return; + + xi8088.turbo = value; + if (!value) { + c = cpu; + cpu = 0; /* 8088/4.77 */ + cpu_set(); + cpu = c; + } else + cpu_set(); } -void xi8088_bios_128kb_set(int val) + +int +xi8088_bios_128kb(void) { - xi8088.bios_128kb = val; + return xi8088.bios_128kb; } -int xi8088_bios_128kb() + +static void * +xi8088_init(const device_t *info) { - return xi8088.bios_128kb; + /* even though the bios by default turns the turbo off when controlling by hotkeys, pcem always starts at full speed */ + xi8088.turbo = 1; + xi8088.turbo_setting = device_get_config_int("turbo_setting"); + xi8088.bios_128kb = device_get_config_int("bios_128kb"); + + return &xi8088; } -static void *xi8088_init() -{ - /* even though the bios by default turns the turbo off when controlling by hotkeys, pcem always starts at full speed */ - xi8088.turbo = 1; - xi8088.turbo_setting = device_get_config_int("turbo_setting"); - - return &xi8088; -} static const device_config_t xi8088_config[] = { @@ -95,6 +100,23 @@ static const device_config_t xi8088_config[] = }, .default_int = 0 }, + { + .name = "bios_128kb", + .description = "BIOS size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "64KB", + .value = 0 + }, + { + .description = "128KB", + .value = 1 + } + }, + .default_int = 1 + }, { .type = -1 } @@ -115,21 +137,46 @@ const device_t xi8088_device = xi8088_config }; + const device_t * xi8088_get_device(void) { return &xi8088_device; } -void machine_xt_xi8088_init(const machine_t *model) + +int +machine_xt_xi8088_init(const machine_t *model) { - /* TODO: set UMBs? See if PCem always sets when we have > 640KB ram and avoids conflicts when a peripheral uses the same memory space */ - machine_common_init(model); - device_add(&fdc_xt_device); - device_add(&keyboard_ps2_device); - nmi_init(); - device_add(&at_nvr_device); - pic2_init(); - if (joystick_type != 7) - device_add(&gameport_device); + int ret; + + if (bios_only) { + ret = bios_load_linear(L"roms/machines/xi8088/bios-xi8088.bin", + 0x000f0000, 65536, 0); + } else { + device_add(&xi8088_device); + + if (xi8088_bios_128kb()) { + ret = bios_load_linear_inverted(L"roms/machines/xi8088/bios-xi8088.bin", + 0x000e0000, 131072, 0); + } else { + ret = bios_load_linear(L"roms/machines/xi8088/bios-xi8088.bin", + 0x000f0000, 65536, 0); + } + } + + if (bios_only || !ret) + return ret; + + /* TODO: set UMBs? See if PCem always sets when we have > 640KB ram and avoids conflicts when a peripheral uses the same memory space */ + machine_common_init(model); + device_add(&fdc_at_device); + device_add(&keyboard_ps2_xi8088_device); + nmi_init(); + device_add(&ibmat_nvr_device); + pic2_init(); + if (joystick_type != 7) + device_add(&gameport_device); + + return ret; } diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c new file mode 100644 index 000000000..23b44199d --- /dev/null +++ b/src/machine/m_xt_zenith.c @@ -0,0 +1,132 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of various Zenith PC compatible machines. + * Currently only the Zenith Data Systems Supersport is emulated. + * + * Version: @(#)m_xt_compaq.c 1.0.1 2019/11/15 + * + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../dma.h" +#include "../nmi.h" +#include "../pic.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../serial.h" +#include "machine.h" + + +typedef struct { + mem_mapping_t scratchpad_mapping; + uint8_t *scratchpad_ram; +} zenith_t; + + +static uint8_t +zenith_scratchpad_read(uint32_t addr, void *p) +{ + zenith_t *dev = (zenith_t *)p; + return dev->scratchpad_ram[addr & 0x3fff]; +} + + +static void +zenith_scratchpad_write(uint32_t addr, uint8_t val, void *p) +{ + zenith_t *dev = (zenith_t *)p; + dev->scratchpad_ram[addr & 0x3fff] = val; +} + + +static void * +zenith_scratchpad_init(const device_t *info) +{ + zenith_t *dev; + + dev = (zenith_t *)malloc(sizeof(zenith_t)); + memset(dev, 0x00, sizeof(zenith_t)); + + dev->scratchpad_ram = malloc(0x4000); + + mem_mapping_add(&dev->scratchpad_mapping, 0xf0000, 0x4000, + zenith_scratchpad_read, NULL, NULL, + zenith_scratchpad_write, NULL, NULL, + dev->scratchpad_ram, MEM_MAPPING_EXTERNAL, dev); + + return dev; +} + + +static void +zenith_scratchpad_close(void *p) +{ + zenith_t *dev = (zenith_t *)p; + + free(dev->scratchpad_ram); + free(dev); +} + + +static const device_t zenith_scratchpad_device = { + "Zenith scratchpad RAM", + 0, 0, + zenith_scratchpad_init, zenith_scratchpad_close, NULL, + NULL, + NULL, + NULL +}; + + +int +machine_xt_zenith_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/zdsupers/z184m v3.1d.10d", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + machine_common_init(model); + + device_add(&fdc_xt_device); + lpt1_remove(); /* only one parallel port */ + lpt2_remove(); + lpt1_init(0x278); + device_add(&i8250_device); + serial_set_next_inst(2); /* So that serial_standalone_init() won't do anything. */ + device_add(&zenith_scratchpad_device); + pit_ctr_set_out_func(&pit->counters[1], pit_refresh_timer_xt); + device_add(&keyboard_xt_compaq_device); + nmi_init(); + + return ret; +} diff --git a/src/machine/machine.c b/src/machine/machine.c index 9396de0ba..c2f19bd47 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.c 1.0.34 2018/04/29 + * Version: @(#)machine.c 1.0.38 2019/11/15 * * Authors: Sarah Walker, * Miran Grca, @@ -26,6 +26,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../device.h" +#include "../timer.h" #include "../dma.h" #include "../pic.h" #include "../pit.h" @@ -34,23 +35,22 @@ #include "../lpt.h" #include "../serial.h" #include "../cpu/cpu.h" +#include "../video/video.h" #include "machine.h" +int bios_only = 0; int machine; int AT, PCI; -int romset; #ifdef ENABLE_MACHINE_LOG int machine_do_log = ENABLE_MACHINE_LOG; -#endif static void machine_log(const char *fmt, ...) { -#ifdef ENABLE_TANDY_LOG va_list ap; if (machine_do_log) @@ -59,28 +59,63 @@ machine_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define machine_log(fmt, ...) #endif + + +static int +machine_init_ex(int m) +{ + int ret = 0; + + if (!bios_only) { + machine_log("Initializing as \"%s\"\n", machine_getname_ex(m)); + + /* Set up the architecture flags. */ + AT = IS_ARCH(machine, MACHINE_AT); + PCI = IS_ARCH(machine, MACHINE_PCI); + + /* Resize the memory. */ + mem_reset(); + + lpt_init(); + } + + /* All good, boot the machine! */ + if (machines[m].init) + ret = machines[m].init(&machines[m]); + + if (bios_only || !ret) + return ret; + + /* Reset the graphics card (or do nothing if it was already done + by the machine's init function). */ + video_reset(gfxcard); + + return ret; } void machine_init(void) { - machine_log("Initializing as \"%s\"\n", machine_getname()); + bios_only = 0; + (void) machine_init_ex(machine); +} - /* Set up the architecture flags. */ - AT = IS_ARCH(machine, MACHINE_AT); - PCI = IS_ARCH(machine, MACHINE_PCI); - /* Resize the memory. */ - mem_reset(); +int +machine_available(int m) +{ + int ret; - /* Load the machine's ROM BIOS. */ - rom_load_bios(romset); - mem_add_bios(); + bios_only = 1; + ret = machine_init_ex(m); - /* All good, boot the machine! */ - machines[machine].init(&machines[machine]); + bios_only = 0; + return ret; } @@ -90,20 +125,8 @@ machine_common_init(const machine_t *model) /* System devices first. */ pic_init(); dma_init(); - pit_init(); cpu_set(); - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) - setrtcconst(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - else - setrtcconst(14318184.0); - if (lpt_enabled) - lpt_init(); - - if (serial_enabled[0]) - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - - if (serial_enabled[1]) - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + pit_common_init(!!AT, pit_irq0_timer, NULL); } diff --git a/src/machine/machine.h b/src/machine/machine.h index 89228c5eb..7d4b52ab7 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -8,21 +8,22 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.h 1.0.24 2018/05/10 + * Version: @(#)machine.h 1.0.34 2019/03/08 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_MACHINE_H # define EMU_MACHINE_H /* Machine feature flags. */ +#ifdef NEW_FLAGS #define MACHINE_PC 0x000000 /* PC architecture */ #define MACHINE_AT 0x000001 /* PC/AT architecture */ #define MACHINE_PS2 0x000002 /* PS/2 architecture */ @@ -34,16 +35,56 @@ #define MACHINE_PCI 0x000200 /* sys has PCI bus */ #define MACHINE_AGP 0x000400 /* sys has AGP bus */ #define MACHINE_HDC 0x001000 /* sys has int HDC */ -#define MACHINE_HDC_PS2 0x002000 /* sys has int PS/2 HDC */ -#define MACHINE_MOUSE 0x004000 /* sys has int mouse */ -#define MACHINE_VIDEO 0x008000 /* sys has int video */ +#define MACHINE_VIDEO 0x002000 /* sys has int video */ +#define MACHINE_VIDEO_FIXED 0x004000 /* sys has ONLY int video */ +#define MACHINE_MOUSE 0x008000 /* sys has int mouse */ +#define MACHINE_NONMI 0x010000 /* sys does not have NMI's */ +#else +#define MACHINE_PC 0x000000 /* PC architecture */ +#define MACHINE_AT 0x000001 /* PC/AT architecture */ +#define MACHINE_PS2 0x000002 /* PS/2 architecture */ +#define MACHINE_ISA 0x000010 /* sys has ISA bus */ +#define MACHINE_CBUS 0x000020 /* sys has C-BUS bus */ +#define MACHINE_EISA 0x000040 /* sys has EISA bus */ +#define MACHINE_VLB 0x000080 /* sys has VL bus */ +#define MACHINE_MCA 0x000100 /* sys has MCA bus */ +#define MACHINE_PCI 0x000200 /* sys has PCI bus */ +#define MACHINE_AGP 0x000400 /* sys has AGP bus */ +#define MACHINE_HDC 0x001000 /* sys has int HDC */ +#define MACHINE_VIDEO 0x002000 /* sys has int video */ +#define MACHINE_VIDEO_FIXED 0x004000 /* sys has ONLY int video */ +#define MACHINE_MOUSE 0x008000 /* sys has int mouse */ +#define MACHINE_NONMI 0x010000 /* sys does not have NMI's */ +#endif #define IS_ARCH(m, a) (machines[(m)].flags & (a)) ? 1 : 0; +#ifdef NEW_STRUCT +typedef struct _machine_ { + const char *name; + const char *internal_name; +#ifdef EMU_DEVICE_H + const device_t *device; +#else + void *device; +#endif + struct { + const char *name; +#ifdef EMU_CPU_H + CPU *cpus; +#else + void *cpus; +#endif + } cpu[5]; + int flags; + uint32_t min_ram, max_ram; + int ram_granularity; + int nvrmask; +} machine_t; +#else typedef struct _machine_ { const char *name; - int id; const char *internal_name; struct { const char *name; @@ -53,39 +94,37 @@ typedef struct _machine_ { void *cpus; #endif } cpu[5]; - int fixed_gfxcard; int flags; uint32_t min_ram, max_ram; int ram_granularity; int nvrmask; - void (*init)(const struct _machine_ *); + int (*init)(const struct _machine_ *); #ifdef EMU_DEVICE_H const device_t *(*get_device)(void); #else void *get_device; #endif } machine_t; +#endif /* Global variables. */ extern const machine_t machines[]; +extern int bios_only; extern int machine; -extern int romset; extern int AT, PCI; /* Core functions. */ extern int machine_count(void); -extern int machine_getromset(void); -extern int machine_getmachine(int romset); +extern int machine_available(int m); extern char *machine_getname(void); extern char *machine_get_internal_name(void); extern int machine_get_machine_from_internal_name(char *s); extern void machine_init(void); #ifdef EMU_DEVICE_H -extern const device_t *machine_getdevice(int machine); +extern const device_t *machine_getdevice(int m); #endif -extern int machine_getromset_ex(int m); extern char *machine_get_internal_name_ex(int m); extern int machine_get_nvrmask(int m); extern void machine_close(void); @@ -94,123 +133,255 @@ extern void machine_close(void); /* Initialization functions for boards and systems. */ extern void machine_common_init(const machine_t *); +/* m_amstrad.c */ +extern int machine_pc1512_init(const machine_t *); +extern int machine_pc1640_init(const machine_t *); +extern int machine_pc200_init(const machine_t *); +extern int machine_ppc512_init(const machine_t *); +extern int machine_pc2086_init(const machine_t *); +extern int machine_pc3086_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *pc1512_get_device(void); +extern const device_t *pc1640_get_device(void); +extern const device_t *pc200_get_device(void); +extern const device_t *ppc512_get_device(void); +extern const device_t *pc2086_get_device(void); +extern const device_t *pc3086_get_device(void); +#endif + +/* m_at.c */ +extern void machine_at_common_init_ex(const machine_t *, int is_ibm); extern void machine_at_common_init(const machine_t *); extern void machine_at_init(const machine_t *); extern void machine_at_ps2_init(const machine_t *); extern void machine_at_common_ide_init(const machine_t *); +extern void machine_at_ibm_common_ide_init(const machine_t *); extern void machine_at_ide_init(const machine_t *); extern void machine_at_ps2_ide_init(const machine_t *); -extern void machine_at_top_remap_init(const machine_t *); -extern void machine_at_ide_top_remap_init(const machine_t *); -extern void machine_at_ibm_init(const machine_t *); +extern int machine_at_ibm_init(const machine_t *); -extern void machine_at_t3100e_init(const machine_t *); +//IBM AT with custom BIOS +extern int machine_at_ibmatami_init(const machine_t *); // IBM AT with AMI BIOS +extern int machine_at_ibmatpx_init(const machine_t *); //IBM AT with Phoenix BIOS +extern int machine_at_ibmatquadtel_init(const machine_t *); // IBM AT with Quadtel BIOS -extern void machine_at_p54tp4xe_init(const machine_t *); -extern void machine_at_endeavor_init(const machine_t *); -extern void machine_at_zappa_init(const machine_t *); -extern void machine_at_mb500n_init(const machine_t *); -extern void machine_at_president_init(const machine_t *); -extern void machine_at_thor_init(const machine_t *); -extern void machine_at_pb640_init(const machine_t *); +extern int machine_at_ibmxt286_init(const machine_t *); -extern void machine_at_acerm3a_init(const machine_t *); -extern void machine_at_acerv35n_init(const machine_t *); -extern void machine_at_ap53_init(const machine_t *); -extern void machine_at_p55t2p4_init(const machine_t *); -extern void machine_at_p55t2s_init(const machine_t *); - -extern void machine_at_batman_init(const machine_t *); -extern void machine_at_plato_init(const machine_t *); - -extern void machine_at_p55tvp4_init(const machine_t *); -extern void machine_at_i430vx_init(const machine_t *); -extern void machine_at_p55va_init(const machine_t *); - -#if defined(DEV_BRANCH) && defined(USE_I686) -extern void machine_at_i440fx_init(const machine_t *); -extern void machine_at_s1668_init(const machine_t *); -#endif -extern void machine_at_ali1429_init(const machine_t *); -extern void machine_at_cmdpc_init(const machine_t *); - -extern void machine_at_headland_init(const machine_t *); -extern void machine_at_neat_init(const machine_t *); -extern void machine_at_neat_ami_init(const machine_t *); -extern void machine_at_opti495_init(const machine_t *); -extern void machine_at_opti495_ami_init(const machine_t *); -extern void machine_at_scat_init(const machine_t *); -extern void machine_at_scatsx_init(const machine_t *); -extern void machine_at_compaq_init(const machine_t *); - -extern void machine_at_dtk486_init(const machine_t *); -extern void machine_at_r418_init(const machine_t *); - -extern void machine_at_wd76c10_init(const machine_t *); - -#if defined(DEV_BRANCH) && defined(USE_GREENB) -extern void machine_at_4gpv31_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) +extern int machine_at_open_at_init(const machine_t *); #endif -extern void machine_pcjr_init(const machine_t *); +/* m_at_286_386sx.c */ +#if defined(DEV_BRANCH) && defined(USE_AMI386SX) +extern int machine_at_headland_init(const machine_t *); +#endif +extern int machine_at_tg286m_init(const machine_t *); +extern int machine_at_ama932j_init(const machine_t *); +extern int machine_at_headlandpho_init(const machine_t *); +extern int machine_at_headlandquadtel_init(const machine_t *); +extern int machine_at_iqs_init(const machine_t *); + +extern int machine_at_neat_init(const machine_t *); +extern int machine_at_neat_ami_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_MICRONICS386) +extern int machine_at_micronics386_init(const machine_t *); //Neat based Phoenix 80386 board. It has memory related issues. +#endif + +extern int machine_at_award286_init(const machine_t *); +extern int machine_at_gw286ct_init(const machine_t *); +extern int machine_at_super286tr_init(const machine_t *); +extern int machine_at_spc4200p_init(const machine_t *); +extern int machine_at_spc4216p_init(const machine_t *); +extern int machine_at_kmxc02_init(const machine_t *); +extern int machine_at_deskmaster286_init(const machine_t *); + +extern int machine_at_wd76c10_init(const machine_t *); -extern void machine_ps1_m2011_init(const machine_t *); #ifdef EMU_DEVICE_H -extern void ps1_hdc_inform(void *, void *); -extern void ps1_set_feedback(void *); -extern const device_t ps1_hdc_device; +extern const device_t *at_ama932j_get_device(void); #endif -extern void machine_ps1_m2121_init(const machine_t *); -extern void machine_ps1_m2133_init(const machine_t *); +/* m_at_386dx_486.c */ +extern int machine_at_pb410a_init(const machine_t *); -extern void machine_ps2_m30_286_init(const machine_t *); -extern void machine_ps2_model_50_init(const machine_t *); -extern void machine_ps2_model_55sx_init(const machine_t *); -extern void machine_ps2_model_70_type3_init(const machine_t *); -extern void machine_ps2_model_70_type4_init(const machine_t *); -extern void machine_ps2_model_80_init(const machine_t *); -#ifdef WALTJE -extern void machine_ps2_model_80_486_init(const machine_t *); +extern int machine_at_ali1429_init(const machine_t *); +extern int machine_at_winbios1429_init(const machine_t *); + +extern int machine_at_opti495_init(const machine_t *); +extern int machine_at_opti495_ami_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_MR495) +extern int machine_at_opti495_mr_init(const machine_t *); #endif -extern void machine_amstrad_init(const machine_t *); +extern int machine_at_ami471_init(const machine_t *); +extern int machine_at_dtk486_init(const machine_t *); +extern int machine_at_px471_init(const machine_t *); +extern int machine_at_win471_init(const machine_t *); -extern void machine_europc_init(const machine_t *); +extern int machine_at_r418_init(const machine_t *); +extern int machine_at_alfredo_init(const machine_t *); + +/* m_at_commodore.c */ +extern int machine_at_cmdpc_init(const machine_t *); + +/* m_at_compaq.c */ +extern int machine_at_portableii_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) +extern int machine_at_portableiii_init(const machine_t *); +extern int machine_at_portableiii386_init(const machine_t *); +#endif + +/* m_at_socket4_5.c */ +extern int machine_at_batman_init(const machine_t *); +extern int machine_at_ambradp60_init(const machine_t *); +extern int machine_at_586mc1_init(const machine_t *); + +extern int machine_at_plato_init(const machine_t *); +extern int machine_at_ambradp90_init(const machine_t *); +extern int machine_at_430nx_init(const machine_t *); + +extern int machine_at_p54tp4xe_init(const machine_t *); +extern int machine_at_endeavor_init(const machine_t *); +extern int machine_at_zappa_init(const machine_t *); +extern int machine_at_mb500n_init(const machine_t *); +extern int machine_at_president_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_VECTRA54) +extern int machine_at_vectra54_init(const machine_t *); +#endif + +#ifdef EMU_DEVICE_H +extern const device_t *at_endeavor_get_device(void); +#endif + +/* m_at_socket7_s7.c */ +extern int machine_at_thor_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) +extern int machine_at_mrthor_init(const machine_t *); +#endif +extern int machine_at_pb640_init(const machine_t *); + +extern int machine_at_acerm3a_init(const machine_t *); +extern int machine_at_acerv35n_init(const machine_t *); +extern int machine_at_ap53_init(const machine_t *); +extern int machine_at_p55t2p4_init(const machine_t *); +extern int machine_at_p55t2s_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +extern int machine_at_tc430hx_init(const machine_t *); +#endif + +extern int machine_at_p55tvp4_init(const machine_t *); +extern int machine_at_i430vx_init(const machine_t *); +extern int machine_at_p55va_init(const machine_t *); +extern int machine_at_j656vxd_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *at_pb640_get_device(void); +#endif + +/* m_at_socket8.c */ +#if defined(DEV_BRANCH) && defined(USE_I686) +extern int machine_at_i440fx_init(const machine_t *); +extern int machine_at_s1668_init(const machine_t *); +#endif + +/* m_at_t3100e.c */ +extern int machine_at_t3100e_init(const machine_t *); + +/* m_europc.c */ +extern int machine_europc_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t europc_device; #endif -extern void machine_olim24_init(const machine_t *); -extern void machine_olim24_video_init(void); +/* m_oivetti_m24.c */ +extern int machine_olim24_init(const machine_t *); -extern void machine_tandy1k_init(const machine_t *); -extern int tandy1k_eeprom_read(void); +/* m_pcjr.c */ +extern int machine_pcjr_init(const machine_t *); -extern void machine_xt_init(const machine_t *); -extern void machine_xt_compaq_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_LASERXT) -extern void machine_xt_laserxt_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t *pcjr_get_device(void); #endif -extern void machine_xt_t1000_init(const machine_t *); -extern void machine_xt_t1200_init(const machine_t *); +/* m_ps1.c */ +extern int machine_ps1_m2011_init(const machine_t *); +extern int machine_ps1_m2121_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_PS1M2133) +extern int machine_ps1_m2133_init(const machine_t *); +#endif -extern void machine_xt_xi8088_init(const machine_t *); +/* m_ps1_hdc.c */ +#ifdef EMU_DEVICE_H +extern void ps1_hdc_inform(void *, uint8_t *); +extern const device_t ps1_hdc_device; +#endif + +/* m_ps2_isa.c */ +extern int machine_ps2_m30_286_init(const machine_t *); + +/* m_ps2_mca.c */ +extern int machine_ps2_model_50_init(const machine_t *); +extern int machine_ps2_model_55sx_init(const machine_t *); +extern int machine_ps2_model_70_type3_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) +extern int machine_ps2_model_70_type4_init(const machine_t *); +#endif +extern int machine_ps2_model_80_init(const machine_t *); + +/* m_tandy.c */ +extern int tandy1k_eeprom_read(void); +extern int machine_tandy_init(const machine_t *); +extern int machine_tandy1000hx_init(const machine_t *); +extern int machine_tandy1000sl2_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *tandy1k_get_device(void); +extern const device_t *tandy1k_hx_get_device(void); +#endif + +/* m_xt.c */ +extern int machine_pc_init(const machine_t *); +extern int machine_pc82_init(const machine_t *); + +extern int machine_xt_init(const machine_t *); +extern int machine_genxt_init(const machine_t *); + +extern int machine_xt86_init(const machine_t *); + +extern int machine_xt_amixt_init(const machine_t *); +extern int machine_xt_dtk_init(const machine_t *); +extern int machine_xt_jukopc_init(const machine_t *); +extern int machine_xt_open_xt_init(const machine_t *); +extern int machine_xt_pxxt_init(const machine_t *); + +/* m_xt_compaq.c */ +extern int machine_xt_compaq_init(const machine_t *); + +/* m_xt_laserxt.c */ +#if defined(DEV_BRANCH) && defined(USE_LASERXT) +extern int machine_xt_laserxt_init(const machine_t *); +extern int machine_xt_lxt3_init(const machine_t *); +#endif + +/* m_xt_t1000.c */ +extern int machine_xt_t1000_init(const machine_t *); +extern int machine_xt_t1200_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *t1000_get_device(void); +extern const device_t *t1200_get_device(void); +#endif + +/* m_xt_zenith.c */ +extern int machine_xt_zenith_init(const machine_t *); + +/* m_xt_xi8088.c */ +extern int machine_xt_xi8088_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t *xi8088_get_device(void); - -extern const device_t *pcjr_get_device(void); - -extern const device_t *tandy1k_get_device(void); -extern const device_t *tandy1k_hx_get_device(void); - -extern const device_t *t1000_get_device(void); -extern const device_t *t1200_get_device(void); - -extern const device_t *at_endeavor_get_device(void); #endif diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 8798fdce5..893b37e7a 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,15 +11,15 @@ * NOTES: OpenAT wip for 286-class machine with open BIOS. * PS2_M80-486 wip, pending receipt of TRM's for machine. * - * Version: @(#)machine_table.c 1.0.30 2018/05/26 + * Version: @(#)machine_table.c 1.0.50 2019/11/19 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -33,147 +33,186 @@ #include "machine.h" -const machine_t machines[] = { - { "[8088] AMI XT clone", ROM_AMIXT, "amixt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Compaq Portable", ROM_PORTABLE, "portable", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, - { "[8088] DTK XT clone", ROM_DTKXT, "dtk", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] IBM PC", ROM_IBMPC, "ibmpc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 32, 0, machine_xt_init, NULL }, - { "[8088] IBM PCjr", ROM_IBMPCJR, "ibmpcjr", {{"", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, - { "[8088] IBM XT", ROM_IBMXT, "ibmxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Juko XT clone", ROM_JUKOPC, "jukopc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, - { "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device }, - { "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device }, - { "[8088] Toshiba T1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL }, -#endif - { "[8088] Xi8088", ROM_XI8088, "xi8088", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, NULL }, - - { "[8086] Amstrad PC1512", ROM_PC1512, "pc1512", {{"", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC1640", ROM_PC1640, "pc1640", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC2086", ROM_PC2086, "pc2086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC3086", ROM_PC3086, "pc3086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, - { "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, - { "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL }, - { "[8086] Toshiba T1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL }, -#endif - - { "[286 ISA] AMI 286 clone", ROM_AMI286, "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_neat_ami_init, NULL }, - { "[286 ISA] Award 286 clone", ROM_AWARD286, "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, - { "[286 ISA] Commodore PC 30 III", ROM_CMDPC30, "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL }, - { "[286 ISA] Compaq Portable II", ROM_PORTABLEII, "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_compaq_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - { "[286 ISA] Compaq Portable III", ROM_PORTABLEIII, "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO, 640,16384, 128, 127, machine_at_compaq_init, NULL }, -#endif - { "[286 ISA] GW-286CT GEAR", ROM_GW286CT, "gw286ct", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, - { "[286 ISA] Hyundai Super-286TR", ROM_SUPER286TR, "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, - { "[286 ISA] IBM AT", ROM_IBMAT, "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL }, - { "[286 ISA] IBM PS/1 model 2011", ROM_IBMPS1_2011, "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_PS2 | MACHINE_HDC_PS2, 512,16384, 512, 63, machine_ps1_m2011_init, NULL }, - { "[286 ISA] IBM PS/2 model 30-286", ROM_IBMPS2_M30_286, "ibmps2_m30_286", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL }, - { "[286 ISA] IBM XT Model 286", ROM_IBMXT286, "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 127, machine_at_ibm_init, NULL }, - { "[286 ISA] Samsung SPC-4200P", ROM_SPC4200P, "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_scat_init, NULL }, - { "[286 ISA] Samsung SPC-4216P", ROM_SPC4216P, "spc4216p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_scat_init, NULL }, -#ifdef WALTJE - { "[286 ISA] OpenAT 286", ROM_OPENAT, "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512, 4096, 128, 127, machine_at_init, NULL }, -#endif - { "[286 ISA] Toshiba T3100e", ROM_T3100E, "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, - - { "[286 MCA] IBM PS/2 model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, - - { "[386SX ISA] AMI 386SX clone", ROM_AMI386SX, "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, - { "[386SX ISA] Amstrad MegaPC", ROM_MEGAPC, "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 16, 1, 127, machine_at_wd76c10_init, NULL }, - { "[386SX ISA] Award 386SX clone", ROM_AWARD386SX_OPTI495, "award386sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, - { "[386SX ISA] DTK 386SX clone", ROM_DTK386, "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_neat_init, NULL }, - { "[386SX ISA] IBM PS/1 model 2121", ROM_IBMPS1_2121, "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, - { "[386SX ISA] IBM PS/1 m.2121+ISA", ROM_IBMPS1_2121_ISA, "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, - { "[386SX ISA] KMX-C-02", ROM_KMXC02, "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_scatsx_init, NULL }, - - { "[386SX MCA] IBM PS/2 model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, - - { "[386DX ISA] AMI 386DX clone", ROM_AMI386DX_OPTI495, "ami386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, - { "[386DX ISA] Amstrad MegaPC 386DX", ROM_MEGAPCDX, "megapcdx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, - { "[386DX ISA] Award 386DX clone", ROM_AWARD386DX_OPTI495, "award386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, - { "[386DX ISA] MR 386DX clone", ROM_MR386DX_OPTI495, "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - { "[386DX ISA] Compaq Portable III (386)", ROM_PORTABLEIII386, "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 1, 14, 1, 127, machine_at_compaq_init, NULL }, -#endif - - { "[386DX MCA] IBM PS/2 model 70 (type 3)", ROM_IBMPS2_M70_TYPE3, "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL }, - { "[386DX MCA] IBM PS/2 model 80", ROM_IBMPS2_M80, "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 12, 1, 63, machine_ps2_model_80_init, NULL }, - - { "[486 ISA] AMI 486 clone", ROM_AMI486, "ami486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, - { "[486 ISA] AMI WinBIOS 486", ROM_WIN486, "win486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, - { "[486 ISA] Award 486 clone", ROM_AWARD486_OPTI495, "award486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, - { "[486 ISA] DTK PKM-0038S E-2", ROM_DTK486, "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_dtk486_init, NULL }, - { "[486 ISA] IBM PS/1 model 2133", ROM_IBMPS1_2133, "ibmps1_2133", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 1, 64, 1, 127, machine_ps1_m2133_init, NULL }, - - { "[486 MCA] IBM PS/2 model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, - - { "[486 PCI] Rise Computer R418", ROM_R418, "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, - - { "[Socket 4 LX] Intel Premiere/PCI", ROM_REVENGE, "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL }, - #if defined(DEV_BRANCH) && defined(USE_AMD_K) - { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, - - { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, - { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, - { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, - { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, - - { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) - { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, -#endif - { "[Socket 7 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, - { "[Socket 7 FX] Packard Bell PB640", ROM_PB640, "pb640", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, NULL }, - - { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, - { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, - { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, - { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p55t2p4_init, NULL }, - { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, - - { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, - { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, - { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, +#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}} +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) +#define MACHINE_CPUS_PENTIUM_S73V {{"Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"Cyrix", cpus_6x863V},{"", NULL}} +#define MACHINE_CPUS_PENTIUM_S7 {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86}, {"", NULL}} #else - { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, +#define MACHINE_CPUS_PENTIUM_S73V {{ "Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}} +#define MACHINE_CPUS_PENTIUM_S7 {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"", NULL}, {"", NULL}} +#endif +#else +#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}} +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) +#define MACHINE_CPUS_PENTIUM_S73V {{"Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x863V}, {"", NULL}, {"", NULL}} +#define MACHINE_CPUS_PENTIUM_S7 {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}} +#else +#define MACHINE_CPUS_PENTIUM_S73V {{"Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}} +#define MACHINE_CPUS_PENTIUM_S7 {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}} +#endif +#endif - { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, - { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, - { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, - { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, +const machine_t machines[] = { + { "[8088] AMI XT clone", "amixt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_amixt_init, NULL }, + { "[8088] Compaq Portable", "portable", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, + { "[8088] DTK XT clone", "dtk", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, + { "[8088] IBM PC (1981)", "ibmpc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 16, 64, 16, 0, machine_pc_init, NULL }, + { "[8088] IBM PC (1982)", "ibmpc82", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 256, 256, 0, machine_pc82_init, NULL }, + { "[8088] IBM PCjr", "ibmpcjr", {{"Intel", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, + { "[8088] IBM XT (1982)", "ibmxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 256, 64, 0, machine_xt_init, NULL }, + { "[8088] IBM XT (1986)", "ibmxt86", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 64, 0, machine_xt86_init, NULL }, + { "[8088] Generic XT clone", "genxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_genxt_init, NULL }, + { "[8088] Juko XT clone", "jukopc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, + { "[8088] OpenXT", "open_xt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_open_xt_init, NULL }, + { "[8088] Phoenix XT clone", "pxxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_pxxt_init, NULL }, + { "[8088] Schneider EuroPC", "europc", {{"Siemens", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_HDC | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, + { "[8088] Tandy 1000", "tandy", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_tandy_init, tandy1k_get_device }, + { "[8088] Tandy 1000 HX", "tandy1000hx", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 256, 640, 128, 0, machine_tandy1000hx_init, tandy1k_hx_get_device }, + { "[8088] Toshiba T1000", "t1000", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, t1000_get_device }, +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + { "[8088] VTech Laser Turbo XT", "ltxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_laserxt_init, NULL }, +#endif + { "[8088] Xi8088", "xi8088", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device }, + { "[8088] Zenith Data SupersPort", "zdsupers", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 128, 640, 128, 0, machine_xt_zenith_init, NULL }, + + { "[8086] Amstrad PC1512", "pc1512", {{"Intel", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_pc1512_init, pc1512_get_device }, + { "[8086] Amstrad PC1640", "pc1640", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc1640_init, pc1640_get_device }, + { "[8086] Amstrad PC2086", "pc2086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc2086_init, pc2086_get_device }, + { "[8086] Amstrad PC3086", "pc3086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc3086_init, pc3086_get_device }, + { "[8086] Amstrad PC20(0)", "pc200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_pc200_init, pc200_get_device }, + { "[8086] Amstrad PPC512/640", "ppc512", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_ppc512_init, ppc512_get_device }, + { "[8086] Olivetti M24", "olivetti_m24", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, + { "[8086] Tandy 1000 SL/2", "tandy1000sl2", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 512, 768, 128, 0, machine_tandy1000sl2_init, NULL }, + { "[8086] Toshiba T1200", "t1200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, t1200_get_device }, +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + { "[8086] VTech Laser XT3", "lxt3", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_lxt3_init, NULL }, +#endif - { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, + { "[286 ISA] AMI 286 clone", "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, + { "[286 ISA] Award 286 clone", "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_award286_init, NULL }, + { "[286 ISA] Commodore PC 30 III", "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL }, + { "[286 ISA] Compaq Portable II", "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_portableii_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + { "[286 ISA] Compaq Portable III", "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 640,16384, 128, 127, machine_at_portableiii_init, NULL }, +#endif + { "[286 ISA] GW-286CT GEAR", "gw286ct", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_gw286ct_init, NULL }, + { "[286 ISA] Hyundai Super-286TR", "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_super286tr_init, NULL }, + { "[286 ISA] IBM AT", "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL }, + { "[286 ISA] AMI IBM AT", "ibmatami", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibmatami_init, NULL }, + { "[286 ISA] Quadtel IBM AT", "ibmatquadtel", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibmatquadtel_init, NULL }, + { "[286 ISA] Phoenix IBM AT", "ibmatpx", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibmatpx_init, NULL }, + { "[286 ISA] IBM PS/1 model 2011", "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 512,16384, 512, 63, machine_ps1_m2011_init, NULL }, + { "[286 ISA] IBM PS/2 model 30-286", "ibmps2_m30_286", {{"Intel", cpus_ps2_m30_286}, {"IBM", cpus_IBM486SLC}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL }, + { "[286 ISA] IBM XT Model 286", "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 127, machine_at_ibmxt286_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) + { "[286 ISA] OpenAT", "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_open_at_init, NULL }, +#endif + { "[286 ISA] Samsung SPC-4200P", "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_spc4200p_init, NULL }, + { "[286 ISA] Samsung SPC-4216P", "spc4216p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_spc4216p_init, NULL }, + { "[286 ISA] Toshiba T3100e", "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, + { "[286 ISA] Trigem 286M", "tg286m", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_tg286m_init, NULL }, + + { "[286 ISA] Unknown Phoenix Headland", "headlandpho", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_headlandpho_init, NULL }, + { "[286 ISA] Unknown Quadtel Headland", "headlandquadtel", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_headlandquadtel_init, NULL }, + { "[286 ISA] Headland IQS", "iqs", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_iqs_init, NULL }, + { "[286 ISA] Samsung Deskmaster 286", "deskmaster286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_deskmaster286_init, NULL }, + + { "[286 MCA] IBM PS/2 model 50", "ibmps2_m50", {{"Intel", cpus_ps2_m30_286}, {"IBM", cpus_IBM486SLC}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, + + { "[386SX ISA] AMA-932J", "ama932j", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, +#if defined(DEV_BRANCH) && defined(USE_AMI386SX) + { "[386SX ISA] AMI Unknown 386SX", "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, +#endif + { "[386SX ISA] Amstrad MegaPC", "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386SX ISA] DTK 386SX clone", "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_neat_init, NULL }, + { "[386SX ISA] IBM PS/1 model 2121", "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] KMX-C-02", "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_kmxc02_init, NULL }, + + { "[386SX MCA] IBM PS/2 model 55SX", "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"IBM", cpus_IBM486SLC}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, + +#if defined(DEV_BRANCH) && defined(USE_MICRONICS386) + { "[386SX ISA] Unknown Micronics 386 Board", "micronics386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, +#endif + + { "[386DX ISA] AMI 386DX clone", "ami386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_ami_init, NULL }, + { "[386DX ISA] Award 386DX clone", "award386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_MR495) + { "[386DX ISA] MR 386DX clone", "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, +#endif +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + { "[386DX ISA] Compaq Portable III (386)", "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 14, 1, 127, machine_at_portableiii386_init, NULL }, +#endif + + { "[386DX MCA] IBM PS/2 model 70 (type 3)", "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"IBM", cpus_IBM486BL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL }, + { "[386DX MCA] IBM PS/2 model 80", "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"IBM", cpus_IBM486BL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 12, 1, 63, machine_ps2_model_80_init, NULL }, + + { "[486 ISA] AMI 486 clone", "ami486", {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_ami_init, NULL }, + { "[486 ISA] AMI ALi 1429", "ali1429", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_ali1429_init, NULL }, + { "[486 ISA] AMI SiS 471", "ami471", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ami471_init, NULL }, + { "[486 ISA] AMI WinBIOS 486", "win486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_winbios1429_init, NULL }, + { "[486 ISA] AMI WinBIOS SiS 471", "win471", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_win471_init, NULL }, + { "[486 ISA] Award 486 clone", "award486", {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_init, NULL }, + { "[486 ISA] DTK PKM-0038S E-2", "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_dtk486_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_PS1M2133) + { "[486 ISA] IBM PS/1 model 2133", "ibmps1_2133", {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_NONMI, 1, 64, 1, 127, machine_ps1_m2133_init, NULL }, +#endif +#if defined(DEV_BRANCH) && defined(USE_MR495) + { "[486 ISA] MR 486 clone", "mr486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, +#endif + { "[486 ISA] Packard Bell PB410A", "pb410a", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 64, 1, 127, machine_at_pb410a_init, NULL }, + { "[486 ISA] Phoenix SiS 471", "px471", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_px471_init, NULL }, + +#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) + { "[486 MCA] IBM PS/2 model 70 (type 4)", "ibmps2_m70_type4", {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, +#endif + + { "[486 PCI] Intel Classic/PCI", "alfredo", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_alfredo_init, NULL }, + { "[486 PCI] Rise Computer R418", "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, + + { "[Socket 4 LX] Intel Premiere/PCI", "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL }, + { "[Socket 4 LX] IBM Ambra DP60 PCI", "ambradp60", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_ambradp60_init, NULL }, + { "[Socket 4 LX] Micro Star 586MC1", "586mc1", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_586mc1_init, NULL }, + + { "[Socket 5 NX] Intel Premiere/PCI II", "plato", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, + { "[Socket 5 NX] IBM Ambra DP90 PCI", "ambradp90", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_ambradp90_init, NULL }, + { "[Socket 5 NX] Gigabyte GA-586IP", "430nx", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_430nx_init, NULL }, + + { "[Socket 5 FX] ASUS P/I-P54TP4XE", "p54tp4xe", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_VECTRA54) + { "[Socket 5 FX] HP Vectra VL 5 Series 4", "vectra54", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_vectra54_init, NULL }, +#endif + { "[Socket 5 FX] Intel Advanced/ZP", "zappa", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, + { "[Socket 5 FX] PC Partner MB500N", "mb500n", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, + { "[Socket 5 FX] President Award 430FX PCI","president", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, + + { "[Socket 7 FX] Intel Advanced/ATX", "thor", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_MRTHOR) - { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, + { "[Socket 7 FX] MR Intel Advanced/ATX", "mrthor", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_mrthor_init, NULL }, #endif - { "[Socket 7 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, - { "[Socket 7 FX] Packard Bell PB640", ROM_PB640, "pb640", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, NULL }, + { "[Socket 7 FX] Intel Advanced/EV", "endeavor", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, + { "[Socket 7 FX] Packard Bell PB640", "pb640", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, at_pb640_get_device }, - { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, - { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, - { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, - { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p55t2p4_init, NULL }, - { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, - - { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, - { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, - { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, + { "[Socket 7 HX] Acer M3a", "acerm3a", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, + { "[Socket 7 HX] Acer V35n", "acerv35n", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, + { "[Socket 7 HX] AOpen AP53", "ap53", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, + { "[Socket 7 HX] ASUS P/I-P55T2P4", "p55t2p4", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 127, machine_at_p55t2p4_init, NULL }, + { "[Socket 7 HX] SuperMicro Super P55T2S", "p55t2s", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_TC430HX) + { "[Socket 7 HX] TC430HX", "tc430hx", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_tc430hx_init, NULL }, #endif + { "[Socket 7 VX] ASUS P/I-P55TVP4", "p55tvp4", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, + { "[Socket 7 VX] Epox P55-VA", "p55va", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, + { "[Socket 7 VX] Jetway J656VXD", "j656vxd", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_j656vxd_init, NULL }, + { "[Socket 7 VX] Shuttle HOT-557", "430vx", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, + #if defined(DEV_BRANCH) && defined(USE_I686) - { "[Socket 8 FX] Tyan Titan-Pro AT", ROM_440FX, "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_i440fx_init, NULL }, - { "[Socket 8 FX] Tyan Titan-Pro ATX", ROM_S1668, "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_s1668_init, NULL }, + { "[Socket 8 FX] Tyan Titan-Pro AT", "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_i440fx_init, NULL }, + { "[Socket 8 FX] Tyan Titan-Pro ATX", "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_s1668_init, NULL }, #endif - { "", -1, "", {{"", 0}, {"", 0}, {"", 0}}, 0,0,0,0, 0 } + { NULL, NULL, {{"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}}, 0, 0, 0, 0, 0, NULL, NULL } }; @@ -184,35 +223,6 @@ machine_count(void) } -int -machine_getromset(void) -{ - return(machines[machine].id); -} - - -int -machine_getromset_ex(int m) -{ - return(machines[m].id); -} - - -int -machine_getmachine(int romset) -{ - int c = 0; - - while (machines[c].id != -1) { - if (machines[c].id == romset) - return(c); - c++; - } - - return(0); -} - - char * machine_getname(void) { @@ -220,11 +230,18 @@ machine_getname(void) } -const device_t * -machine_getdevice(int machine) +char * +machine_getname_ex(int m) { - if (machines[machine].get_device) - return(machines[machine].get_device()); + return((char *)machines[m].name); +} + + +const device_t * +machine_getdevice(int m) +{ + if (machines[m].get_device) + return(machines[m].get_device()); return(NULL); } @@ -256,7 +273,7 @@ machine_get_machine_from_internal_name(char *s) { int c = 0; - while (machines[c].id != -1) { + while (machines[c].init != NULL) { if (!strcmp(machines[c].internal_name, (const char *)s)) return(c); c++; diff --git a/src/machine/machine_table_new.c b/src/machine/machine_table_new.c new file mode 100644 index 000000000..a46e7175c --- /dev/null +++ b/src/machine/machine_table_new.c @@ -0,0 +1,267 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handling of the emulated machines. + * + * NOTES: OpenAT wip for 286-class machine with open BIOS. + * PS2_M80-486 wip, pending receipt of TRM's for machine. + * + * Version: @(#)machine_table.c 1.0.50 2019/11/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu_new/cpu.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "machine.h" + + +#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}} +#define MACHINE_CPUS_PENTIUM_S73V {{ "Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"Cyrix", cpus_6x863V},{"", NULL}} +#define MACHINE_CPUS_PENTIUM_S7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86}, {"", NULL}} + +const machine_t machines[] = { + { "[8088] AMI XT clone", "amixt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_amixt_init, NULL }, + { "[8088] Compaq Portable", "portable", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, + { "[8088] DTK XT clone", "dtk", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, + { "[8088] IBM PC (1981)", "ibmpc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 16, 64, 16, 0, machine_pc_init, NULL }, + { "[8088] IBM PC (1982)", "ibmpc82", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 256, 256, 0, machine_pc82_init, NULL }, + { "[8088] IBM PCjr", "ibmpcjr", {{"Intel", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, + { "[8088] IBM XT (1982)", "ibmxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 256, 64, 0, machine_xt_init, NULL }, + { "[8088] IBM XT (1986)", "ibmxt86", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 64, 0, machine_xt86_init, NULL }, + { "[8088] Generic XT clone", "genxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_genxt_init, NULL }, + { "[8088] Juko XT clone", "jukopc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, + { "[8088] OpenXT", "open_xt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_open_xt_init, NULL }, + { "[8088] Phoenix XT clone", "pxxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_pxxt_init, NULL }, + { "[8088] Schneider EuroPC", "europc", {{"Siemens", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_HDC | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, + { "[8088] Tandy 1000", "tandy", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_tandy_init, tandy1k_get_device }, + { "[8088] Tandy 1000 HX", "tandy1000hx", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 256, 640, 128, 0, machine_tandy1000hx_init, tandy1k_hx_get_device }, + { "[8088] Toshiba T1000", "t1000", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, t1000_get_device }, +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + { "[8088] VTech Laser Turbo XT", "ltxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_laserxt_init, NULL }, +#endif + { "[8088] Xi8088", "xi8088", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device }, + { "[8088] Zenith Data SupersPort", "zdsupers", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 128, 640, 128, 0, machine_xt_zenith_init, NULL }, + + { "[8086] Amstrad PC1512", "pc1512", {{"Intel", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_pc1512_init, pc1512_get_device }, + { "[8086] Amstrad PC1640", "pc1640", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc1640_init, pc1640_get_device }, + { "[8086] Amstrad PC2086", "pc2086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc2086_init, pc2086_get_device }, + { "[8086] Amstrad PC3086", "pc3086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc3086_init, pc3086_get_device }, + { "[8086] Amstrad PC20(0)", "pc200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_pc200_init, pc200_get_device }, + { "[8086] Amstrad PPC512/640", "ppc512", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_ppc512_init, ppc512_get_device }, + { "[8086] Olivetti M24", "olivetti_m24", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, + { "[8086] Tandy 1000 SL/2", "tandy1000sl2", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 512, 768, 128, 0, machine_tandy1000sl2_init, NULL }, + { "[8086] Toshiba T1200", "t1200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, t1200_get_device }, +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + { "[8086] VTech Laser XT3", "lxt3", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_lxt3_init, NULL }, +#endif + + { "[286 ISA] AMI 286 clone", "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, + { "[286 ISA] Award 286 clone", "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_award286_init, NULL }, + { "[286 ISA] Commodore PC 30 III", "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL }, + { "[286 ISA] Compaq Portable II", "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_portableii_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + { "[286 ISA] Compaq Portable III", "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 640,16384, 128, 127, machine_at_portableiii_init, NULL }, +#endif + { "[286 ISA] GW-286CT GEAR", "gw286ct", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_gw286ct_init, NULL }, + { "[286 ISA] Hyundai Super-286TR", "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_super286tr_init, NULL }, + { "[286 ISA] IBM AT", "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL }, + { "[286 ISA] AMI IBM AT", "ibmatami", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibmatami_init, NULL }, + { "[286 ISA] Quadtel IBM AT", "ibmatquadtel", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibmatquadtel_init, NULL }, + { "[286 ISA] Phoenix IBM AT", "ibmatpx", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibmatpx_init, NULL }, + { "[286 ISA] IBM PS/1 model 2011", "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 512,16384, 512, 63, machine_ps1_m2011_init, NULL }, + { "[286 ISA] IBM PS/2 model 30-286", "ibmps2_m30_286", {{"Intel", cpus_ps2_m30_286}, {"IBM", cpus_IBM486SLC}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL }, + { "[286 ISA] IBM XT Model 286", "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 127, machine_at_ibmxt286_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) + { "[286 ISA] OpenAT", "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_open_at_init, NULL }, +#endif + { "[286 ISA] Samsung SPC-4200P", "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_spc4200p_init, NULL }, + { "[286 ISA] Samsung SPC-4216P", "spc4216p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_spc4216p_init, NULL }, + { "[286 ISA] Toshiba T3100e", "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, + { "[286 ISA] Trigem 286M", "tg286m", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_tg286m_init, NULL }, + + { "[286 ISA] Unknown Phoenix Headland", "headlandpho", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_headlandpho_init, NULL }, + { "[286 ISA] Unknown Quadtel Headland", "headlandquadtel", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_headlandquadtel_init, NULL }, + { "[286 ISA] Headland IQS", "iqs", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_iqs_init, NULL }, + { "[286 ISA] Samsung Deskmaster 286", "deskmaster286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_deskmaster286_init, NULL }, + + { "[286 MCA] IBM PS/2 model 50", "ibmps2_m50", {{"Intel", cpus_ps2_m30_286}, {"IBM", cpus_IBM486SLC}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, + + { "[386SX ISA] AMA-932J", "ama932j", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, +#if defined(DEV_BRANCH) && defined(USE_AMI386SX) + { "[386SX ISA] AMI Unknown 386SX", "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, +#endif + { "[386SX ISA] Amstrad MegaPC", "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386SX ISA] DTK 386SX clone", "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_neat_init, NULL }, + { "[386SX ISA] IBM PS/1 model 2121", "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] KMX-C-02", "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_kmxc02_init, NULL }, + +#if defined(DEV_BRANCH) && defined(USE_MICRONICS386) + { "[386SX ISA] Unknown Micronics 386 Board", "micronics386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_micronics386_init, NULL }, +#endif + + { "[386SX MCA] IBM PS/2 model 55SX", "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"IBM", cpus_IBM486SLC}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, + + { "[386DX ISA] Dataexpert SX495 (386DX)", "ami386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_ami_init, NULL }, + { "[386DX ISA] Award 386DX clone", "award386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_MR495) + { "[386DX ISA] MR 386DX clone", "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, +#endif +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + { "[386DX ISA] Compaq Portable III (386)", "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 14, 1, 127, machine_at_portableiii386_init, NULL }, +#endif + + { "[386DX MCA] IBM PS/2 model 70 (type 3)", "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"IBM", cpus_IBM486BL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL }, + { "[386DX MCA] IBM PS/2 model 80", "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"IBM", cpus_IBM486BL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 12, 1, 63, machine_ps2_model_80_init, NULL }, + + { "[486 ISA] Dataexpert SX495 (486)", "ami486", {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_ami_init, NULL }, + { "[486 ISA] Olystar LIL1429", "ali1429", {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_ali1429_init, NULL }, + { "[486 ISA] AMI SiS 471", "ami471", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ami471_init, NULL }, + { "[486 ISA] AMI WinBIOS 486", "win486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_winbios1429_init, NULL }, + { "[486 ISA] AMI WinBIOS SiS 471", "win471", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_win471_init, NULL }, + { "[486 ISA] Award 486 clone", "award486", {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_init, NULL }, + { "[486 ISA] DTK PKM-0038S E-2", "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_dtk486_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_PS1M2133) + { "[486 ISA] IBM PS/1 model 2133", "ibmps1_2133", {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_NONMI, 1, 64, 1, 127, machine_ps1_m2133_init, NULL }, +#endif +#if defined(DEV_BRANCH) && defined(USE_MR495) + { "[486 ISA] MR 486 clone", "mr486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, +#endif + { "[486 ISA] Packard Bell PB410A", "pb410a", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 64, 1, 127, machine_at_pb410a_init, NULL }, + { "[486 ISA] Phoenix SiS 471", "px471", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_px471_init, NULL }, + +#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) + { "[486 MCA] IBM PS/2 model 70 (type 4)", "ibmps2_m70_type4", {{"Intel", cpus_i486S1}, {"AMD", cpus_Am486S1}, {"Cyrix", cpus_Cx486S1},{"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, +#endif + + { "[486 PCI] Intel Classic/PCI", "alfredo", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_alfredo_init, NULL }, + { "[486 PCI] Rise Computer R418", "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, + + { "[Socket 4 LX] Intel Premiere/PCI", "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL }, + { "[Socket 4 LX] IBM Ambra DP60 PCI", "ambradp60", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_ambradp60_init, NULL }, + { "[Socket 4 LX] Micro Star 586MC1", "586mc1", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_586mc1_init, NULL }, + + { "[Socket 5 NX] Intel Premiere/PCI II", "plato", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, + { "[Socket 5 NX] IBM Ambra DP90 PCI", "ambradp90", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_ambradp90_init, NULL }, + { "[Socket 5 NX] Gigabyte GA-586IP", "430nx", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_430nx_init, NULL }, + + { "[Socket 5 FX] ASUS P/I-P54TP4XE", "p54tp4xe", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_VECTRA54) + { "[Socket 5 FX] HP Vectra VL 5 Series 4", "vectra54", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_vectra54_init, NULL }, +#endif + { "[Socket 5 FX] Intel Advanced/ZP", "zappa", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, + { "[Socket 5 FX] PC Partner MB500N", "mb500n", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, + { "[Socket 5 FX] President Award 430FX PCI","president", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, + + { "[Socket 7 FX] Intel Advanced/ATX", "thor", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) + { "[Socket 7 FX] MR Intel Advanced/ATX", "mrthor", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_mrthor_init, NULL }, +#endif + { "[Socket 7 FX] Intel Advanced/EV", "endeavor", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, + { "[Socket 7 FX] Packard Bell PB640", "pb640", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, at_pb640_get_device }, + + { "[Socket 7 HX] Acer M3a", "acerm3a", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, + { "[Socket 7 HX] Acer V35n", "acerv35n", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, + { "[Socket 7 HX] AOpen AP53", "ap53", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, + { "[Socket 7 HX] ASUS P/I-P55T2P4", "p55t2p4", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 127, machine_at_p55t2p4_init, NULL }, + { "[Socket 7 HX] SuperMicro Super P55T2S", "p55t2s", MACHINE_CPUS_PENTIUM_S73V, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_TC430HX) + { "[Socket 7 HX] TC430HX", "tc430hx", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_tc430hx_init, NULL }, +#endif + + { "[Socket 7 VX] ASUS P/I-P55TVP4", "p55tvp4", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, + { "[Socket 7 VX] Epox P55-VA", "p55va", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, + { "[Socket 7 VX] Jetway J656VXD", "j656vxd", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_j656vxd_init, NULL }, + { "[Socket 7 VX] Shuttle HOT-557", "430vx", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, + +#if defined(DEV_BRANCH) && defined(USE_I686) + { "[Socket 8 FX] Tyan Titan-Pro AT", "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_i440fx_init, NULL }, + { "[Socket 8 FX] Tyan Titan-Pro ATX", "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_s1668_init, NULL }, +#endif + { NULL, NULL, {{"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}}, 0, 0, 0, 0, 0, NULL, NULL } +}; + + +int +machine_count(void) +{ + return((sizeof(machines) / sizeof(machine)) - 1); +} + + +char * +machine_getname(void) +{ + return((char *)machines[machine].name); +} + + +char * +machine_getname_ex(int m) +{ + return((char *)machines[m].name); +} + + +const device_t * +machine_getdevice(int m) +{ + if (machines[m].get_device) + return(machines[m].get_device()); + + return(NULL); +} + + +char * +machine_get_internal_name(void) +{ + return((char *)machines[machine].internal_name); +} + + +char * +machine_get_internal_name_ex(int m) +{ + return((char *)machines[m].internal_name); +} + + +int +machine_get_nvrmask(int m) +{ + return(machines[m].nvrmask); +} + + +int +machine_get_machine_from_internal_name(char *s) +{ + int c = 0; + + while (machines[c].init != NULL) { + if (!strcmp(machines[c].internal_name, (const char *)s)) + return(c); + c++; + } + + return(0); +} diff --git a/src/mca.c b/src/mca.c index 3d0677b26..73e227b8e 100644 --- a/src/mca.c +++ b/src/mca.c @@ -8,6 +8,7 @@ void (*mca_card_write[8])(int addr, uint8_t val, void *priv); uint8_t (*mca_card_read[8])(int addr, void *priv); +uint8_t (*mca_card_feedb[8])(void *priv); void *mca_priv[8]; static int mca_index; @@ -51,7 +52,15 @@ 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) +uint8_t mca_feedb(void) +{ + if (mca_card_feedb[mca_index]) + return !!(mca_card_feedb[mca_index](mca_priv[mca_index])); + else + return 0; +} + +void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void *priv) { int c; @@ -61,6 +70,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_feedb[c] = feedb; mca_priv[c] = priv; return; } diff --git a/src/mca.h b/src/mca.h index dd88c1f98..d38156352 100644 --- a/src/mca.h +++ b/src/mca.h @@ -1,7 +1,8 @@ extern void mca_init(int nr_cards); -extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv); +extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void *priv); extern void mca_set_index(int index); extern uint8_t mca_read(uint16_t port); extern void mca_write(uint16_t port, uint8_t val); +extern uint8_t mca_feedb(void); extern void ps2_cache_clean(void); \ No newline at end of file diff --git a/src/mcr.c b/src/mcr.c index ddd2dd784..86bddcbaf 100644 --- a/src/mcr.c +++ b/src/mcr.c @@ -6,7 +6,6 @@ #include #include #include "86box.h" -#include "cpu/cpu.h" #include "mem.h" diff --git a/src/mem.c b/src/mem.c index cad04677b..0741e18d5 100644 --- a/src/mem.c +++ b/src/mem.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Memory handling and MMU. * @@ -12,33 +12,15 @@ * the DYNAMIC_TABLES=1 enables this. Will eventually go * away, either way... * - * Version: @(#)mem.c 1.0.10 2018/04/29 + * Version: @(#)mem.c 1.0.22 2019/12/02 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -71,25 +53,27 @@ #define DYNAMIC_TABLES 0 /* experimental */ -mem_mapping_t ram_low_mapping; -mem_mapping_t ram_high_mapping; -mem_mapping_t ram_mid_mapping; -mem_mapping_t bios_mapping[8]; -mem_mapping_t bios_high_mapping[8]; -mem_mapping_t romext_mapping; +mem_mapping_t base_mapping, + ram_low_mapping, /* 0..640K mapping */ +#if 1 + ram_mid_mapping, +#endif + ram_remapped_mapping, /* 640..1024K mapping */ + ram_high_mapping, /* 1024K+ mapping */ + ram_remapped_mapping, + ram_split_mapping, + bios_mapping, + bios_high_mapping; page_t *pages, /* RAM page table */ **page_lookup; /* pagetable lookup */ uint32_t pages_sz; /* #pages in table */ -uint8_t isram[0x10000]; - uint8_t *ram; /* the virtual RAM */ uint32_t rammask; uint8_t *rom; /* the virtual ROM */ -uint8_t romext[32768]; -uint32_t biosmask; +uint32_t biosmask, biosaddr; uint32_t pccache; uint8_t *pccache2; @@ -109,11 +93,8 @@ int shadowbios = 0, shadowbios_write; int readlnum = 0, writelnum = 0; -int pctrans = 0; int cachesize = 256; -uint32_t ram_mapped_addr[64]; - uint32_t get_phys_virt, get_phys_phys; @@ -126,48 +107,48 @@ int mmu_perm = 4; /* FIXME: re-do this with a 'mem_ops' struct. */ -static uint8_t (*_mem_read_b[0x40000])(uint32_t addr, void *priv); -static uint16_t (*_mem_read_w[0x40000])(uint32_t addr, void *priv); -static uint32_t (*_mem_read_l[0x40000])(uint32_t addr, void *priv); -static void (*_mem_write_b[0x40000])(uint32_t addr, uint8_t val, void *priv); -static void (*_mem_write_w[0x40000])(uint32_t addr, uint16_t val, void *priv); -static void (*_mem_write_l[0x40000])(uint32_t addr, uint32_t val, void *priv); -static uint8_t *_mem_exec[0x40000]; -static void *_mem_priv_r[0x40000]; -static void *_mem_priv_w[0x40000]; -static mem_mapping_t *_mem_mapping_r[0x40000]; -static mem_mapping_t *_mem_mapping_w[0x40000]; -static int _mem_state[0x40000]; - -static mem_mapping_t base_mapping; -static mem_mapping_t ram_remapped_mapping; +static mem_mapping_t *read_mapping[MEM_MAPPINGS_NO]; +static mem_mapping_t *write_mapping[MEM_MAPPINGS_NO]; +static uint8_t *_mem_exec[MEM_MAPPINGS_NO]; +static int _mem_state[MEM_MAPPINGS_NO]; #if FIXME -static uint8_t ff_array[0x1000]; +#if (MEM_GRANULARITY_BITS >= 12) +static uint8_t ff_array[MEM_GRANULARITY_SIZE]; +#else +static uint8_t ff_array[4096]; /* Must be at least one page. */ +#endif #else static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; #endif -static int port_92_reg = 0; - #ifdef ENABLE_MEM_LOG int mem_do_log = ENABLE_MEM_LOG; -#endif static void -mem_log(const char *format, ...) +mem_log(const char *fmt, ...) { -#ifdef ENABLE_MEM_LOG va_list ap; if (mem_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define mem_log(fmt, ...) #endif + + +int +mem_addr_is_ram(uint32_t addr) +{ + mem_mapping_t *mapping = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) || (mapping == &ram_remapped_mapping); } @@ -296,7 +277,7 @@ mem_flush_write_page(uint32_t addr, uint32_t virt) #define mmutranslate_read(addr) mmutranslatereal(addr,0) #define mmutranslate_write(addr) mmutranslatereal(addr,1) -#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> 14]))[((x) >> 2) & 0xfff] +#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 2) & MEM_GRANULARITY_QMASK] uint32_t mmutranslatereal(uint32_t addr, int rw) @@ -436,7 +417,7 @@ addreadlookup(uint32_t virt, uint32_t phys) readlookup[readlnext++] = virt >> 12; readlnext &= (cachesize-1); - cycles -= 9; + sub_cycles(9); } @@ -465,7 +446,7 @@ addwritelookup(uint32_t virt, uint32_t phys) writelookup[writelnext++] = virt >> 12; writelnext &= (cachesize - 1); - cycles -= 9; + sub_cycles(9); } @@ -476,29 +457,22 @@ getpccache(uint32_t a) a2 = a; - if (a2 < 0x100000 && ram_mapped_addr[a2 >> 14]) { - a = (ram_mapped_addr[a2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? a2 : (ram_mapped_addr[a2 >> 14] & ~0x3FFF) + (a2 & 0x3FFF); - return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)]; - } - - a2 = a; - if (cr0 >> 31) { - pctrans=1; a = mmutranslate_read(a); - pctrans = 0; if (a == 0xffffffff) return ram; } a &= rammask; - if (_mem_exec[a >> 14]) { - if (_mem_mapping_r[a >> 14]->flags & MEM_MAPPING_ROM) - cpu_prefetch_cycles = cpu_rom_prefetch_cycles; - else - cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + if (_mem_exec[a >> MEM_GRANULARITY_BITS]) { + if (is286) { + if (read_mapping[a >> MEM_GRANULARITY_BITS] && (read_mapping[a >> MEM_GRANULARITY_BITS]->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)]; + return &_mem_exec[a >> MEM_GRANULARITY_BITS][(uintptr_t)(a & MEM_GRANULARITY_PAGE) - (uintptr_t)(a2 & ~0xfff)]; } mem_log("Bad getpccache %08X\n", a); @@ -514,13 +488,9 @@ getpccache(uint32_t a) uint8_t readmembl(uint32_t addr) { - mem_logical_addr = addr; + mem_mapping_t *map; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if(addr < (uint32_t) (mem_size * 1024)) return ram[addr]; - return 0xff; - } + mem_logical_addr = addr; if (cr0 >> 31) { addr = mmutranslate_read(addr); @@ -528,8 +498,9 @@ 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 >> MEM_GRANULARITY_BITS]; + if (map && map->read_b) + return map->read_b(addr, map->p); return 0xff; } @@ -538,16 +509,11 @@ readmembl(uint32_t addr) void writemembl(uint32_t addr, uint8_t val) { + mem_mapping_t *map; mem_logical_addr = addr; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < (uint32_t) (mem_size * 1024)) - ram[addr] = val; - return; - } - - if (page_lookup[addr>>12]) { + if (page_lookup[addr>>12]) + { page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); return; @@ -559,90 +525,34 @@ 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 >> MEM_GRANULARITY_BITS]; + if (map && map->write_b) + map->write_b(addr, val, map->p); } - uint8_t readmemb386l(uint32_t seg, uint32_t addr) { - if (seg == (uint32_t) -1) { - x86gpf("NULL segment", 0); - - return -1; - } - - mem_logical_addr = addr = addr + seg; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < (uint32_t) (mem_size * 1024)) - return ram[addr]; - return 0xff; - } - - if (cr0 >> 31) { - addr = mmutranslate_read(addr); - if (addr == 0xffffffff) - return 0xff; - } - - addr &= rammask; - - if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); - - return 0xff; + return readmembl(addr + seg); } void writememb386l(uint32_t seg, uint32_t addr, uint8_t val) { - if (seg == (uint32_t) -1) { - x86gpf("NULL segment", 0); - return; - } - - mem_logical_addr = addr = addr + seg; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < (uint32_t) (mem_size * 1024)) - ram[addr] = val; - return; - } - - if (page_lookup[addr>>12]) { - page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); - - return; - } - - if (cr0 >> 31) { - addr = mmutranslate_write(addr); - if (addr == 0xffffffff) return; - } - - addr &= rammask; - - if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + writemembl(addr + seg, val); } uint16_t readmemwl(uint32_t seg, uint32_t addr) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == (uint32_t) -1) { - x86gpf("NULL segment", 0); - return -1; - } - if (addr2 & 1) { if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xFFF) > 0xffe) { if (cr0 >> 31) { if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; @@ -655,31 +565,26 @@ readmemwl(uint32_t seg, uint32_t addr) return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); } - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < (uint32_t) (mem_size * 1024)) - return *((uint16_t *)&ram[addr]); - return 0xffff; - } - if (cr0 >> 31) { addr2 = mmutranslate_read(addr2); if (addr2 == 0xffffffff) return 0xFFFF; - } + } - addr2 &= rammask; + addr2 &= rammask; - if (_mem_read_w[addr2 >> 14]) - return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + map = read_mapping[addr2 >> MEM_GRANULARITY_BITS]; - if (_mem_read_b[addr2 >> 14]) { - if (AT) - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint16_t) (_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]) | - ((uint16_t) (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14])) << 8); + if (map && map->read_w) + return map->read_w(addr2, map->p); + + if (map && map->read_b) { + if (AT) + return map->read_b(addr2, map->p) | + ((uint16_t) (map->read_b(addr2 + 1, map->p)) << 8); + else + return map->read_b(addr2, map->p) | + ((uint16_t) (map->read_b(seg + ((addr + 1) & 0xffff), map->p)) << 8); } return 0xffff; @@ -689,23 +594,12 @@ readmemwl(uint32_t seg, uint32_t addr) void writememwl(uint32_t seg, uint32_t addr, uint16_t val) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == (uint32_t) -1) { - x86gpf("NULL segment", 0); - return; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - *((uint16_t *)&ram[addr]) = val; - return; - } - if (addr2 & 1) { if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xFFF) > 0xffe) { if (cr0 >> 31) { if (mmutranslate_write(addr2) == 0xffffffff) return; @@ -737,19 +631,16 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) addr2 &= rammask; -#if 0 - if (addr2 >= 0xa0000 && addr2 < 0xc0000) - mem_log("writememwl %08X %02X\n", addr2, val); -#endif + map = write_mapping[addr2 >> MEM_GRANULARITY_BITS]; - if (_mem_write_w[addr2 >> 14]) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + if (map && map->write_w) { + map->write_w(addr2, val, map->p); return; } - if (_mem_write_b[addr2 >> 14]) { - _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_b[(addr2 + 1) >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + if (map && map->write_b) { + map->write_b(addr2, val, map->p); + map->write_b(addr2 + 1, val >> 8, map->p); return; } } @@ -758,23 +649,12 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) uint32_t readmemll(uint32_t seg, uint32_t addr) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == (uint32_t) -1) { - x86gpf("NULL segment", 0); - return -1; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - return *((uint32_t *)&ram[addr]); - return 0xffffffff; - } - if (addr2 & 3) { if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xfff) > 0xffc) { if (cr0 >> 31) { if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; @@ -793,18 +673,20 @@ readmemll(uint32_t seg, uint32_t addr) addr2 &= rammask; - if (_mem_read_l[addr2 >> 14]) - return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + map = read_mapping[addr2 >> MEM_GRANULARITY_BITS]; - if (_mem_read_w[addr2 >> 14]) - return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint32_t) (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14])) << 16); + if (map && map->read_l) + return map->read_l(addr2, map->p); - if (_mem_read_b[addr2 >> 14]) - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14])) << 8) | - ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14])) << 16) | - ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14])) << 24); + if (map && map->read_w) + return map->read_w(addr2, map->p) | + ((uint32_t) (map->read_w(addr2 + 2, map->p)) << 16); + + if (map && map->read_b) + return map->read_b(addr2, map->p) | + ((uint32_t) (map->read_b(addr2 + 1, map->p)) << 8) | + ((uint32_t) (map->read_b(addr2 + 2, map->p)) << 16) | + ((uint32_t) (map->read_b(addr2 + 3, map->p)) << 24); return 0xffffffff; } @@ -813,23 +695,12 @@ readmemll(uint32_t seg, uint32_t addr) void writememll(uint32_t seg, uint32_t addr, uint32_t val) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == (uint32_t) -1) { - x86gpf("NULL segment", 0); - return; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - *((uint32_t *)&ram[addr]) = val; - return; - } - if (addr2 & 3) { if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xfff) > 0xffc) { if (cr0 >> 31) { if (mmutranslate_write(addr2) == 0xffffffff) return; @@ -856,20 +727,22 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) addr2 &= rammask; - if (_mem_write_l[addr2 >> 14]) { - _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + map = write_mapping[addr2 >> MEM_GRANULARITY_BITS]; + + if (map && map->write_l) { + map->write_l(addr2, val, map->p); return; } - if (_mem_write_w[addr2 >> 14]) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + if (map && map->write_w) { + map->write_w(addr2, val, map->p); + map->write_w(addr2 + 2, val >> 16, map->p); 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]); + if (map && map->write_b) { + map->write_b(addr2, val, map->p); + map->write_b(addr2 + 1, val >> 8, map->p); + map->write_b(addr2 + 2, val >> 16, map->p); + map->write_b(addr2 + 3, val >> 24, map->p); return; } } @@ -878,22 +751,11 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) uint64_t readmemql(uint32_t seg, uint32_t addr) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == (uint32_t) -1) { - x86gpf("NULL segment", 0); - return -1; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - return *((uint64_t *)&ram[addr]); - return -1; - } - if (addr2 & 7) { - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xfff) > 0xff8) { if (cr0 >> 31) { if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; @@ -912,9 +774,9 @@ readmemql(uint32_t seg, uint32_t addr) addr2 &= rammask; - if (_mem_read_l[addr2 >> 14]) - return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint64_t)_mem_read_l[addr2 >> 14](addr2 + 4, _mem_priv_r[addr2 >> 14]) << 32); + map = read_mapping[addr2 >> MEM_GRANULARITY_BITS]; + if (map && map->read_l) + return map->read_l(addr2, map->p) | ((uint64_t)map->read_l(addr2 + 4, map->p) << 32); return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); } @@ -923,22 +785,11 @@ readmemql(uint32_t seg, uint32_t addr) void writememql(uint32_t seg, uint32_t addr, uint64_t val) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == (uint32_t) -1) { - x86gpf("NULL segment", 0); - return; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - *((uint64_t *)&ram[addr]) = val; - return; - } - if (addr2 & 7) { - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xfff) > 0xff8) { if (cr0 >> 31) { if (mmutranslate_write(addr2) == 0xffffffff) return; @@ -966,59 +817,60 @@ writememql(uint32_t seg, uint32_t addr, uint64_t val) addr2 &= rammask; - if (_mem_write_l[addr2 >> 14]) { - _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_l[addr2 >> 14](addr2+4, val >> 32, _mem_priv_w[addr2 >> 14]); + map = write_mapping[addr2 >> MEM_GRANULARITY_BITS]; + + if (map && map->write_l) { + map->write_l(addr2, val, map->p); + map->write_l(addr2+4, val >> 32, map->p); return; } - if (_mem_write_w[addr2 >> 14]) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + if (map && map->write_w) { + map->write_w(addr2, val, map->p); + map->write_w(addr2 + 2, val >> 16, map->p); + map->write_w(addr2 + 4, val >> 32, map->p); + map->write_w(addr2 + 6, val >> 48, map->p); 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]); + if (map && map->write_b) { + map->write_b(addr2, val, map->p); + map->write_b(addr2 + 1, val >> 8, map->p); + map->write_b(addr2 + 2, val >> 16, map->p); + map->write_b(addr2 + 3, val >> 24, map->p); + map->write_b(addr2 + 4, val >> 32, map->p); + map->write_b(addr2 + 5, val >> 40, map->p); + map->write_b(addr2 + 6, val >> 48, map->p); + map->write_b(addr2 + 7, val >> 56, map->p); return; } } +int +mem_mapping_is_romcs(uint32_t addr, int write) +{ + mem_mapping_t *map; + + if (write) + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + else + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map) + return !!(map->flags & MEM_MAPPING_ROMCS); + else + return 0; +} + + uint8_t mem_readb_phys(uint32_t addr) { - mem_logical_addr = 0xffffffff; + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); - - return 0xff; -} - - -/* - * Version of mem_readby_phys that doesn't go through - * the CPU paging mechanism. - */ -uint8_t -mem_readb_phys_dma(uint32_t addr) -{ -#if 0 - mem_logical_addr = 0xffffffff; -#endif - - if (_mem_exec[addr >> 14]) - return _mem_exec[addr >> 14][addr & 0x3fff]; - else if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + return _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK]; + else if (map && map->read_b) + return map->read_b(addr, map->p); else return 0xff; } @@ -1027,53 +879,70 @@ mem_readb_phys_dma(uint32_t addr) uint16_t mem_readw_phys(uint32_t addr) { - mem_logical_addr = 0xffffffff; + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + uint16_t temp; - if (_mem_read_w[addr >> 14]) - return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + return ((uint16_t *) _mem_exec[addr >> MEM_GRANULARITY_BITS])[(addr >> 1) & MEM_GRANULARITY_HMASK]; + else if (map && map->read_w) + return map->read_w(addr, map->p); + else { + temp = mem_readb_phys(addr + 1) << 8; + temp |= mem_readb_phys(addr); + } - return 0xff; + return temp; } +uint32_t +mem_readl_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + uint32_t temp; + + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + return ((uint32_t *) _mem_exec[addr >> MEM_GRANULARITY_BITS])[(addr >> 1) & MEM_GRANULARITY_HMASK]; + else if (map && map->read_l) + return map->read_l(addr, map->p); + else { + temp = mem_readb_phys(addr + 3) << 24; + temp |= mem_readb_phys(addr + 2) << 16; + temp |= mem_readb_phys(addr + 1) << 8; + temp |= mem_readb_phys(addr); + } + + return temp; +} void mem_writeb_phys(uint32_t addr, uint8_t val) { - mem_logical_addr = 0xffffffff; + mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; - if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK] = val; + else if (map && map->write_b) + map->write_b(addr, val, map->p); } - -/* - * Version of mem_readby_phys that doesn't go through - * the CPU paging mechanism. - */ -void -mem_writeb_phys_dma(uint32_t addr, uint8_t val) -{ -#if 0 - mem_logical_addr = 0xffffffff; -#endif - - if (_mem_exec[addr >> 14]) - _mem_exec[addr >> 14][addr & 0x3fff] = val; - else if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -} - - void -mem_writew_phys(uint32_t addr, uint16_t val) +mem_writel_phys(uint32_t addr, uint32_t val) { - mem_logical_addr = 0xffffffff; + mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; - if (_mem_write_w[addr >> 14]) - _mem_write_w[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK] = val; + else if (map && map->write_l) + map->write_l(addr, val, map->p); + else + { + mem_writeb_phys(addr, val & 0xff); + mem_writeb_phys(addr + 1, (val >> 8) & 0xff); + mem_writeb_phys(addr + 2, (val >> 16) & 0xff); + mem_writeb_phys(addr + 3, (val >> 24) & 0xff); + } } - uint8_t mem_read_ram(uint32_t addr, void *priv) { @@ -1174,49 +1043,108 @@ mem_write_raml(uint32_t addr, uint32_t val, void *priv) } +static uint8_t +mem_read_remapped(uint32_t addr, void *priv) +{ + if(addr >= (mem_size * 1024) && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} + + +static uint16_t +mem_read_remappedw(uint32_t addr, void *priv) +{ + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} + + +static uint32_t +mem_read_remappedl(uint32_t addr, void *priv) +{ + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} + + +static void +mem_write_remapped(uint32_t addr, uint8_t val, void *priv) +{ + uint32_t oldaddr = addr; + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); +} + + +static void +mem_write_remappedw(uint32_t addr, uint16_t val, void *priv) +{ + uint32_t oldaddr = addr; + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); +} + + +static void +mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) +{ + uint32_t oldaddr = addr; + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); +} + + uint8_t mem_read_bios(uint32_t addr, void *priv) { - return rom[addr & biosmask]; + uint8_t ret = 0xff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = rom[addr - biosaddr]; + + return ret; } uint16_t mem_read_biosw(uint32_t addr, void *priv) { - return *(uint16_t *)&rom[addr & biosmask]; + uint16_t ret = 0xffff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint16_t *)&rom[addr - biosaddr]; + + return ret; } uint32_t mem_read_biosl(uint32_t addr, void *priv) { - return *(uint32_t *)&rom[addr & biosmask]; -} + uint32_t ret = 0xffffffff; + addr &= 0x000fffff; -uint8_t -mem_read_romext(uint32_t addr, void *priv) -{ - return romext[addr & 0x7fff]; -} + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint32_t *)&rom[addr - biosaddr]; - -uint16_t -mem_read_romextw(uint32_t addr, void *priv) -{ - uint16_t *p = (uint16_t *)&romext[addr & 0x7fff]; - - return *p; -} - - -uint32_t -mem_read_romextl(uint32_t addr, void *priv) -{ - uint32_t *p = (uint32_t *)&romext[addr & 0x7fff]; - - return *p; + return ret; } @@ -1241,13 +1169,18 @@ mem_write_nulll(uint32_t addr, uint32_t val, void *p) void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) { + uint32_t cur_addr; start_addr &= ~PAGE_MASK_MASK; end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { uint64_t mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - pages[start_addr >> 12].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + /* Do nothing if the pages array is empty or DMA reads/writes to/from PCI device memory addresses + may crash the emulator. */ + cur_addr = (start_addr >> 12); + if (cur_addr < pages_sz) + pages[cur_addr].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; } } @@ -1256,10 +1189,22 @@ static __inline int mem_mapping_read_allowed(uint32_t flags, int state) { switch (state & MEM_READ_MASK) { + case MEM_READ_DISABLED: + return 0; + case MEM_READ_ANY: return 1; + /* On external and 0 mappings without ROMCS. */ case MEM_READ_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_ROMCS); + + /* On external and 0 mappings with ROMCS. */ + case MEM_READ_ROMCS: + return !(flags & MEM_MAPPING_INTERNAL) && (flags & MEM_MAPPING_ROMCS); + + /* On any external mappings. */ + case MEM_READ_EXTANY: return !(flags & MEM_MAPPING_INTERNAL); case MEM_READ_INTERNAL: @@ -1279,12 +1224,25 @@ mem_mapping_write_allowed(uint32_t flags, int state) switch (state & MEM_WRITE_MASK) { case MEM_WRITE_DISABLED: return 0; + case MEM_WRITE_ANY: return 1; + + /* On external and 0 mappings without ROMCS. */ case MEM_WRITE_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_ROMCS); + + /* On external and 0 mappings with ROMCS. */ + case MEM_WRITE_ROMCS: + return !(flags & MEM_MAPPING_INTERNAL) && (flags & MEM_MAPPING_ROMCS); + + /* On any external mappings. */ + case MEM_WRITE_EXTANY: return !(flags & MEM_MAPPING_INTERNAL); + case MEM_WRITE_INTERNAL: return !(flags & MEM_MAPPING_EXTERNAL); + default: fatal("mem_mapping_write_allowed : bad state %x\n", state); } @@ -1296,59 +1254,42 @@ mem_mapping_write_allowed(uint32_t flags, int state) static void mem_mapping_recalc(uint64_t base, uint64_t size) { - mem_mapping_t *mapping = base_mapping.next; + mem_mapping_t *map = base_mapping.next; uint64_t c; if (! size) return; /* Clear out old mappings. */ - for (c = base; c < base + size; c += 0x4000) { - _mem_read_b[c >> 14] = NULL; - _mem_read_w[c >> 14] = NULL; - _mem_read_l[c >> 14] = NULL; - _mem_exec[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; + for (c = base; c < base + size; c += MEM_GRANULARITY_SIZE) { + read_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + write_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; } /* Walk mapping list. */ - while (mapping != NULL) { + while (map != NULL) { /*In range?*/ - if (mapping->enable && (uint64_t)mapping->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)mapping->base + (uint64_t)mapping->size) > (uint64_t)base) { - uint64_t start = (mapping->base < base) ? mapping->base : base; - uint64_t end = (((uint64_t)mapping->base + (uint64_t)mapping->size) < (base + size)) ? ((uint64_t)mapping->base + (uint64_t)mapping->size) : (base + size); - if (start < mapping->base) - start = mapping->base; + if (map->enable && (uint64_t)map->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)map->base + (uint64_t)map->size) > (uint64_t)base) { + uint64_t start = (map->base < base) ? map->base : base; + uint64_t end = (((uint64_t)map->base + (uint64_t)map->size) < (base + size)) ? ((uint64_t)map->base + (uint64_t)map->size) : (base + size); + if (start < map->base) + start = map->base; - for (c = start; c < end; c += 0x4000) { - if ((mapping->read_b || mapping->read_w || mapping->read_l) && - mem_mapping_read_allowed(mapping->flags, _mem_state[c >> 14])) { - _mem_read_b[c >> 14] = mapping->read_b; - _mem_read_w[c >> 14] = mapping->read_w; - _mem_read_l[c >> 14] = mapping->read_l; - if (mapping->exec) - _mem_exec[c >> 14] = mapping->exec + (c - mapping->base); + for (c = start; c < end; c += MEM_GRANULARITY_SIZE) { + if ((map->read_b || map->read_w || map->read_l) && + mem_mapping_read_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS])) { + if (map->exec) + _mem_exec[c >> MEM_GRANULARITY_BITS] = map->exec + (c - map->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; + _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; + read_mapping[c >> MEM_GRANULARITY_BITS] = map; } + if ((map->write_b || map->write_w || map->write_l) && + mem_mapping_write_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS])) + write_mapping[c >> MEM_GRANULARITY_BITS] = map; } } - mapping = mapping->next; + map = map->next; } flushmmucache_cr3(); @@ -1356,7 +1297,25 @@ mem_mapping_recalc(uint64_t base, uint64_t size) void -mem_mapping_add(mem_mapping_t *mapping, +mem_mapping_del(mem_mapping_t *map) +{ + mem_mapping_t *ptr; + + /* Disable the entry. */ + mem_mapping_disable(map); + + /* Zap it from the list. */ + for (ptr = &base_mapping; ptr->next != NULL; ptr = ptr->next) { + if (ptr->next == map) { + ptr->next = map->next; + break; + } + } +} + + +void +mem_mapping_add(mem_mapping_t *map, uint32_t base, uint32_t size, uint8_t (*read_b)(uint32_t addr, void *p), @@ -1366,7 +1325,7 @@ mem_mapping_add(mem_mapping_t *mapping, void (*write_w)(uint32_t addr, uint16_t val, void *p), void (*write_l)(uint32_t addr, uint32_t val, void *p), uint8_t *exec, - uint32_t flags, + uint32_t fl, void *p) { mem_mapping_t *dest = &base_mapping; @@ -1374,32 +1333,33 @@ mem_mapping_add(mem_mapping_t *mapping, /* Add mapping to the end of the list.*/ while (dest->next) dest = dest->next; - dest->next = mapping; - mapping->prev = dest; + dest->next = map; + map->prev = dest; if (size) - mapping->enable = 1; + map->enable = 1; else - mapping->enable = 0; - mapping->base = base; - mapping->size = size; - mapping->read_b = read_b; - mapping->read_w = read_w; - mapping->read_l = read_l; - mapping->write_b = write_b; - mapping->write_w = write_w; - mapping->write_l = write_l; - mapping->exec = exec; - mapping->flags = flags; - mapping->p = p; - mapping->next = NULL; + map->enable = 0; + map->base = base; + map->size = size; + map->read_b = read_b; + map->read_w = read_w; + map->read_l = read_l; + map->write_b = write_b; + map->write_w = write_w; + map->write_l = write_l; + map->exec = exec; + map->flags = fl; + map->p = p; + map->dev = NULL; + map->next = NULL; - mem_mapping_recalc(mapping->base, mapping->size); + mem_mapping_recalc(map->base, map->size); } void -mem_mapping_set_handler(mem_mapping_t *mapping, +mem_mapping_set_handler(mem_mapping_t *map, uint8_t (*read_b)(uint32_t addr, void *p), uint16_t (*read_w)(uint32_t addr, void *p), uint32_t (*read_l)(uint32_t addr, void *p), @@ -1407,64 +1367,71 @@ mem_mapping_set_handler(mem_mapping_t *mapping, void (*write_w)(uint32_t addr, uint16_t val, void *p), void (*write_l)(uint32_t addr, uint32_t val, void *p)) { - mapping->read_b = read_b; - mapping->read_w = read_w; - mapping->read_l = read_l; - mapping->write_b = write_b; - mapping->write_w = write_w; - mapping->write_l = write_l; + map->read_b = read_b; + map->read_w = read_w; + map->read_l = read_l; + map->write_b = write_b; + map->write_w = write_w; + map->write_l = write_l; - mem_mapping_recalc(mapping->base, mapping->size); + mem_mapping_recalc(map->base, map->size); } void -mem_mapping_set_addr(mem_mapping_t *mapping, uint32_t base, uint32_t size) +mem_mapping_set_addr(mem_mapping_t *map, uint32_t base, uint32_t size) { /* Remove old mapping. */ - mapping->enable = 0; - mem_mapping_recalc(mapping->base, mapping->size); + map->enable = 0; + mem_mapping_recalc(map->base, map->size); /* Set new mapping. */ - mapping->enable = 1; - mapping->base = base; - mapping->size = size; + map->enable = 1; + map->base = base; + map->size = size; - mem_mapping_recalc(mapping->base, mapping->size); + mem_mapping_recalc(map->base, map->size); } void -mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec) +mem_mapping_set_exec(mem_mapping_t *map, uint8_t *exec) { - mapping->exec = exec; + map->exec = exec; - mem_mapping_recalc(mapping->base, mapping->size); + mem_mapping_recalc(map->base, map->size); } void -mem_mapping_set_p(mem_mapping_t *mapping, void *p) +mem_mapping_set_p(mem_mapping_t *map, void *p) { - mapping->p = p; + map->p = p; } void -mem_mapping_disable(mem_mapping_t *mapping) +mem_mapping_set_dev(mem_mapping_t *map, void *p) { - mapping->enable = 0; - - mem_mapping_recalc(mapping->base, mapping->size); + map->dev = p; } void -mem_mapping_enable(mem_mapping_t *mapping) +mem_mapping_disable(mem_mapping_t *map) { - mapping->enable = 1; + map->enable = 0; - mem_mapping_recalc(mapping->base, mapping->size); + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_enable(mem_mapping_t *map) +{ + map->enable = 1; + + mem_mapping_recalc(map->base, map->size); } @@ -1473,8 +1440,8 @@ mem_set_mem_state(uint32_t base, uint32_t size, int state) { uint32_t c; - for (c = 0; c < size; c += 0x4000) - _mem_state[(c + base) >> 14] = state; + for (c = 0; c < size; c += MEM_GRANULARITY_SIZE) + _mem_state[(c + base) >> MEM_GRANULARITY_BITS] = state; mem_mapping_recalc(base, size); } @@ -1483,89 +1450,34 @@ mem_set_mem_state(uint32_t base, uint32_t size, int state) void mem_add_bios(void) { - if (AT || (romset == ROM_XI8088 && xi8088_bios_128kb())) { - mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, + if (biosmask > 0x1ffff) { + /* 256k+ BIOS'es only have low mappings at E0000-FFFFF. */ + mem_mapping_add(&bios_mapping, 0xe0000, 0x20000, mem_read_bios,mem_read_biosw,mem_read_biosl, mem_write_null,mem_write_nullw,mem_write_nulll, - rom,MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, + &rom[0x20000], MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); + + mem_set_mem_state(0x0e0000, 0x20000, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); + } else { + mem_mapping_add(&bios_mapping, biosaddr, biosmask + 1, mem_read_bios,mem_read_biosw,mem_read_biosl, mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x4000 & 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 + (0x8000 & 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 + (0xc000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); + + mem_set_mem_state(biosaddr, biosmask + 1, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); } - 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|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 + (0x14000 & 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 + (0x18000 & 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 + (0x1c000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + if (AT) { + mem_mapping_add(&bios_high_mapping, biosaddr | (cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 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, 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 + (0x4000 & 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 + (0x8000 & 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 + (0xc000 & 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 + (0x10000 & 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 + (0x14000 & 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 + (0x18000 & 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 + (0x1c000 & biosmask), MEM_MAPPING_ROM, 0); + mem_set_mem_state(biosaddr | (cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); + } } @@ -1590,22 +1502,7 @@ mem_reset(void) { uint32_t c, m; - /* Free the ROM memory and reset size mask. */ - if (rom != NULL) { - free(rom); - rom = NULL; - } - biosmask = 0xffff; - - /* - * Always allocate the full 16 MB memory space if memory size - * is smaller, we'll need this for stupid things like the PS/2 - * split mapping. - */ - if (mem_size < 16384) - m = 1024UL * 16384; - else - m = 1024UL * (mem_size + 384); /* 386 extra kB for top remapping */ + m = 1024UL * mem_size; if (ram != NULL) { free(ram); ram = NULL; @@ -1673,30 +1570,16 @@ mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *)); #endif - memset(pages, 0x00, pages_sz*sizeof(page_t)); + memset(pages, 0x00, pages_sz*sizeof(page_t)); - for (c=0; c= 0xa && c <= 0xf) || - (cpu_16bitbus && c >= 0xfe && c <= 0xff)) - isram[c] = 0; - } - - memset(_mem_read_b, 0x00, sizeof(_mem_read_b)); - memset(_mem_read_w, 0x00, sizeof(_mem_read_w)); - memset(_mem_read_l, 0x00, sizeof(_mem_read_l)); - memset(_mem_write_b, 0x00, sizeof(_mem_write_b)); - memset(_mem_write_w, 0x00, sizeof(_mem_write_w)); - memset(_mem_write_l, 0x00, sizeof(_mem_write_l)); memset(_mem_exec, 0x00, sizeof(_mem_exec)); memset(&base_mapping, 0x00, sizeof(base_mapping)); @@ -1739,18 +1622,13 @@ mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); 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 (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); - - 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 + (1 << 20), MEM_MAPPING_INTERNAL, NULL); - mem_mapping_disable(&ram_remapped_mapping); - + + mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 256 * 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); + mem_mapping_disable(&ram_remapped_mapping); + mem_a20_init(); } @@ -1775,8 +1653,6 @@ mem_init(void) writelookup2 = malloc((1<<20)*sizeof(uintptr_t)); #endif - memset(ram_mapped_addr, 0x00, 64 * sizeof(uint32_t)); - #if FIXME memset(ff_array, 0xff, sizeof(ff_array)); #endif @@ -1786,45 +1662,41 @@ mem_init(void) } -static void -mem_remap_top(int max_size) +void +mem_remap_top(int kb) { - uint32_t c; + int c; + uint32_t start = (mem_size >= 1024) ? mem_size : 1024; + int size = mem_size - 640; - if (mem_size > 640) { - uint32_t start = (mem_size >= 1024) ? mem_size : 1024; - int size = mem_size - 640; - if (size > max_size) - size = max_size; + mem_log("MEM: remapping top %iKB (mem=%i)\n", kb, mem_size); + if (mem_size <= 640) return; - for (c = (start / 64); c < ((start + size - 1) / 64); c++) - isram[c] = 1; + if (kb == 0) { + /* Called to disable the mapping. */ + mem_mapping_disable(&ram_remapped_mapping); - mem_set_mem_state(start * 1024, size * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_set_addr(&ram_remapped_mapping, - start * 1024, size * 1024); - mem_mapping_set_exec(&ram_remapped_mapping, ram + (start * 1024)); + return; + } + + if (size > kb) + size = kb; - flushmmucache(); + for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++) { + pages[c].mem = &ram[0xA0000 + ((c - ((start * 1024) >> 12)) << 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; } + + mem_set_mem_state(start * 1024, size * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, size * 1024); + mem_mapping_set_exec(&ram_remapped_mapping, ram + (start * 1024)); + + flushmmucache(); } - -void -mem_remap_top_256k(void) -{ - mem_remap_top(256); -} - - -void -mem_remap_top_384k(void) -{ - mem_remap_top(384); -} - - void mem_reset_page_blocks(void) { @@ -1832,7 +1704,7 @@ mem_reset_page_blocks(void) if (pages == NULL) return; - for (c = 0; c < ((mem_size * 1024) >> 12); c++) { + for (c = 0; c < pages_sz; c++) { pages[c].write_b = mem_write_ramb_page; pages[c].write_w = mem_write_ramw_page; pages[c].write_l = mem_write_raml_page; @@ -1866,61 +1738,3 @@ mem_a20_recalc(void) mem_a20_state = state; } - - -uint8_t -port_92_read(uint16_t port, void *priv) -{ - return port_92_reg; -} - - -void -port_92_write(uint16_t port, uint8_t val, void *priv) -{ - if ((mem_a20_alt ^ val) & 2) { - mem_a20_alt = (val & 2); - mem_a20_recalc(); - } - - if ((~port_92_reg & val) & 1) { - softresetx86(); - cpu_set_edx(); - } - - port_92_reg = val; -} - - -void -port_92_clear_reset(void) -{ - port_92_reg &= 2; -} - - -void -port_92_add(void) -{ - io_sethandler(0x0092, 1, - port_92_read,NULL,NULL, port_92_write, NULL,NULL,NULL); -} - - -void -port_92_remove(void) -{ - io_removehandler(0x0092, 1, - port_92_read,NULL,NULL, port_92_write,NULL,NULL, NULL); -} - - -void -port_92_reset(void) -{ - port_92_reg = 0; - mem_a20_alt = 0; - mem_a20_recalc(); - - flushmmucache(); -} diff --git a/src/mem.h b/src/mem.h index 660bab616..6b5641ee6 100644 --- a/src/mem.h +++ b/src/mem.h @@ -1,38 +1,22 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Definitions for the memory interface. * - * Version: @(#)mem.h 1.0.4 2018/03/16 + * Version: @(#)mem.h 1.0.10 2019/10/19 * - * Authors: Fred N. van Kempen, - * Sarah Walker, + * Authors: Sarah Walker, + * Fred N. van Kempen, + * Miran Grca, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2008-2018 Sarah Walker. - * - * 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. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. */ #ifndef EMU_MEM_H # define EMU_MEM_H @@ -42,6 +26,7 @@ #define MEM_MAPPING_INTERNAL 2 /* on internal bus (RAM) */ #define MEM_MAPPING_ROM 4 /* Executing from ROM may involve * additional wait states. */ +#define MEM_MAPPING_ROMCS 8 /* respond to ROMCS* */ #define MEM_MAP_TO_SHADOW_RAM_MASK 1 #define MEM_MAP_TO_RAM_ADDR_MASK 2 @@ -49,14 +34,40 @@ #define MEM_READ_ANY 0x00 #define MEM_READ_INTERNAL 0x10 #define MEM_READ_EXTERNAL 0x20 +#define MEM_READ_DISABLED 0x30 +#define MEM_READ_ROMCS 0x60 /* EXTERNAL type + ROMC flag */ +#define MEM_READ_EXTANY 0x70 /* Any EXTERNAL type */ #define MEM_READ_MASK 0xf0 #define MEM_WRITE_ANY 0x00 #define MEM_WRITE_INTERNAL 0x01 #define MEM_WRITE_EXTERNAL 0x02 #define MEM_WRITE_DISABLED 0x03 +#define MEM_WRITE_ROMCS 0x06 /* EXTERNAL type + ROMC flag */ +#define MEM_WRITE_EXTANY 0x07 /* Any EXTERNAL type */ #define MEM_WRITE_MASK 0x0f +/* #define's for memory granularity, currently 16k, but may + change in the future - 4k works, less does not because of + internal 4k pages. */ +#ifdef DEFAULT_GRANULARITY +#define MEM_GRANULARITY_BITS 14 +#define MEM_GRANULARITY_SIZE (1 << MEM_GRANULARITY_BITS) +#define MEM_GRANULARITY_MASK (MEM_GRANULARITY_SIZE - 1) +#define MEM_GRANULARITY_HMASK ((1 << (MEM_GRANULARITY_BITS - 1)) - 1) +#define MEM_GRANULARITY_QMASK ((1 << (MEM_GRANULARITY_BITS - 2)) - 1) +#define MEM_MAPPINGS_NO ((0x100000 >> MEM_GRANULARITY_BITS) << 12) +#define MEM_GRANULARITY_PAGE (MEM_GRANULARITY_MASK & ~0xfff) +#else +#define MEM_GRANULARITY_BITS 12 +#define MEM_GRANULARITY_SIZE (1 << MEM_GRANULARITY_BITS) +#define MEM_GRANULARITY_MASK (MEM_GRANULARITY_SIZE - 1) +#define MEM_GRANULARITY_HMASK ((1 << (MEM_GRANULARITY_BITS - 1)) - 1) +#define MEM_GRANULARITY_QMASK ((1 << (MEM_GRANULARITY_BITS - 2)) - 1) +#define MEM_MAPPINGS_NO ((0x100000 >> MEM_GRANULARITY_BITS) << 12) +#define MEM_GRANULARITY_PAGE (MEM_GRANULARITY_MASK & ~0xfff) +#endif + typedef struct _mem_mapping_ { struct _mem_mapping_ *prev, *next; @@ -77,9 +88,50 @@ typedef struct _mem_mapping_ { uint32_t flags; - void *p; + void *p; /* backpointer to mapping or device */ + + void *dev; /* backpointer to memory device */ } mem_mapping_t; +#ifdef USE_NEW_DYNAREC +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); + void (*write_w)(uint32_t addr, uint16_t val, struct page_t *p); + void (*write_l)(uint32_t addr, uint32_t val, struct page_t *p); + + uint8_t *mem; + + uint16_t block, block_2; + + /*Head of codeblock tree associated with this page*/ + 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 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); +#else typedef struct _page_ { void (*write_b)(uint32_t addr, uint8_t val, struct _page_ *p); void (*write_w)(uint32_t addr, uint16_t val, struct _page_ *p); @@ -95,14 +147,14 @@ typedef struct _page_ { /*Head of codeblock tree associated with this page*/ struct codeblock_t *head; } page_t; +#endif extern uint8_t *ram; extern uint32_t rammask; extern uint8_t *rom; -extern uint8_t romext[32768]; -extern uint32_t biosmask; +extern uint32_t biosmask, biosaddr; extern int readlookup[256], readlookupp[256]; @@ -114,12 +166,15 @@ extern uintptr_t *writelookup2; extern int writelnext; extern uint32_t ram_mapped_addr[64]; -extern mem_mapping_t bios_mapping[8], - bios_high_mapping[8], - romext_mapping, +mem_mapping_t base_mapping, ram_low_mapping, +#if 1 ram_mid_mapping, - ram_high_mapping; +#endif + ram_remapped_mapping, + ram_high_mapping, + bios_mapping, + bios_high_mapping; extern uint32_t mem_logical_addr; @@ -133,9 +188,7 @@ extern int shadowbios, extern int readlnum, writelnum; -extern int nopageerrors; extern int memspeed[11]; -extern uint8_t isram[0x10000]; extern int mmu_perm; @@ -144,11 +197,11 @@ extern int mem_a20_state, mem_a20_key; +#ifndef USE_NEW_DYNAREC #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)) & 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)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) - extern uint8_t readmembl(uint32_t addr); extern void writemembl(uint32_t addr, uint8_t val); extern uint8_t readmemb386l(uint32_t seg, uint32_t addr); @@ -159,13 +212,25 @@ extern uint32_t readmemll(uint32_t seg, uint32_t addr); extern void writememll(uint32_t seg, uint32_t addr, uint32_t val); extern uint64_t readmemql(uint32_t seg, uint32_t addr); extern void writememql(uint32_t seg, uint32_t addr, uint64_t val); +#else +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_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); +#endif extern uint8_t *getpccache(uint32_t a); extern uint32_t mmutranslatereal(uint32_t addr, int rw); extern void addreadlookup(uint32_t virt, uint32_t phys); extern void addwritelookup(uint32_t virt, uint32_t phys); -extern void mem_mapping_add(mem_mapping_t *mapping, +extern void mem_mapping_del(mem_mapping_t *); + +extern void mem_mapping_add(mem_mapping_t *, uint32_t base, uint32_t size, uint8_t (*read_b)(uint32_t addr, void *p), @@ -178,7 +243,7 @@ extern void mem_mapping_add(mem_mapping_t *mapping, uint32_t flags, void *p); -extern void mem_mapping_set_handler(mem_mapping_t *mapping, +extern void mem_mapping_set_handler(mem_mapping_t *, uint8_t (*read_b)(uint32_t addr, void *p), uint16_t (*read_w)(uint32_t addr, void *p), uint32_t (*read_l)(uint32_t addr, void *p), @@ -186,22 +251,23 @@ extern void mem_mapping_set_handler(mem_mapping_t *mapping, void (*write_w)(uint32_t addr, uint16_t val, void *p), void (*write_l)(uint32_t addr, uint32_t val, void *p)); -extern void mem_mapping_set_p(mem_mapping_t *mapping, void *p); +extern void mem_mapping_set_p(mem_mapping_t *, void *p); -extern void mem_mapping_set_addr(mem_mapping_t *mapping, +extern void mem_mapping_set_dev(mem_mapping_t *, void *dev); + +extern void mem_mapping_set_addr(mem_mapping_t *, uint32_t base, uint32_t size); -extern void mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec); -extern void mem_mapping_disable(mem_mapping_t *mapping); -extern void mem_mapping_enable(mem_mapping_t *mapping); +extern void mem_mapping_set_exec(mem_mapping_t *, uint8_t *exec); +extern void mem_mapping_disable(mem_mapping_t *); +extern void mem_mapping_enable(mem_mapping_t *); extern void mem_set_mem_state(uint32_t base, uint32_t size, int state); extern uint8_t mem_readb_phys(uint32_t addr); -extern uint8_t mem_readb_phys_dma(uint32_t addr); extern uint16_t mem_readw_phys(uint32_t addr); +extern uint32_t mem_readl_phys(uint32_t addr); extern void mem_writeb_phys(uint32_t addr, uint8_t val); -extern void mem_writeb_phys_dma(uint32_t addr, uint8_t val); -extern void mem_writew_phys(uint32_t addr, uint16_t val); +extern void mem_writel_phys(uint32_t addr, uint32_t val); extern uint8_t mem_read_ram(uint32_t addr, void *priv); extern uint16_t mem_read_ramw(uint32_t addr, void *priv); @@ -218,6 +284,8 @@ extern void mem_write_null(uint32_t addr, uint8_t val, void *p); extern void mem_write_nullw(uint32_t addr, uint16_t val, void *p); extern void mem_write_nulll(uint32_t addr, uint32_t val, void *p); +extern int mem_addr_is_ram(uint32_t addr); + extern uint32_t mmutranslate_noabrt(uint32_t addr, int rw); extern void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr); @@ -236,51 +304,54 @@ extern void mmu_invalidate(uint32_t addr); extern void mem_a20_recalc(void); +extern void mem_add_upper_bios(void); extern void mem_add_bios(void); extern void mem_init(void); extern void mem_reset(void); -extern void mem_remap_top_256k(void); -extern void mem_remap_top_384k(void); - -extern uint8_t port_92_read(uint16_t port, void *priv); -extern void port_92_write(uint16_t port, uint8_t val, void *priv); -extern void port_92_clear_reset(void); -extern void port_92_add(void); -extern void port_92_remove(void); -extern void port_92_reset(void); +extern void mem_remap_top(int kb); #ifdef EMU_CPU_H static __inline uint32_t get_phys(uint32_t addr) { - if (! ((addr ^ get_phys_virt) & ~0xfff)) + if (!((addr ^ get_phys_virt) & ~0xfff)) return get_phys_phys | (addr & 0xfff); get_phys_virt = addr; - - if (! (cr0 >> 31)) { + + if (!(cr0 >> 31)) { get_phys_phys = (addr & rammask) & ~0xfff; - return addr & rammask; } - get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff; + if (((int) (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); + } -#if 1 return get_phys_phys | (addr & 0xfff); -#else - return mmutranslatereal(addr, 0) & rammask; -#endif } static __inline uint32_t get_phys_noabrt(uint32_t addr) { - if (! (cr0 >> 31)) + uint32_t phys_addr; + + if (!(cr0 >> 31)) return addr & rammask; - return mmutranslate_noabrt(addr, 0) & rammask; + if (((int) (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; } #endif diff --git a/src/mem_new.c b/src/mem_new.c new file mode 100644 index 000000000..4fd4dbc91 --- /dev/null +++ b/src/mem_new.c @@ -0,0 +1,1802 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Memory handling and MMU. + * + * NOTE: Experimenting with dynamically allocated lookup tables; + * the DYNAMIC_TABLES=1 enables this. Will eventually go + * away, either way... + * + * Version: @(#)mem.c 1.0.22 2019/12/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu_new/cpu.h" +#include "cpu_new/x86_ops.h" +#include "cpu_new/x86.h" +#include "machine/machine.h" +#include "machine/m_xt_xi8088.h" +#include "config.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#ifdef USE_DYNAREC +# include "cpu_new/codegen.h" +#else +# define PAGE_MASK_INDEX_MASK 3 +# define PAGE_MASK_INDEX_SHIFT 10 +# define PAGE_MASK_MASK 63 +# define PAGE_MASK_SHIFT 4 +#endif + + +#define FIXME 0 +#define DYNAMIC_TABLES 0 /* experimental */ + + +mem_mapping_t base_mapping, + ram_low_mapping, /* 0..640K mapping */ +#if 1 + ram_mid_mapping, +#endif + ram_remapped_mapping, /* 640..1024K mapping */ + ram_high_mapping, /* 1024K+ mapping */ + ram_remapped_mapping, + ram_split_mapping, + bios_mapping, + bios_high_mapping; + +page_t *pages, /* RAM page table */ + **page_lookup; /* pagetable lookup */ +uint32_t pages_sz; /* #pages in table */ + +uint8_t *ram; /* the virtual RAM */ +uint32_t rammask; + +uint8_t *rom; /* the virtual ROM */ +uint32_t biosmask, biosaddr; + +uint32_t pccache; +uint8_t *pccache2; + +int readlnext; +int readlookup[256], + readlookupp[256]; +uintptr_t *readlookup2; +int writelnext; +int writelookup[256], + writelookupp[256]; +uintptr_t *writelookup2; + +uint32_t mem_logical_addr; + +int shadowbios = 0, + shadowbios_write; +int readlnum = 0, + writelnum = 0; +int cachesize = 256; + +uint32_t get_phys_virt, + get_phys_phys; + +int mem_a20_key = 0, + mem_a20_alt = 0, + mem_a20_state = 0; + +int mmuflush = 0; +int mmu_perm = 4; + +uint64_t *byte_dirty_mask; +uint64_t *byte_code_present_mask; + +uint32_t purgable_page_list_head = 0; +int purgeable_page_count = 0; + + +/* FIXME: re-do this with a 'mem_ops' struct. */ +static mem_mapping_t *read_mapping[MEM_MAPPINGS_NO]; +static mem_mapping_t *write_mapping[MEM_MAPPINGS_NO]; +static uint8_t *_mem_exec[MEM_MAPPINGS_NO]; +static int _mem_state[MEM_MAPPINGS_NO]; + +#if FIXME +#if (MEM_GRANULARITY_BITS >= 12) +static uint8_t ff_array[MEM_GRANULARITY_SIZE]; +#else +static uint8_t ff_array[4096]; /* Must be at least one page. */ +#endif +#else +static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; +#endif + + +#ifdef ENABLE_MEM_LOG +int mem_do_log = ENABLE_MEM_LOG; + + +static void +mem_log(const char *fmt, ...) +{ + va_list ap; + + if (mem_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define mem_log(fmt, ...) +#endif + + +int +mem_addr_is_ram(uint32_t addr) +{ + mem_mapping_t *mapping = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) || (mapping == &ram_remapped_mapping); +} + + +void +resetreadlookup(void) +{ + int c; + + /* This is NULL after app startup, when mem_init() has not yet run. */ +#if DYNAMIC_TABLES +mem_log("MEM: reset_lookup: pages=%08lx, lookup=%08lx, pages_sz=%i\n", pages, page_lookup, pages_sz); +#endif + + /* Initialize the page lookup table. */ +#if DYNAMIC_TABLES + memset(page_lookup, 0x00, pages_sz*sizeof(page_t *)); +#else + memset(page_lookup, 0x00, (1<<20)*sizeof(page_t *)); +#endif + + /* Initialize the tables for lower (<= 1024K) RAM. */ + for (c = 0; c < 256; c++) { + readlookup[c] = 0xffffffff; + writelookup[c] = 0xffffffff; + } + + /* Initialize the tables for high (> 1024K) RAM. */ +#if DYNAMIC_TABLES + memset(readlookup2, 0xff, pages_sz*sizeof(uintptr_t)); + memset(writelookup2, 0xff, pages_sz*sizeof(uintptr_t)); +#else + memset(readlookup2, 0xff, (1<<20)*sizeof(uintptr_t)); + memset(writelookup2, 0xff, (1<<20)*sizeof(uintptr_t)); +#endif + + readlnext = 0; + writelnext = 0; + pccache = 0xffffffff; +} + + +void +flushmmucache(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } + mmuflush++; + + pccache = (uint32_t)0xffffffff; + pccache2 = (uint8_t *)0xffffffff; + +#ifdef USE_DYNAREC + codegen_flush(); +#endif +} + + +void +flushmmucache_nopc(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } +} + + +void +flushmmucache_cr3(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } +} + + +void +mem_flush_write_page(uint32_t addr, uint32_t virt) +{ + page_t *page_target = &pages[addr >> 12]; + int c; + + for (c = 0; c < 256; c++) { + if (writelookup[c] != (int) 0xffffffff) { + uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; + + if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) { + writelookup2[writelookup[c]] = -1; + page_lookup[writelookup[c]] = NULL; + writelookup[c] = 0xffffffff; + } + } + } +} + + +#define mmutranslate_read(addr) mmutranslatereal(addr,0) +#define mmutranslate_write(addr) mmutranslatereal(addr,1) +#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 2) & MEM_GRANULARITY_QMASK] + +uint32_t +mmutranslatereal(uint32_t addr, int rw) +{ + uint32_t temp,temp2,temp3; + uint32_t addr2; + + if (cpu_state.abrt) return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + if (! (temp&1)) { + cr2 = addr; + temp &= 1; + if (CPL == 3) temp |= 4; + if (rw) temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return -1; + } + + 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))) { + 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; + rammap(addr2) |= 0x20; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); + temp3 = temp & temp2; + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && ((CPL == 3 && !cpl_override) || cr0&WP_FLAG))) { + 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; + rammap(addr2) |= 0x20; + rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw?0x60:0x20); + + return (temp&~0xfff)+(addr&0xfff); +} + + +uint32_t +mmutranslate_noabrt(uint32_t addr, int rw) +{ + uint32_t temp,temp2,temp3; + uint32_t addr2; + + if (cpu_state.abrt) + return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + + if (! (temp & 1)) + return -1; + + 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 = rammap((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))) + return -1; + + return (temp & ~0xfff) + (addr & 0xfff); +} + + +void +mmu_invalidate(uint32_t addr) +{ + flushmmucache_cr3(); +} + + +uint8_t +mem_addr_range_match(uint32_t addr, uint32_t start, uint32_t len) +{ + if (addr < start) + return 0; + else if (addr >= (start + len)) + return 0; + else + return 1; +} + + +uint32_t +mem_addr_translate(uint32_t addr, uint32_t chunk_start, uint32_t len) +{ + uint32_t mask = len - 1; + + return chunk_start + (addr & mask); +} + + +void +addreadlookup(uint32_t virt, uint32_t phys) +{ + if (virt == 0xffffffff) return; + + if (readlookup2[virt>>12] != (uintptr_t) -1) return; + + if (readlookup[readlnext] != (int) 0xffffffff) + readlookup2[readlookup[readlnext]] = -1; + + readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + + readlookupp[readlnext] = mmu_perm; + readlookup[readlnext++] = virt >> 12; + readlnext &= (cachesize-1); + + sub_cycles(9); +} + + +void +addwritelookup(uint32_t virt, uint32_t phys) +{ + if (virt == 0xffffffff) return; + + if (page_lookup[virt >> 12]) return; + + if (writelookup[writelnext] != -1) { + page_lookup[writelookup[writelnext]] = NULL; + writelookup2[writelookup[writelnext]] = -1; + } + + if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page) + page_lookup[virt >> 12] = &pages[phys >> 12];//(uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + else + writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + + writelookupp[writelnext] = mmu_perm; + writelookup[writelnext++] = virt >> 12; + writelnext &= (cachesize - 1); + + sub_cycles(9); +} + + +uint8_t * +getpccache(uint32_t a) +{ + uint32_t a2; + + a2 = a; + + if (cr0 >> 31) { + a = mmutranslate_read(a); + + if (a == 0xffffffff) return ram; + } + a &= rammask; + + if (_mem_exec[a >> MEM_GRANULARITY_BITS]) { + if (is286) { + if (read_mapping[a >> MEM_GRANULARITY_BITS] && (read_mapping[a >> MEM_GRANULARITY_BITS]->flags & MEM_MAPPING_ROM)) + cpu_prefetch_cycles = cpu_rom_prefetch_cycles; + else + cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + } + + return &_mem_exec[a >> MEM_GRANULARITY_BITS][(uintptr_t)(a & MEM_GRANULARITY_PAGE) - (uintptr_t)(a2 & ~0xfff)]; + } + + mem_log("Bad getpccache %08X\n", a); + +#if FIXME + return &ff_array[0-(uintptr_t)(a2 & ~0xfff)]; +#else + return (uint8_t *)&ff_pccache; +#endif +} + + +uint8_t +readmembl(uint32_t addr) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + if (cr0 >> 31) { + addr = mmutranslate_read(addr); + if (addr == 0xFFFFFFFF) return 0xFF; + } + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_b) + return map->read_b(addr, map->p); + return 0xFF; +} + + +void +writemembl(uint32_t addr, uint8_t val) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0 >> 31) { + addr = mmutranslate_write(addr); + if (addr == 0xFFFFFFFF) + return; + } + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->write_b) + return map->write_b(addr, val, map->p); +} + + +uint16_t +readmemwl(uint32_t addr) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + sub_cycles(timing_misaligned); + if ((addr & 0xFFF) > 0xFFE) { + 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); + } else if (readlookup2[addr >> 12] != -1) + return *(uint16_t *)(readlookup2[addr >> 12] + addr); + } + if (cr0>>31) { + addr = mmutranslate_read(addr); + if (addr==0xFFFFFFFF) + return 0xFFFF; + } + + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + 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); + } + + return 0xffff; +} + + +void +writememwl(uint32_t addr, uint16_t val) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + sub_cycles(timing_misaligned); + if ((addr & 0xFFF) > 0xFFE) { + 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; + } else if (writelookup2[addr >> 12] != -1) { + *(uint16_t *)(writelookup2[addr >> 12] + addr) = val; + return; + } + } + + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_w(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0>>31) { + addr = mmutranslate_write(addr); + if (addr==0xFFFFFFFF) + return; + } + + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + 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); + } + } +} + + +uint32_t +readmemll(uint32_t addr) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + sub_cycles(timing_misaligned); + if ((addr&0xFFF)>0xFFC) { + 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); + } else if (readlookup2[addr >> 12] != -1) + return *(uint32_t *)(readlookup2[addr >> 12] + addr); + } + + if (cr0>>31) { + addr = mmutranslate_read(addr); + if (addr==0xFFFFFFFF) + return 0xFFFFFFFF; + } + + addr&=rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + if (map->read_l) + return map->read_l(addr, map->p); + + if (map->read_w) + return map->read_w(addr, map->p) | (map->read_w(addr + 2, map->p) << 16); + + 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); + } + + return 0xffffffff; +} + + +void +writememll(uint32_t addr, uint32_t val) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + sub_cycles(timing_misaligned); + if ((addr & 0xFFF) > 0xFFC) { + 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; + } + } + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_l(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0>>31) { + addr = mmutranslate_write(addr); + if (addr==0xFFFFFFFF) + return; + } + + addr&=rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + 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); + } + } +} + + +uint64_t +readmemql(uint32_t addr) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 7) { + sub_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) { + addr = mmutranslate_read(addr); + if (addr==0xFFFFFFFF) + return 0xFFFFFFFF; + } + + addr&=rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_l) + return map->read_l(addr, map->p) | ((uint64_t)map->read_l(addr + 4, map->p) << 32); + + return readmemll(addr) | ((uint64_t)readmemll(addr+4)<<32); +} + + +void +writememql(uint32_t addr, uint64_t val) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 7) { + sub_cycles(timing_misaligned); + if ((addr & 0xFFF) > 0xFF8) { + 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; + } + } + if (page_lookup[addr>>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) { + addr = mmutranslate_write(addr); + if (addr==0xFFFFFFFF) + return; + } + + addr&=rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + 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); + } + } +} + + +int +mem_mapping_is_romcs(uint32_t addr, int write) +{ + mem_mapping_t *map; + + if (write) + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + else + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map) + return !!(map->flags & MEM_MAPPING_ROMCS); + else + return 0; +} + + +uint8_t +mem_readb_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + return _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK]; + else if (map && map->read_b) + return map->read_b(addr, map->p); + else + return 0xff; +} + + +uint16_t +mem_readw_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + uint16_t temp; + + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + return ((uint16_t *) _mem_exec[addr >> MEM_GRANULARITY_BITS])[(addr >> 1) & MEM_GRANULARITY_HMASK]; + else if (map && map->read_w) + return map->read_w(addr, map->p); + else { + temp = mem_readb_phys(addr + 1) << 8; + temp |= mem_readb_phys(addr); + } + + return temp; +} + +uint32_t +mem_readl_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + uint32_t temp; + + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + return ((uint32_t *) _mem_exec[addr >> MEM_GRANULARITY_BITS])[(addr >> 1) & MEM_GRANULARITY_HMASK]; + else if (map && map->read_l) + return map->read_l(addr, map->p); + else { + temp = mem_readb_phys(addr + 3) << 24; + temp |= mem_readb_phys(addr + 2) << 16; + temp |= mem_readb_phys(addr + 1) << 8; + temp |= mem_readb_phys(addr); + } + + return temp; +} + + +void +mem_writeb_phys(uint32_t addr, uint8_t val) +{ + mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK] = val; + else if (map && map->write_b) + map->write_b(addr, val, map->p); +} + +void +mem_writel_phys(uint32_t addr, uint32_t val) +{ + mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK] = val; + else if (map && map->write_l) + map->write_l(addr, val, map->p); + else + { + mem_writeb_phys(addr, val & 0xff); + mem_writeb_phys(addr + 1, (val >> 8) & 0xff); + mem_writeb_phys(addr + 2, (val >> 16) & 0xff); + mem_writeb_phys(addr + 3, (val >> 24) & 0xff); + } +} + +uint8_t +mem_read_ram(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return ram[addr]; +} + + +uint16_t +mem_read_ramw(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return *(uint16_t *)&ram[addr]; +} + + +uint32_t +mem_read_raml(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return *(uint32_t *)&ram[addr]; +} + + +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) +{ + 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) +{ + 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); + 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); + + p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + 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)) + page_add_to_evict_list(p); + } +} + + +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); + 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); + *(uint16_t *)&p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + 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)) + 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)) + page_add_to_evict_list(p); + } +} + + +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); + 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); + *(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))) + 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)) + page_add_to_evict_list(p); + } + } +} + + +void +mem_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); +} + + +void +mem_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); +} + + +void +mem_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); +} + + +static uint8_t +mem_read_remapped(uint32_t addr, void *priv) +{ + if(addr >= (mem_size * 1024) && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} + + +static uint16_t +mem_read_remappedw(uint32_t addr, void *priv) +{ + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} + + +static uint32_t +mem_read_remappedl(uint32_t addr, void *priv) +{ + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} + + +static void +mem_write_remapped(uint32_t addr, uint8_t val, void *priv) +{ + uint32_t oldaddr = addr; + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); +} + + +static void +mem_write_remappedw(uint32_t addr, uint16_t val, void *priv) +{ + uint32_t oldaddr = addr; + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); +} + + +static void +mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) +{ + uint32_t oldaddr = addr; + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); +} + + +uint8_t +mem_read_bios(uint32_t addr, void *priv) +{ + uint8_t ret = 0xff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = rom[addr - biosaddr]; + + return ret; +} + + +uint16_t +mem_read_biosw(uint32_t addr, void *priv) +{ + uint16_t ret = 0xffff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint16_t *)&rom[addr - biosaddr]; + + return ret; +} + + +uint32_t +mem_read_biosl(uint32_t addr, void *priv) +{ + uint32_t ret = 0xffffffff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint32_t *)&rom[addr - biosaddr]; + + return ret; +} + + +void +mem_write_null(uint32_t addr, uint8_t val, void *p) +{ +} + + +void +mem_write_nullw(uint32_t addr, uint16_t val, void *p) +{ +} + + +void +mem_write_nulll(uint32_t addr, uint32_t val, void *p) +{ +} + + +void +mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) +{ + uint64_t mask; + page_t *p; + + start_addr &= ~PAGE_MASK_MASK; + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + + for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { + if ((start_addr >> 12) >= pages_sz) + continue; + + mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + p = &pages[start_addr >> 12]; + + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } +} + + +static __inline int +mem_mapping_read_allowed(uint32_t flags, int state) +{ + switch (state & MEM_READ_MASK) { + case MEM_READ_DISABLED: + return 0; + + case MEM_READ_ANY: + return 1; + + /* On external and 0 mappings without ROMCS. */ + case MEM_READ_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_ROMCS); + + /* On external and 0 mappings with ROMCS. */ + case MEM_READ_ROMCS: + return !(flags & MEM_MAPPING_INTERNAL) && (flags & MEM_MAPPING_ROMCS); + + /* On any external mappings. */ + case MEM_READ_EXTANY: + return !(flags & MEM_MAPPING_INTERNAL); + + case MEM_READ_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + + default: + fatal("mem_mapping_read_allowed : bad state %x\n", state); + } + + return 0; +} + + +static __inline int +mem_mapping_write_allowed(uint32_t flags, int state) +{ + switch (state & MEM_WRITE_MASK) { + case MEM_WRITE_DISABLED: + return 0; + + case MEM_WRITE_ANY: + return 1; + + /* On external and 0 mappings without ROMCS. */ + case MEM_WRITE_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_ROMCS); + + /* On external and 0 mappings with ROMCS. */ + case MEM_WRITE_ROMCS: + return !(flags & MEM_MAPPING_INTERNAL) && (flags & MEM_MAPPING_ROMCS); + + /* On any external mappings. */ + case MEM_WRITE_EXTANY: + return !(flags & MEM_MAPPING_INTERNAL); + + case MEM_WRITE_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + + default: + fatal("mem_mapping_write_allowed : bad state %x\n", state); + } + + return 0; +} + + +static void +mem_mapping_recalc(uint64_t base, uint64_t size) +{ + mem_mapping_t *map = base_mapping.next; + uint64_t c; + + if (! size) return; + + /* Clear out old mappings. */ + for (c = base; c < base + size; c += MEM_GRANULARITY_SIZE) { + read_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + write_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; + } + + /* Walk mapping list. */ + while (map != NULL) { + /*In range?*/ + if (map->enable && (uint64_t)map->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)map->base + (uint64_t)map->size) > (uint64_t)base) { + uint64_t start = (map->base < base) ? map->base : base; + uint64_t end = (((uint64_t)map->base + (uint64_t)map->size) < (base + size)) ? ((uint64_t)map->base + (uint64_t)map->size) : (base + size); + if (start < map->base) + start = map->base; + + for (c = start; c < end; c += MEM_GRANULARITY_SIZE) { + if ((map->read_b || map->read_w || map->read_l) && + mem_mapping_read_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS])) { + read_mapping[c >> MEM_GRANULARITY_BITS] = map; + if (map->exec) + _mem_exec[c >> MEM_GRANULARITY_BITS] = map->exec + (c - map->base); + else + _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; + } + if ((map->write_b || map->write_w || map->write_l) && + mem_mapping_write_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS])) + write_mapping[c >> MEM_GRANULARITY_BITS] = map; + } + } + map = map->next; + } + + flushmmucache_cr3(); +} + + +void +mem_mapping_del(mem_mapping_t *map) +{ + mem_mapping_t *ptr; + + /* Disable the entry. */ + mem_mapping_disable(map); + + /* Zap it from the list. */ + for (ptr = &base_mapping; ptr->next != NULL; ptr = ptr->next) { + if (ptr->next == map) { + ptr->next = map->next; + break; + } + } +} + + +void +mem_mapping_add(mem_mapping_t *map, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t fl, + void *p) +{ + mem_mapping_t *dest = &base_mapping; + + /* Add mapping to the end of the list.*/ + while (dest->next) + dest = dest->next; + dest->next = map; + map->prev = dest; + + if (size) + map->enable = 1; + else + map->enable = 0; + map->base = base; + map->size = size; + map->read_b = read_b; + map->read_w = read_w; + map->read_l = read_l; + map->write_b = write_b; + map->write_w = write_w; + map->write_l = write_l; + map->exec = exec; + map->flags = fl; + map->p = p; + map->dev = NULL; + map->next = NULL; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_set_handler(mem_mapping_t *map, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)) +{ + map->read_b = read_b; + map->read_w = read_w; + map->read_l = read_l; + map->write_b = write_b; + map->write_w = write_w; + map->write_l = write_l; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_set_addr(mem_mapping_t *map, uint32_t base, uint32_t size) +{ + /* Remove old mapping. */ + map->enable = 0; + mem_mapping_recalc(map->base, map->size); + + /* Set new mapping. */ + map->enable = 1; + map->base = base; + map->size = size; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_set_exec(mem_mapping_t *map, uint8_t *exec) +{ + map->exec = exec; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_set_p(mem_mapping_t *map, void *p) +{ + map->p = p; +} + + +void +mem_mapping_set_dev(mem_mapping_t *map, void *p) +{ + map->dev = p; +} + + +void +mem_mapping_disable(mem_mapping_t *map) +{ + map->enable = 0; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_enable(mem_mapping_t *map) +{ + map->enable = 1; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_set_mem_state(uint32_t base, uint32_t size, int state) +{ + uint32_t c; + + for (c = 0; c < size; c += MEM_GRANULARITY_SIZE) + _mem_state[(c + base) >> MEM_GRANULARITY_BITS] = state; + + mem_mapping_recalc(base, size); +} + + +void +mem_add_bios(void) +{ + if (biosmask > 0x1ffff) { + /* 256k+ BIOS'es only have low mappings at E0000-FFFFF. */ + mem_mapping_add(&bios_mapping, 0xe0000, 0x20000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + &rom[0x20000], MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); + + mem_set_mem_state(0x0e0000, 0x20000, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); + } else { + mem_mapping_add(&bios_mapping, biosaddr, biosmask + 1, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); + + mem_set_mem_state(biosaddr, biosmask + 1, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); + } + + if (AT) { + mem_mapping_add(&bios_high_mapping, biosaddr | (cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, 0); + + mem_set_mem_state(biosaddr | (cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, + MEM_READ_ROMCS | MEM_WRITE_ROMCS); + } +} + + +void +mem_a20_init(void) +{ + if (AT) { + rammask = cpu_16bitbus ? 0xefffff : 0xffefffff; + flushmmucache(); + mem_a20_state = mem_a20_key | mem_a20_alt; + } else { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + } +} + + +/* Reset the memory state. */ +void +mem_reset(void) +{ + uint32_t c, m; + + m = 1024UL * mem_size; + if (ram != NULL) { + free(ram); + ram = NULL; + } + ram = (uint8_t *)malloc(m); /* allocate and clear the RAM block */ + memset(ram, 0x00, m); + + /* + * Allocate the page table based on how much RAM we have. + * We re-allocate the table on each (hard) reset, as the + * memory amount could have changed. + */ + if (AT) { + if (cpu_16bitbus) { + /* 80186/286; maximum address space is 16MB. */ + m = 4096; + } else { + /* 80386+; maximum address space is 4GB. */ + m = (mem_size + 384) >> 2; + if ((m << 2) < (mem_size + 384)) + m++; + if (m < 4096) + m = 4096; + } + } else { + /* 8088/86; maximum address space is 1MB. */ + m = 256; + } + + /* + * Allocate and initialize the (new) page table. + * We only do this if the size of the page table has changed. + */ +#if DYNAMIC_TABLES +mem_log("MEM: reset: previous pages=%08lx, pages_sz=%i\n", pages, pages_sz); +#endif + if (pages_sz != m) { + pages_sz = m; + if (pages) { + free(pages); + pages = NULL; + } + pages = (page_t *)malloc(m*sizeof(page_t)); +#if DYNAMIC_TABLES +mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); +#endif + +#if DYNAMIC_TABLES + /* Allocate the (new) lookup tables. */ + if (page_lookup != NULL) free(page_lookup); + page_lookup = (page_t **)malloc(pages_sz*sizeof(page_t *)); + + if (readlookup2 != NULL) free(readlookup2); + readlookup2 = malloc(pages_sz*sizeof(uintptr_t)); + + if (writelookup2 != NULL) free(writelookup2); + writelookup2 = malloc(pages_sz*sizeof(uintptr_t)); + +#endif + } + +#if DYNAMIC_TABLES + memset(page_lookup, 0x00, pages_sz * sizeof(page_t *)); +#else + memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *)); +#endif + + memset(pages, 0x00, pages_sz*sizeof(page_t)); + + + if (byte_dirty_mask) { + free(byte_dirty_mask); + byte_dirty_mask = NULL; + } + byte_dirty_mask = malloc((mem_size * 1024) / 8); + memset(byte_dirty_mask, 0, (mem_size * 1024) / 8); + + if (byte_code_present_mask) { + free(byte_code_present_mask); + byte_code_present_mask = NULL; + } + byte_code_present_mask = malloc((mem_size * 1024) / 8); + memset(byte_code_present_mask, 0, (mem_size * 1024) / 8); + + for (c = 0; c < pages_sz; 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; + 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_exec, 0x00, sizeof(_mem_exec)); + + memset(&base_mapping, 0x00, sizeof(base_mapping)); + + memset(_mem_state, 0x00, 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_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) { + 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) + 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(&ram_remapped_mapping, mem_size * 1024, 256 * 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); + mem_mapping_disable(&ram_remapped_mapping); + + mem_a20_init(); +} + + +void +mem_init(void) +{ + /* Perform a one-time init. */ + ram = rom = NULL; + pages = NULL; +#if DYNAMIC_TABLES + page_lookup = NULL; + readlookup2 = NULL; + writelookup2 = NULL; + +#else + /* Allocate the lookup tables. */ + page_lookup = (page_t **)malloc((1<<20)*sizeof(page_t *)); + + readlookup2 = malloc((1<<20)*sizeof(uintptr_t)); + + writelookup2 = malloc((1<<20)*sizeof(uintptr_t)); +#endif + +#if FIXME + memset(ff_array, 0xff, sizeof(ff_array)); +#endif + + /* Reset the memory state. */ + mem_reset(); +} + + +void +mem_remap_top(int kb) +{ + int c; + uint32_t start = (mem_size >= 1024) ? mem_size : 1024; + int offset, size = mem_size - 640; + + mem_log("MEM: remapping top %iKB (mem=%i)\n", kb, mem_size); + if (mem_size <= 640) return; + + if (kb == 0) { + /* Called to disable the mapping. */ + mem_mapping_disable(&ram_remapped_mapping); + + return; + } + + if (size > kb) + size = kb; + + for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++) { + 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_set_addr(&ram_remapped_mapping, start * 1024, size * 1024); + mem_mapping_set_exec(&ram_remapped_mapping, ram + (start * 1024)); + + flushmmucache(); +} + +void +mem_reset_page_blocks(void) +{ + uint32_t c; + + if (pages == NULL) return; + + for (c = 0; c < pages_sz; c++) { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + pages[c].block = BLOCK_INVALID; + pages[c].block_2 = BLOCK_INVALID; + } +} + + +void +mem_a20_recalc(void) +{ + int state; + + if (! AT) { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + + return; + } + + state = mem_a20_key | mem_a20_alt; + if (state && !mem_a20_state) { + rammask = (AT && cpu_16bitbus) ? 0xffffff : 0xffffffff; + flushmmucache(); + } else if (!state && mem_a20_state) { + rammask = (AT && cpu_16bitbus) ? 0xefffff : 0xffefffff; + flushmmucache(); + } + + mem_a20_state = state; +} diff --git a/src/memregs.c b/src/memregs.c deleted file mode 100644 index f1aae4ac8..000000000 --- a/src/memregs.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Emulation of the memory I/O scratch registers on ports 0xE1 - * and 0xE2, used by just about any emulated machine. - * - * Version: @(#)memregs.c 1.0.6 2018/04/29 - * - * Author: Miran Grca, - * - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "86box.h" -#include "io.h" -#include "memregs.h" - - -static uint8_t mem_regs[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - -static uint8_t mem_reg_ffff = 0; - - -void memregs_write(uint16_t port, uint8_t val, void *priv) -{ - if (port == 0xffff) - { - mem_reg_ffff = 0; - } - - mem_regs[port & 0xf] = val; -} - -uint8_t memregs_read(uint16_t port, void *priv) -{ - if (port == 0xffff) - { - return mem_reg_ffff; - } - - return mem_regs[port & 0xf]; -} - -void memregs_init(void) -{ - io_sethandler(0x00e1, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); -} - -void powermate_memregs_init(void) -{ - io_sethandler(0x00ed, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); - io_sethandler(0xffff, 0x0001, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); -} diff --git a/src/mouse.c b/src/mouse.c index 64364b81e..bd01892f7 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -11,7 +11,7 @@ * TODO: Add the Genius bus- and serial mouse. * Remove the '3-button' flag from mouse types. * - * Version: @(#)mouse.c 1.0.27 2018/04/29 + * Version: @(#)mouse.c 1.0.29 2018/11/04 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -69,6 +69,7 @@ static mouse_t mouse_devices[] = { #endif { "mssystems", &mouse_mssystems_device }, { "msserial", &mouse_msserial_device }, + { "ltserial", &mouse_ltserial_device }, { "ps2", &mouse_ps2_device }, { NULL, NULL } }; @@ -82,22 +83,22 @@ static int (*mouse_dev_poll)(); #ifdef ENABLE_MOUSE_LOG int mouse_do_log = ENABLE_MOUSE_LOG; -#endif static void -mouse_log(const char *format, ...) +mouse_log(const char *fmt, ...) { -#ifdef ENABLE_MOUSE_LOG va_list ap; if (mouse_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define mouse_log(fmt, ...) +#endif /* Initialize the mouse module. */ @@ -131,7 +132,7 @@ mouse_close(void) void mouse_reset(void) { - if ((mouse_curr != NULL) || (mouse_type == MOUSE_TYPE_INTERNAL)) + if (mouse_curr != NULL) return; /* Mouse already initialized. */ mouse_log("MOUSE: reset(type=%d, '%s')\n", @@ -164,7 +165,7 @@ mouse_process(void) { static int poll_delay = 2; - if ((mouse_curr == NULL) || (mouse_type == MOUSE_TYPE_INTERNAL)) + if (mouse_curr == NULL) return; if (--poll_delay) return; diff --git a/src/mouse.h b/src/mouse.h index 341646178..a743a0676 100644 --- a/src/mouse.h +++ b/src/mouse.h @@ -8,13 +8,13 @@ * * Definitions for the mouse driver. * - * Version: @(#)mouse.h 1.0.15 2018/03/18 + * Version: @(#)mouse.h 1.0.15 2019/09/27 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_MOUSE_H # define EMU_MOUSE_H @@ -28,10 +28,14 @@ # define MOUSE_TYPE_GENIBUS 4 /* Genius Bus Mouse */ #endif #define MOUSE_TYPE_MSYSTEMS 5 /* Mouse Systems mouse */ -#define MOUSE_TYPE_MICROSOFT 6 /* Microsoft Serial Mouse */ -#define MOUSE_TYPE_LOGITECH 7 /* Logitech Serial Mouse */ -#define MOUSE_TYPE_MSWHEEL 8 /* Serial Wheel Mouse */ -#define MOUSE_TYPE_PS2 9 /* PS/2 series Bus Mouse */ +#define MOUSE_TYPE_MICROSOFT 6 /* Microsoft 2-button Serial Mouse */ +#define MOUSE_TYPE_MS3BUTTON 7 /* Microsoft 3-button Serial Mouse */ +#define MOUSE_TYPE_MSWHEEL 8 /* Microsoft Serial Wheel Mouse */ +#define MOUSE_TYPE_LOGITECH 9 /* Logitech 2-button Serial Mouse */ +#define MOUSE_TYPE_LT3BUTTON 10 /* Logitech 3-button Serial Mouse */ +#define MOUSE_TYPE_PS2 11 /* PS/2 series Bus Mouse */ + +#define MOUSE_TYPE_ONBOARD 0x80 /* Mouse is an on-board version of one of the above. */ #ifdef __cplusplus @@ -48,12 +52,14 @@ extern const device_t *mouse_get_device(int mouse); extern void *mouse_ps2_init(const device_t *); extern const device_t mouse_logibus_device; +extern const device_t mouse_logibus_onboard_device; extern const device_t mouse_msinport_device; #if 0 extern const device_t mouse_genibus_device; #endif extern const device_t mouse_mssystems_device; extern const device_t mouse_msserial_device; +extern const device_t mouse_ltserial_device; extern const device_t mouse_ps2_device; #endif @@ -65,6 +71,9 @@ extern void mouse_process(void); extern void mouse_set_poll(int (*f)(int,int,int,int,void *), void *); extern void mouse_poll(void); +extern void mouse_bus_set_irq(void *priv, int irq); + + extern char *mouse_get_name(int mouse); extern char *mouse_get_internal_name(int mouse); extern int mouse_get_from_internal_name(char *s); diff --git a/src/mouse_bus.c b/src/mouse_bus.c index e60a7063b..36b039d28 100644 --- a/src/mouse_bus.c +++ b/src/mouse_bus.c @@ -18,6 +18,7 @@ * of the real hardware, testing of drivers, and the old code. * * Logitech Bus Mouse verified with: + * Linux Slackware 3.0 * Logitech LMouse.com 3.12 * Logitech LMouse.com 3.30 * Logitech LMouse.com 3.41 @@ -40,25 +41,30 @@ * Logitech Mouse.exe 6.50 * Microsoft Mouse.com 2.00 * Microsoft Mouse.sys 3.00 + * Microsoft Mouse.com 7.04 + * Microsoft Mouse.com 8.21J * Microsoft Windows 1.00 DR5 * Microsoft Windows 3.10.026 + * Microsoft Windows 3.10.068 both MOUSE.DRV and LMOUSE.DRV * Microsoft Windows NT 3.1 * Microsoft Windows 95 * * InPort verified with: + * Linux Slackware 3.0 * Logitech LMouse.com 6.12 * Logitech LMouse.com 6.41 + * Microsoft Windows 3.10.068 both MOUSE.DRV and LMOUSE.DRV * Microsoft Windows NT 3.1 * Microsoft Windows 98 SE * - * Version: @(#)mouse_bus.c 1.0.0 2018/05/23 + * Version: @(#)mouse_bus.c 1.0.4 2019/09/27 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 200?-2018 Bochs. - * Copyright 2017,2018 Miran Grca. - * Copyright 1989-2018 Fred N. van Kempen. + * Copyright 200?-2019 Bochs. + * Copyright 2017-2019 Miran Grca. + * Copyright 1989-2019 Fred N. van Kempen. */ #include #include @@ -69,7 +75,6 @@ #include #define HAVE_STDARG_H #include "86box.h" -#include "config.h" #include "io.h" #include "pic.h" #include "timer.h" @@ -123,44 +128,45 @@ #define FLAG_TIMER_INT (1 << 3) #define FLAG_DATA_INT (1 << 4) -static const double periods[4] = { 30.0, 50.0, 100.0, 200.0 }; +static const uint8_t periods[4] = { 30, 50, 100, 200 }; /* Our mouse device. */ typedef struct mouse { + uint8_t current_b, control_val, + config_val, sig_val, + command_val, pad; + + int8_t current_x, current_y; + int base, irq, bn, flags, mouse_delayed_dx, mouse_delayed_dy, - mouse_buttons, - current_x, current_y, - current_b, - control_val, mouse_buttons_last, - config_val, sig_val, - command_val, toggle_counter; + mouse_buttons, mouse_buttons_last, + toggle_counter, timer_enabled; double period; - - int64_t timer_enabled, timer; /* mouse event timer */ + pc_timer_t timer; /* mouse event timer */ } mouse_t; #ifdef ENABLE_MOUSE_BUS_LOG int bm_do_log = ENABLE_MOUSE_BUS_LOG; -#endif static void -bm_log(const char *format, ...) +bm_log(const char *fmt, ...) { -#ifdef ENABLE_MOUSE_BUS_LOG va_list ap; if (bm_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define bm_log(fmt, ...) +#endif /* Handle a READ operation from one of our registers. */ @@ -177,15 +183,19 @@ lt_read(uint16_t port, void *priv) switch (dev->control_val & 0x60) { case READ_X_LOW: value = dev->current_x & 0x0F; + dev->current_x &= ~0x0F; break; case READ_X_HIGH: value = (dev->current_x >> 4) & 0x0F; + dev->current_x &= ~0xF0; break; case READ_Y_LOW: value = dev->current_y & 0x0F; + dev->current_y &= ~0x0F; break; case READ_Y_HIGH: value = (dev->current_y >> 4) & 0x0F; + dev->current_y &= ~0xF0; break; default: bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); @@ -198,7 +208,6 @@ lt_read(uint16_t port, void *priv) case BUSM_PORT_CONTROL: value = dev->control_val; dev->control_val |= 0x0F; - /* If the conditions are right, simulate the flakiness of the correct IRQ bit. */ if (dev->flags & FLAG_TIMER_INT) dev->control_val = (dev->control_val & ~IRQ_MASK) | (random_generate() & IRQ_MASK); @@ -232,13 +241,15 @@ ms_read(uint16_t port, void *priv) case INP_PORT_DATA: switch (dev->command_val) { case INP_CTRL_READ_BUTTONS: - value = dev->current_b | 0x80; + value = dev->current_b; break; case INP_CTRL_READ_X: value = dev->current_x; + dev->current_x = 0; break; case INP_CTRL_READ_Y: value = dev->current_y; + dev->current_y = 0; break; case INP_CTRL_COMMAND: value = dev->control_val; @@ -270,6 +281,7 @@ static void lt_write(uint16_t port, uint8_t val, void *priv) { mouse_t *dev = (mouse_t *)priv; + uint8_t bit; bm_log("DEBUG: write to address 0x%04x, value = 0x%02x\n", port, val); @@ -293,7 +305,8 @@ lt_write(uint16_t port, uint8_t val, void *priv) else dev->flags &= ~FLAG_HOLD; - picintc(1 << dev->irq); + if (dev->irq != -1) + picintc(1 << dev->irq); break; case BUSM_PORT_CONFIG: @@ -307,6 +320,8 @@ lt_write(uint16_t port, uint8_t val, void *priv) * explains the value: * * D7 = Mode set flag (1 = active) + * This indicates the mode of operation of D7: + * 1 = Mode set, 0 = Bit set/reset * D6,D5 = Mode selection (port A) * 00 = Mode 0 = Basic I/O * 01 = Mode 1 = Strobed I/O @@ -323,17 +338,27 @@ lt_write(uint16_t port, uint8_t val, void *priv) * port, B is an output port, C is split with upper 4 bits * being an output port and lower 4 bits an input port, and * enable the sucker. Courtesy Intel 8255 databook. Lars + * + * 1001 1011 9B 1111 Default state + * 1001 0001 91 1001 Driver-initialized state + * The only difference is - port C upper and port B go from + * input to output. */ - dev->config_val = val; if (val & DEVICE_ACTIVE) { - dev->flags |= (FLAG_ENABLED | FLAG_TIMER_INT); + /* Mode set/reset - enable this */ + dev->config_val = val; + if (dev->timer_enabled) + dev->flags |= (FLAG_ENABLED | FLAG_TIMER_INT); + else + dev->flags |= FLAG_ENABLED; dev->control_val = 0x0F & ~IRQ_MASK; - dev->timer = ((int64_t) dev->period) * TIMER_USEC; - dev->timer_enabled = 1LL; } else { - dev->flags &= ~(FLAG_ENABLED | FLAG_TIMER_INT); - dev->timer = 0LL; - dev->timer_enabled = 0LL; + /* Single bit set/reset */ + bit = 1 << ((val >> 1) & 0x07); /* Bits 3-1 specify the target bit */ + if (val & 1) + dev->control_val |= bit; /* Set */ + else + dev->control_val &= ~bit; /* Reset */ } break; } @@ -367,7 +392,8 @@ ms_write(uint16_t port, uint8_t val, void *priv) } break; case INP_PORT_DATA: - picintc(1 << dev->irq); + if (dev->irq != -1) + picintc(1 << dev->irq); switch(dev->command_val) { case INP_CTRL_COMMAND: if (val & INP_HOLD_COUNTER) @@ -388,22 +414,24 @@ ms_write(uint16_t port, uint8_t val, void *priv) switch(val & INP_PERIOD_MASK) { case 0: dev->period = 0.0; - dev->timer = 0LL; - dev->timer_enabled = 0LL; + timer_disable(&dev->timer); + dev->timer_enabled = 0; break; case 1: case 2: case 3: case 4: - dev->period = 1000000.0 / periods[(val & INP_PERIOD_MASK) - 1]; - dev->timer = ((int64_t) dev->period) * TIMER_USEC; - dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? 1LL : 0LL; + dev->period = (1000000.0 / (double)periods[(val & INP_PERIOD_MASK) - 1]); + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? 1 : 0; + timer_disable(&dev->timer); + if (dev->timer_enabled) + timer_set_delay_u64(&dev->timer, (uint64_t) (dev->period * (double)TIMER_USEC)); bm_log("DEBUG: Timer is now %sabled at period %i\n", (val & INP_ENABLE_TIMER_IRQ) ? "en" : "dis", (int32_t) dev->period); break; case 6: - if (val & INP_ENABLE_TIMER_IRQ) + if ((val & INP_ENABLE_TIMER_IRQ) && (dev->irq != -1)) picint(1 << dev->irq); dev->control_val &= INP_PERIOD_MASK; dev->control_val |= (val & ~INP_PERIOD_MASK); @@ -483,7 +511,7 @@ bm_poll(int x, int y, int z, int b, void *priv) } /* Send interrupt. */ - if (dev->flags & FLAG_DATA_INT) { + if ((dev->flags & FLAG_DATA_INT) && (dev->irq != -1)) { picint(1 << dev->irq); bm_log("DEBUG: Data Interrupt Fired...\n"); } @@ -500,34 +528,35 @@ bm_update_data(mouse_t *dev) int delta_x, delta_y; int xor; - /* Update the deltas and the delays. */ - if (dev->mouse_delayed_dx > 127) { - delta_x = 127; - dev->mouse_delayed_dx -= 127; - } else if (dev->mouse_delayed_dx < -128) { - delta_x = -128; - dev->mouse_delayed_dx += 128; - } else { - delta_x = dev->mouse_delayed_dx; - dev->mouse_delayed_dx = 0; - } - - if (dev->mouse_delayed_dy > 127) { - delta_y = 127; - dev->mouse_delayed_dy -= 127; - } else if (dev->mouse_delayed_dy < -128) { - delta_y = -128; - dev->mouse_delayed_dy += 128; - } else { - delta_y = dev->mouse_delayed_dy; - dev->mouse_delayed_dy = 0; - } - /* If the counters are not frozen, update them. */ if (!(dev->flags & FLAG_HOLD)) { - dev->current_x = (uint8_t) delta_x; - dev->current_y = (uint8_t) delta_y; - } + /* Update the deltas and the delays. */ + if (dev->mouse_delayed_dx > 127) { + delta_x = 127; + dev->mouse_delayed_dx -= 127; + } else if (dev->mouse_delayed_dx < -128) { + delta_x = -128; + dev->mouse_delayed_dx += 128; + } else { + delta_x = dev->mouse_delayed_dx; + dev->mouse_delayed_dx = 0; + } + + if (dev->mouse_delayed_dy > 127) { + delta_y = 127; + dev->mouse_delayed_dy -= 127; + } else if (dev->mouse_delayed_dy < -128) { + delta_y = -128; + dev->mouse_delayed_dy += 128; + } else { + delta_y = dev->mouse_delayed_dy; + dev->mouse_delayed_dy = 0; + } + + dev->current_x = (int8_t) delta_x; + dev->current_y = (int8_t) delta_y; + } else + delta_x = delta_y = 0; if (dev->flags & FLAG_INPORT) { /* This is an InPort mouse in timer mode, so update current_b always, @@ -554,9 +583,9 @@ bm_timer(void *priv) /* The period is configured either via emulator settings (for MS/Logitech Bus mouse) or via software (for InPort mouse). */ - dev->timer += ((int64_t) dev->period) * TIMER_USEC; + timer_advance_u64(&dev->timer, (uint64_t) (dev->period * (double)TIMER_USEC)); - if (dev->flags & FLAG_TIMER_INT) { + if ((dev->flags & FLAG_TIMER_INT) && (dev->irq != -1)) { picint(1 << dev->irq); bm_log("DEBUG: Timer Interrupt Fired...\n"); } @@ -576,23 +605,40 @@ bm_close(void *priv) } +/* Set the mouse's IRQ. */ +void +mouse_bus_set_irq(void *priv, int irq) +{ + mouse_t *dev = (mouse_t *)priv; + + dev->irq = irq; +} + + /* Initialize the device for use by the user. */ static void * bm_init(const device_t *info) { mouse_t *dev; + int hz; dev = (mouse_t *)malloc(sizeof(mouse_t)); memset(dev, 0x00, sizeof(mouse_t)); - if (info->local == MOUSE_TYPE_INPORT) + if ((info->local & ~MOUSE_TYPE_ONBOARD) == MOUSE_TYPE_INPORT) dev->flags = FLAG_INPORT; else dev->flags = 0; - dev->base = device_get_config_hex16("base"); - dev->irq = device_get_config_int("irq"); - dev->bn = device_get_config_int("buttons"); + if (info->local & MOUSE_TYPE_ONBOARD) { + dev->base = 0x023c; + dev->irq = -1; + dev->bn = 2; + } else { + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bn = device_get_config_int("buttons"); + } mouse_set_buttons(dev->bn); dev->mouse_delayed_dx = 0; @@ -601,32 +647,44 @@ bm_init(const device_t *info) dev->mouse_buttons_last = 0; dev->sig_val = 0; /* the signature port value */ dev->current_x = - dev->current_y = + dev->current_y = 0; dev->current_b = 0; dev->command_val = 0; /* command byte */ dev->toggle_counter = 0; /* signature byte / IRQ bit toggle */ + dev->period = 0.0; + + timer_add(&dev->timer, bm_timer, dev, 0); if (dev->flags & FLAG_INPORT) { dev->control_val = 0; /* the control port value */ dev->flags |= FLAG_ENABLED; - dev->period = 0.0; io_sethandler(dev->base, 4, ms_read, NULL, NULL, ms_write, NULL, NULL, dev); + + dev->timer_enabled = 0; } else { dev->control_val = 0x0f; /* the control port value */ - dev->config_val = 0x0e; /* the config port value */ - dev->period = 1000000.0 / ((double) device_get_config_int("hz")); + dev->config_val = 0x9b; /* the config port value - 0x9b is the + default state of the 8255: all ports + are set to input */ + + hz = device_get_config_int("hz"); + if (hz > 0) + dev->period = (1000000.0 / (double)hz); io_sethandler(dev->base, 4, lt_read, NULL, NULL, lt_write, NULL, NULL, dev); + + if (hz > 0) { + timer_set_delay_u64(&dev->timer, (uint64_t) (dev->period * (double)TIMER_USEC)); + dev->timer_enabled = 1; + } else { + dev->flags |= FLAG_DATA_INT; + dev->timer_enabled = 0; + } } - dev->timer = 0LL; - dev->timer_enabled = 0LL; - - timer_add(bm_timer, &dev->timer, &dev->timer_enabled, dev); - if (dev->flags & FLAG_INPORT) bm_log("MS Inport BusMouse initialized\n"); else @@ -678,6 +736,9 @@ static const device_config_t lt_config[] = { }, { "hz", "Hz", CONFIG_SELECTION, "", 45, { + { + "Non-timed (original)", 0 + }, { "30 Hz (JMP2 = 1)", 30 }, @@ -779,6 +840,14 @@ const device_t mouse_logibus_device = { lt_config }; +const device_t mouse_logibus_onboard_device = { + "Logitech Bus Mouse (On-Board)", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS | MOUSE_TYPE_ONBOARD, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL +}; + const device_t mouse_msinport_device = { "Microsoft Bus Mouse (InPort)", DEVICE_ISA, diff --git a/src/mouse_ps2.c b/src/mouse_ps2.c index 16ec68b5e..cb7653664 100644 --- a/src/mouse_ps2.c +++ b/src/mouse_ps2.c @@ -8,7 +8,7 @@ * * Implementation of PS/2 series Mouse devices. * - * Version: @(#)mouse_ps2.c 1.0.9 2018/05/12 + * Version: @(#)mouse_ps2.c 1.0.12 2018/10/17 * * Authors: Fred N. van Kempen, */ @@ -20,7 +20,6 @@ #include #define HAVE_STDARG_H #include "86box.h" -#include "config.h" #include "device.h" #include "keyboard.h" #include "mouse.h" @@ -61,22 +60,22 @@ int mouse_scan = 0; #ifdef ENABLE_MOUSE_PS2_LOG int mouse_ps2_do_log = ENABLE_MOUSE_PS2_LOG; -#endif static void -mouse_ps2_log(const char *format, ...) +mouse_ps2_log(const char *fmt, ...) { -#ifdef ENABLE_MOUSE_PS2_LOG va_list ap; if (mouse_ps2_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define mouse_ps2_log(fmt, ...) +#endif void @@ -132,7 +131,7 @@ ps2_write(uint8_t val, void *priv) case 0xe9: /* status request */ keyboard_at_adddata_mouse(0xfa); - temp = (dev->flags & 0x3f); + temp = (dev->flags & 0x30); if (mouse_buttons & 0x01) temp |= 0x01; if (mouse_buttons & 0x02) @@ -169,7 +168,7 @@ ps2_write(uint8_t val, void *priv) case 0xff: /* reset */ dev->mode = MODE_STREAM; - dev->flags &= 0x80; + dev->flags &= 0x88; keyboard_at_adddata_mouse(0xfa); keyboard_at_adddata_mouse(0xaa); keyboard_at_adddata_mouse(0x00); @@ -181,8 +180,9 @@ ps2_write(uint8_t val, void *priv) } if (dev->flags & FLAG_INTELLI) { - for (temp=0; temp<5; temp++) - dev->last_data[temp] = dev->last_data[temp+1]; + for (temp = 0; temp < 5; temp++) + dev->last_data[temp] = dev->last_data[temp + 1]; + dev->last_data[5] = val; if (dev->last_data[0] == 0xf3 && dev->last_data[1] == 0xc8 && @@ -197,19 +197,24 @@ static int ps2_poll(int x, int y, int z, int b, void *priv) { mouse_t *dev = (mouse_t *)priv; - uint8_t buff[3]; + uint8_t buff[3] = { 0x08, 0x00, 0x00 }; - if (!x && !y && !z && b == dev->b) return(0xff); + if (!x && !y && !z && (b == dev->b)) + return(0xff); - if (! (dev->flags & FLAG_ENABLED)) return(0xff); +#if 0 + if (!(dev->flags & FLAG_ENABLED)) + return(0xff); +#endif - if (! mouse_scan) return(0xff); + if (!mouse_scan) + return(0xff); dev->x += x; dev->y -= y; dev->z -= z; - if ((dev->mode == MODE_STREAM) && - ((mouse_queue_end-mouse_queue_start) & 0x0f) < 13) { + if ((dev->mode == MODE_STREAM) && (dev->flags & FLAG_ENABLED) && + (((mouse_queue_end - mouse_queue_start) & 0x0f) < 13)) { dev->b = b; if (dev->x > 255) dev->x = 255; @@ -219,8 +224,6 @@ ps2_poll(int x, int y, int z, int b, void *priv) if (dev->z < -8) dev->z = -8; if (dev->z > 7) dev->z = 7; - memset(buff, 0x00, sizeof(buff)); - buff[0] = 0x08; if (dev->x < 0) buff[0] |= 0x10; if (dev->y < 0) @@ -239,7 +242,7 @@ ps2_poll(int x, int y, int z, int b, void *priv) keyboard_at_adddata_mouse(buff[0]); keyboard_at_adddata_mouse(buff[1]); keyboard_at_adddata_mouse(buff[2]); - if (dev->flags & FLAG_INTELLI) + if (dev->flags & FLAG_INTMODE) keyboard_at_adddata_mouse(dev->z); dev->x = dev->y = dev->z = 0; @@ -273,7 +276,7 @@ mouse_ps2_init(const device_t *info) /* Hook into the general AT Keyboard driver. */ keyboard_at_set_mouse(ps2_write, dev); - mouse_ps2_log("%s: buttons=%d\n", dev->name, (dev->flags & FLAG_INTELLI)? 3 : 2); + mouse_ps2_log("%s: buttons=%d\n", dev->name, (dev->flags & FLAG_INTELLI) ? 3 : 2); /* Tell them how many buttons we have. */ mouse_set_buttons((dev->flags & FLAG_INTELLI) ? 3 : 2); diff --git a/src/mouse_serial.c b/src/mouse_serial.c index cb338a0c5..c96a7598d 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -10,7 +10,7 @@ * * TODO: Add the Genius Serial Mouse. * - * Version: @(#)mouse_serial.c 1.0.23 2018/04/29 + * Version: @(#)mouse_serial.c 1.0.29 2019/10/31 * * Author: Fred N. van Kempen, */ @@ -22,27 +22,53 @@ #include #define HAVE_STDARG_H #include "86box.h" -#include "config.h" #include "device.h" #include "timer.h" #include "serial.h" #include "mouse.h" -#define SERMOUSE_PORT 0 /* attach to Serial0 */ +#define SERMOUSE_PORT 0 /* attach to Serial0 */ + +enum { + PHASE_IDLE, + PHASE_ID, + PHASE_DATA, + PHASE_STATUS, + PHASE_DIAGNOSTIC, + PHASE_FORMAT_AND_REVISION, + PHASE_COPYRIGHT_STRING, + PHASE_BUTTONS +}; + +enum { + REPORT_PHASE_PREPARE, + REPORT_PHASE_TRANSMIT +}; typedef struct { const char *name; /* name of this device */ int8_t type, /* type of this device */ port; - uint8_t flags; /* device flags */ + uint8_t flags, but, /* device flags */ + want_data, + status, format, + prompt, on_change, + id_len, id[255], + data_len, data[5]; + int abs_x, abs_y, + rel_x, rel_y, + rel_z, + oldb, lastb; - int pos; - int64_t delay; - int oldb; + int command_pos, command_phase, + report_pos, report_phase, + command_enabled, report_enabled; + double transmit_period, report_period; + pc_timer_t command_timer, report_timer; - SERIAL *serial; + serial_t *serial; } mouse_t; #define FLAG_INPORT 0x80 /* device is MS InPort */ #define FLAG_3BTN 0x20 /* enable 3-button mode */ @@ -54,73 +80,457 @@ typedef struct { #ifdef ENABLE_MOUSE_SERIAL_LOG int mouse_serial_do_log = ENABLE_MOUSE_SERIAL_LOG; + + +static void +mouse_serial_log(const char *fmt, ...) +{ + va_list ap; + + if (mouse_serial_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define mouse_serial_log(fmt, ...) #endif static void -mouse_serial_log(const char *format, ...) +sermouse_timer_on(mouse_t *dev, double period, int report) { -#ifdef ENABLE_MOUSE_SERIAL_LOG - va_list ap; + pc_timer_t *timer; + int *enabled; - if (mouse_serial_do_log) { - va_start(ap, format); - pclog_ex(format, ap); - va_end(ap); + if (report) { + timer = &dev->report_timer; + enabled = &dev->report_enabled; + } else { + timer = &dev->command_timer; + enabled = &dev->command_enabled; } -#endif + + timer_on_auto(timer, period); + + *enabled = 1; +} + + +static double +sermouse_transmit_period(mouse_t *dev, int bps, int rps) +{ + double dbps = (double) bps; + double temp = 0.0; + int word_len; + + switch (dev->format) { + case 0: + case 1: /* Mouse Systems and Three Byte Packed formats: 8 data, no parity, 2 stop, 1 start */ + word_len = 11; + break; + case 2: /* Hexadecimal format - 8 data, no parity, 1 stop, 1 start - number of stop bits is a guess because + it is not documented anywhere. */ + word_len = 10; + break; + case 3: + case 6: /* Bit Pad One formats: 7 data, even parity, 2 stop, 1 start */ + word_len = 11; + break; + case 5: /* MM Series format: 8 data, odd parity, 1 stop, 1 start */ + word_len = 11; + break; + default: + case 7: /* Microsoft-compatible format: 7 data, no parity, 1 stop, 1 start */ + word_len = 9; + break; + } + + if (rps == -1) + temp = (double) word_len; + else { + temp = (double) rps; + temp = (9600.0 - (temp * 33.0)); + temp /= rps; + } + temp = (1000000.0 / dbps) * temp; + + return temp; } /* Callback from serial driver: RTS was toggled. */ static void -sermouse_callback(struct SERIAL *serial, void *priv) +sermouse_callback(struct serial_s *serial, void *priv) { mouse_t *dev = (mouse_t *)priv; /* Start a timer to wake us up in a little while. */ - dev->pos = -1; - serial_clear_fifo((SERIAL *) serial); - dev->delay = 5000LL * (1LL << TIMER_SHIFT); + dev->command_pos = 0; + dev->command_phase = PHASE_ID; + if (dev->id[0] != 'H') + dev->format = 7; + dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); + timer_stop(&dev->command_timer); + sub_cycles(ISA_CYCLES(8)); +#ifdef USE_NEW_DYNAREC + sermouse_timer_on(dev, 5000.0, 0); +#else + sermouse_timer_on(dev, dev->transmit_period, 0); +#endif +} + + +static uint8_t +sermouse_data_msystems(mouse_t *dev, int x, int y, int b) +{ + dev->data[0] = 0x80; + dev->data[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ + dev->data[0] |= (b & 0x02) ? 0x00 : 0x01; /* middle button */ + dev->data[0] |= (b & 0x04) ? 0x00 : 0x02; /* right button */ + dev->data[1] = x; + dev->data[2] = -y; + dev->data[3] = x; /* same as byte 1 */ + dev->data[4] = -y; /* same as byte 2 */ + + return 5; +} + + +static uint8_t +sermouse_data_3bp(mouse_t *dev, int x, int y, int b) +{ + dev->data[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ + dev->data[0] |= (b & 0x04) ? 0x00 : 0x02; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x00 : 0x01; /* right button */ + dev->data[1] = x; + dev->data[2] = -y; + + return 3; +} + + +static uint8_t +sermouse_data_mmseries(mouse_t *dev, int x, int y, int b) +{ + if (x < -127) + x = -127; + if (y < -127) + y = -127; + + dev->data[0] = 0x80; + if (x >= 0) + dev->data[0] |= 0x10; + if (y < 0) + dev->data[0] |= 0x08; + dev->data[0] |= (b & 0x01) ? 0x04 : 0x00; /* left button */ + dev->data[0] |= (b & 0x04) ? 0x02 : 0x00; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x01 : 0x00; /* right button */ + dev->data[1] = abs(x); + dev->data[2] = abs(y); + + return 3; +} + + +static uint8_t +sermouse_data_bp1(mouse_t *dev, int x, int y, int b) +{ + dev->data[0] = 0x80; + dev->data[0] |= (b & 0x01) ? 0x10 : 0x00; /* left button */ + dev->data[0] |= (b & 0x04) ? 0x08 : 0x00; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x04 : 0x00; /* right button */ + dev->data[1] = (x & 0x3f); + dev->data[2] = (x >> 6); + dev->data[3] = (y & 0x3f); + dev->data[4] = (y >> 6); + + return 5; +} + + +static uint8_t +sermouse_data_ms(mouse_t *dev, int x, int y, int z, int b) +{ + uint8_t len; + + dev->data[0] = 0x40; + dev->data[0] |= (((y >> 6) & 0x03) << 2); + dev->data[0] |= ((x >> 6) & 0x03); + if (b & 0x01) + dev->data[0] |= 0x20; + if (b & 0x02) + dev->data[0] |= 0x10; + dev->data[1] = x & 0x3F; + dev->data[2] = y & 0x3F; + if (dev->but == 3) { + len = 3; + if (dev->type == MOUSE_TYPE_LT3BUTTON) { + if (b & 0x04) { + dev->data[3] = 0x20; + len++; + } + } else { + if ((b ^ dev->oldb) & 0x04) { + /* Microsoft 3-button mice send a fourth byte of 0x00 when the middle button + has changed. */ + dev->data[3] = 0x00; + len++; + } + } + } else if (dev->but == 4) { + len = 4; + dev->data[3] = z & 0x0F; + if (b & 0x04) + dev->data[3] |= 0x10; + } else + len = 3; + + return len; +} + + +static uint8_t +sermouse_data_hex(mouse_t *dev, int x, int y, int b) +{ + char ret[6] = { 0, 0, 0, 0, 0, 0 }; + uint8_t i, but = 0x00; + + but |= (b & 0x01) ? 0x04 : 0x00; /* left button */ + but |= (b & 0x04) ? 0x02 : 0x00; /* middle button */ + but |= (b & 0x02) ? 0x01 : 0x00; /* right button */ + + sprintf(ret, "%02X%02X%01X", (int8_t) y, (int8_t) x, but & 0x0f); + + for (i = 0; i < 5; i++) + dev->data[i] = ret[4 - i]; + + return 5; +} + + +static void +sermouse_report(int x, int y, int z, int b, mouse_t *dev) +{ + int len = 0; + + memset(dev->data, 0, 5); + + /* If the mouse is 2-button, ignore the middle button. */ + if (dev->but == 2) + b &= ~0x04; + + switch (dev->format) { + case 0: + len = sermouse_data_msystems(dev, x, y, b); + break; + case 1: + len = sermouse_data_3bp(dev, x, y, b); + break; + case 2: + len = sermouse_data_hex(dev, x, y, b); + break; + case 3: /* Relative */ + len = sermouse_data_bp1(dev, x, y, b); + break; + case 5: + len = sermouse_data_mmseries(dev, x, y, b); + break; + case 6: /* Absolute */ + len = sermouse_data_bp1(dev, dev->abs_x, dev->abs_y, b); + break; + case 7: + len = sermouse_data_ms(dev, x, y, z, b); + break; + } + + dev->data_len = len; +} + + +static void +sermouse_command_phase_idle(mouse_t *dev) +{ + dev->command_pos = 0; + dev->command_phase = PHASE_IDLE; + dev->command_enabled = 0; +} + + +static void +sermouse_command_pos_check(mouse_t *dev, int len) +{ + if (++dev->command_pos == len) + sermouse_command_phase_idle(dev); + else + timer_on_auto(&dev->command_timer, dev->transmit_period); +} + + +static uint8_t +sermouse_last_button_status(mouse_t *dev) +{ + uint8_t ret = 0x00; + + if (dev->oldb & 0x01) + ret |= 0x04; + if (dev->oldb & 0x02) + ret |= 0x02; + if (dev->oldb & 0x04) + ret |= 0x01; + + return ret; +} + + +static void +sermouse_update_delta(mouse_t *dev, int *local, int *global) +{ + int min, max; + + if (dev->format == 3) { + min = -2048; + max = 2047; + } else { + min = -128; + max = 127; + } + + if (*global > max) { + *local = max; + *global -= max; + } else if (*global < min) { + *local = min; + *global += -min; + } else { + *local = *global; + *global = 0; + } +} + + +static uint8_t +sermouse_update_data(mouse_t *dev) +{ + uint8_t ret = 0; + int delta_x, delta_y, delta_z; + + /* Update the deltas and the delays. */ + sermouse_update_delta(dev, &delta_x, &dev->rel_x); + sermouse_update_delta(dev, &delta_y, &dev->rel_y); + sermouse_update_delta(dev, &delta_z, &dev->rel_z); + + sermouse_report(delta_x, delta_y, delta_z, dev->oldb, dev); + + mouse_serial_log("delta_x = %i, delta_y = %i, delta_z = %i, dev->oldb = %02X\n", + delta_x, delta_y, delta_z, dev->oldb); + + if (delta_x || delta_y || delta_z || (dev->oldb != dev->lastb) || !dev->on_change) + ret = 1; + + dev->lastb = dev->oldb; + + mouse_serial_log("sermouse_update_data(): ret = %i\n", ret); + + return ret; +} + + +static double +sermouse_report_period(mouse_t *dev) +{ + if (dev->report_period == 0) + return dev->transmit_period; + else + return dev->report_period; +} + + +static void +sermouse_report_prepare(mouse_t *dev) +{ + if (sermouse_update_data(dev)) { + /* Start sending data. */ + dev->report_phase = REPORT_PHASE_TRANSMIT; + dev->report_pos = 0; + sermouse_timer_on(dev, dev->transmit_period, 1); + } else { + dev->report_phase = REPORT_PHASE_PREPARE; + sermouse_timer_on(dev, sermouse_report_period(dev), 1); + } +} + + +static void +sermouse_report_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->report_phase == REPORT_PHASE_PREPARE) + sermouse_report_prepare(dev); + else { + /* If using the Mouse Systems format, update data because + the last two bytes are the X and Y delta since bytes 1 + and 2 were transmitted. */ + if (!dev->format && (dev->report_pos == 3)) + sermouse_update_data(dev); + serial_write_fifo(dev->serial, dev->data[dev->report_pos]); + if (++dev->report_pos == dev->data_len) { + if (!dev->report_enabled) + sermouse_report_prepare(dev); + else { + sermouse_timer_on(dev, sermouse_report_period(dev), 1); + dev->report_phase = REPORT_PHASE_PREPARE; + } + } else + sermouse_timer_on(dev, dev->transmit_period, 1); + } } /* Callback timer expired, now send our "mouse ID" to the serial port. */ static void -sermouse_timer(void *priv) +sermouse_command_timer(void *priv) { mouse_t *dev = (mouse_t *)priv; - dev->delay = 0LL; - - if (dev->pos != -1) return; - - dev->pos = 0; - switch(dev->type) { - case MOUSE_TYPE_MSYSTEMS: - /* Identifies Mouse Systems serial mouse. */ - serial_write_fifo(dev->serial, 'H'); + switch (dev->command_phase) { + case PHASE_ID: + serial_write_fifo(dev->serial, dev->id[dev->command_pos]); + sermouse_command_pos_check(dev, dev->id_len); + if ((dev->command_phase == PHASE_IDLE) && (dev->type != MOUSE_TYPE_MSYSTEMS)) { + /* This resets back to Microsoft-compatible mode. */ + dev->report_phase = REPORT_PHASE_PREPARE; + sermouse_report_timer((void *) dev); + } break; - - case MOUSE_TYPE_MICROSOFT: - /* Identifies a two-button Microsoft Serial mouse. */ - serial_write_fifo(dev->serial, 'M'); + case PHASE_DATA: + serial_write_fifo(dev->serial, dev->data[dev->command_pos]); + sermouse_command_pos_check(dev, dev->data_len); break; - - case MOUSE_TYPE_LOGITECH: - /* Identifies a two-button Logitech Serial mouse. */ - serial_write_fifo(dev->serial, 'M'); - serial_write_fifo(dev->serial, '3'); + case PHASE_STATUS: + serial_write_fifo(dev->serial, dev->status); + sermouse_command_phase_idle(dev); break; - - case MOUSE_TYPE_MSWHEEL: - /* Identifies multi-button Microsoft Wheel Mouse. */ - serial_write_fifo(dev->serial, 'M'); - serial_write_fifo(dev->serial, 'Z'); + case PHASE_DIAGNOSTIC: + if (dev->command_pos) + serial_write_fifo(dev->serial, 0x00); + else + serial_write_fifo(dev->serial, sermouse_last_button_status(dev)); + sermouse_command_pos_check(dev, 3); + break; + case PHASE_FORMAT_AND_REVISION: + serial_write_fifo(dev->serial, 0x10 | (dev->format << 1)); + sermouse_command_phase_idle(dev); + break; + case PHASE_BUTTONS: + serial_write_fifo(dev->serial, dev->but); + sermouse_command_phase_idle(dev); break; - default: - mouse_serial_log("%s: unsupported mouse type %d?\n", dev->type); + sermouse_command_phase_idle(dev); + break; } } @@ -129,88 +539,212 @@ static int sermouse_poll(int x, int y, int z, int b, void *priv) { mouse_t *dev = (mouse_t *)priv; - uint8_t buff[16]; - int len; - if (!x && !y && b == dev->oldb) return(1); - -#if 0 - mouse_serial_log("%s: poll(%d,%d,%d,%02x)\n", dev->name, x, y, z, b); -#endif + if (!x && !y && !z && (b == dev->oldb)) { + dev->oldb = b; + return(1); + } dev->oldb = b; + dev->abs_x += x; + dev->abs_y += y; + if (dev->abs_x < 0) + dev->abs_x = 0; + if (dev->abs_x > 4095) + dev->abs_x = 4095; + if (dev->abs_y < 0) + dev->abs_y = 0; + if (dev->abs_y > 4095) + dev->abs_y = 4095; - if (x > 127) x = 127; - if (y > 127) y = 127; - if (x <- 128) x = -128; - if (y <- 128) y = -128; - - len = 0; - switch(dev->type) { - case MOUSE_TYPE_MSYSTEMS: - buff[0] = 0x80; - buff[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ - buff[0] |= (b & 0x02) ? 0x00 : 0x01; /* middle button */ - buff[0] |= (b & 0x04) ? 0x00 : 0x02; /* right button */ - buff[1] = x; - buff[2] = -y; - buff[3] = x; /* same as byte 1 */ - buff[4] = -y; /* same as byte 2 */ - len = 5; - break; - - case MOUSE_TYPE_MICROSOFT: - case MOUSE_TYPE_LOGITECH: - case MOUSE_TYPE_MSWHEEL: - buff[0] = 0x40; - buff[0] |= (((y >> 6) & 0x03) << 2); - buff[0] |= ((x >> 6) & 0x03); - if (b & 0x01) buff[0] |= 0x20; - if (b & 0x02) buff[0] |= 0x10; - buff[1] = x & 0x3F; - buff[2] = y & 0x3F; - if (dev->type == MOUSE_TYPE_LOGITECH) { - len = 3; - if (b & 0x04) { - buff[3] = 0x20; - len++; - } - } else if (dev->type == MOUSE_TYPE_MSWHEEL) { - len = 4; - buff[3] = z & 0x0F; - if (b & 0x04) - buff[3] |= 0x10; - } else - len = 3; - break; + if (dev->format == 3) { + if (x > 2047) x = 2047; + if (y > 2047) y = 2047; + if (x <- 2048) x = -2048; + if (y <- 2048) y = -2048; + } else { + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x <- 128) x = -128; + if (y <- 128) y = -128; } -#if 0 - mouse_serial_log("%s: [", dev->name); - for (b=0; bserial != NULL) { - for (b=0; bserial, buff[b]); - } + dev->rel_x += x; + dev->rel_y += y; + dev->rel_z += z; return(0); } +static void +ltsermouse_prompt_mode(mouse_t *dev, int prompt) +{ + dev->prompt = prompt; + dev->status &= 0xBF; + if (prompt) + dev->status |= 0x40; +} + + +static void +ltsermouse_command_phase(mouse_t *dev, int phase) +{ + dev->command_pos = 0; + dev->command_phase = phase; + timer_stop(&dev->command_timer); + sermouse_timer_on(dev, dev->transmit_period, 0); +} + + +static void +ltsermouse_set_report_period(mouse_t *dev, int rps) +{ + dev->report_period = sermouse_transmit_period(dev, 9600, rps); + timer_stop(&dev->report_timer); + sermouse_timer_on(dev, dev->report_period, 1); + ltsermouse_prompt_mode(dev, 0); + dev->report_phase = REPORT_PHASE_PREPARE; +} + + +static void +ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Stop reporting when we're processing a command. */ + dev->report_phase = REPORT_PHASE_PREPARE; + + if (dev->want_data) switch (dev->want_data) { + case 0x2A: + dev->data_len--; + dev->want_data = 0; + switch (data) { + default: + mouse_serial_log("Serial mouse: Invalid period %02X, using 1200 bps\n", data); + case 0x6E: + dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); + break; + case 0x6F: + dev->transmit_period = sermouse_transmit_period(dev, 2400, -1); + break; + case 0x70: + dev->transmit_period = sermouse_transmit_period(dev, 4800, -1); + break; + case 0x71: + dev->transmit_period = sermouse_transmit_period(dev, 9600, -1); + break; + } + break; + } else switch (data) { + case 0x2A: + dev->want_data = data; + dev->data_len = 1; + break; + case 0x44: /* Set prompt mode */ + ltsermouse_prompt_mode(dev, 1); + break; + case 0x50: + if (!dev->prompt) + ltsermouse_prompt_mode(dev, 1); + sermouse_update_data(dev); + ltsermouse_command_phase(dev, PHASE_DATA); + break; + case 0x73: /* Status */ + ltsermouse_command_phase(dev, PHASE_STATUS); + break; + case 0x4A: /* Report Rate Selection commands */ + ltsermouse_set_report_period(dev, 10); + break; + case 0x4B: + ltsermouse_set_report_period(dev, 20); + break; + case 0x4C: + ltsermouse_set_report_period(dev, 35); + break; + case 0x52: + ltsermouse_set_report_period(dev, 50); + break; + case 0x4D: + ltsermouse_set_report_period(dev, 70); + break; + case 0x51: + ltsermouse_set_report_period(dev, 100); + break; + case 0x4E: + ltsermouse_set_report_period(dev, 150); + break; + case 0x4F: + ltsermouse_prompt_mode(dev, 0); + dev->report_period = 0; + timer_stop(&dev->report_timer); + dev->report_phase = REPORT_PHASE_PREPARE; + sermouse_report_timer((void *) dev); + break; + case 0x41: + dev->format = 6; /* Aboslute Bit Pad One Format */ + dev->abs_x = dev->abs_y = 0; + break; + case 0x42: + dev->format = 3; /* Relative Bit Pad One Format */ + break; + case 0x53: + dev->format = 5; /* MM Series Format */ + break; + case 0x54: + dev->format = 1; /* Three Byte Packed Binary Format */ + break; + case 0x55: /* This is the Mouse Systems-compatible format */ + dev->format = 0; /* Five Byte Packed Binary Format */ + break; + case 0x56: + dev->format = 7; /* Microsoft Compatible Format */ + break; + case 0x57: + dev->format = 2; /* Hexadecimal Format */ + break; + case 0x05: + ltsermouse_command_phase(dev, PHASE_DIAGNOSTIC); + break; + case 0x66: + ltsermouse_command_phase(dev, PHASE_FORMAT_AND_REVISION); + break; + case 0x6B: + ltsermouse_command_phase(dev, PHASE_BUTTONS); + break; + } +} + + +static void +sermouse_speed_changed(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->report_enabled) { + timer_stop(&dev->report_timer); + if (dev->report_phase == REPORT_PHASE_TRANSMIT) + sermouse_timer_on(dev, dev->transmit_period, 1); + else + sermouse_timer_on(dev, sermouse_report_period(dev), 1); + } + + if (dev->command_enabled) { + timer_stop(&dev->command_timer); + sermouse_timer_on(dev, dev->transmit_period, 0); + } +} + + static void sermouse_close(void *priv) { mouse_t *dev = (mouse_t *)priv; /* Detach serial port from the mouse. */ - if ((dev != NULL) && (dev->serial != NULL)) { - dev->serial->rcr_callback = NULL; - dev->serial->rcr_callback_p = NULL; - } + if (dev && dev->serial && dev->serial->sd) + memset(dev->serial->sd, 0, sizeof(serial_device_t)); free(dev); } @@ -221,45 +755,71 @@ static void * sermouse_init(const device_t *info) { mouse_t *dev; - int i; dev = (mouse_t *)malloc(sizeof(mouse_t)); memset(dev, 0x00, sizeof(mouse_t)); dev->name = info->name; - i = device_get_config_int("buttons"); - if (i > 2) + dev->but = device_get_config_int("buttons"); + if (dev->but > 2) dev->flags |= FLAG_3BTN; - if (info->local == MOUSE_TYPE_MSYSTEMS) + if (info->local == MOUSE_TYPE_MSYSTEMS) { + dev->on_change = 1; + dev->format = 0; dev->type = info->local; - else { - switch(i) { + dev->id_len = 1; + dev->id[0] = 'H'; + } else { + dev->on_change = !info->local; + dev->format = 7; + dev->status = 0x0f; + dev->id_len = 1; + dev->id[0] = 'M'; + switch(dev->but) { case 2: default: - dev->type = MOUSE_TYPE_MICROSOFT; + dev->type = info->local ? MOUSE_TYPE_LOGITECH : MOUSE_TYPE_MICROSOFT; break; case 3: - dev->type = MOUSE_TYPE_LOGITECH; + dev->type = info->local ? MOUSE_TYPE_LT3BUTTON : MOUSE_TYPE_MS3BUTTON; + dev->id_len = 2; + dev->id[1] = '3'; break; case 4: dev->type = MOUSE_TYPE_MSWHEEL; + dev->id_len = 6; + dev->id[1] = 'Z'; + dev->id[2] = '@'; break; } } + dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); + + /* Default: Continuous reporting = no delay between reports. */ + dev->report_phase = REPORT_PHASE_PREPARE; + dev->report_period = 0; + + /* Default: Doing nothing - command transmit timer deactivated. */ + dev->command_phase = PHASE_IDLE; + dev->port = device_get_config_int("port"); /* Attach a serial port to the mouse. */ - if (dev->port == 0) - dev->serial = &serial1; - else - dev->serial = &serial2; - dev->serial->rcr_callback = sermouse_callback; - dev->serial->rcr_callback_p = dev; + if (info->local) + dev->serial = serial_attach(dev->port, sermouse_callback, ltsermouse_write, dev); + else + dev->serial = serial_attach(dev->port, sermouse_callback, NULL, dev); - mouse_serial_log("%s: port=COM%d\n", dev->name, dev->port+1); + mouse_serial_log("%s: port=COM%d\n", dev->name, dev->port + 1); - timer_add(sermouse_timer, &dev->delay, &dev->delay, dev); + timer_add(&dev->report_timer, sermouse_report_timer, dev, 0); + timer_add(&dev->command_timer, sermouse_command_timer, dev, 0); + + if (info->local == MOUSE_TYPE_MSYSTEMS) { + sermouse_timer_on(dev, dev->transmit_period, 1); + dev->report_enabled = 1; + } /* Tell them how many buttons we have. */ mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); @@ -269,7 +829,7 @@ sermouse_init(const device_t *info) } -static const device_config_t sermouse_config[] = { +static const device_config_t mssermouse_config[] = { { "port", "Serial Port", CONFIG_SELECTION, "", 0, { { @@ -305,20 +865,62 @@ static const device_config_t sermouse_config[] = { }; +static const device_config_t ltsermouse_config[] = { + { + "port", "Serial Port", CONFIG_SELECTION, "", 0, { + { + "COM1", 0 + }, + { + "COM2", 1 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + const device_t mouse_mssystems_device = { "Mouse Systems Serial Mouse", 0, MOUSE_TYPE_MSYSTEMS, sermouse_init, sermouse_close, NULL, - sermouse_poll, NULL, NULL, - sermouse_config + sermouse_poll, sermouse_speed_changed, NULL, + mssermouse_config }; const device_t mouse_msserial_device = { - "Microsoft/Logitech Serial Mouse", + "Microsoft Serial Mouse", 0, 0, sermouse_init, sermouse_close, NULL, - sermouse_poll, NULL, NULL, - sermouse_config + sermouse_poll, sermouse_speed_changed, NULL, + mssermouse_config +}; + +const device_t mouse_ltserial_device = { + "Logitech Serial Mouse", + 0, + 1, + sermouse_init, sermouse_close, NULL, + sermouse_poll, sermouse_speed_changed, NULL, + ltsermouse_config }; diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index 65bea5af7..282219ab3 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -8,7 +8,7 @@ * Implementation of the following network controllers: * - 3Com Etherlink II 3c503 (ISA 8-bit). * - * Version: @(#)net_3c503.c 1.0.0 2018/06/08 + * Version: @(#)net_3c503.c 1.0.2 2018/10/17 * * Based on @(#)3c503.cpp Carl (MAME) * @@ -49,28 +49,24 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../config.h" -#include "../machine/machine.h" #include "../io.h" #include "../dma.h" #include "../pic.h" #include "../mem.h" #include "../random.h" #include "../device.h" -#include "../ui.h" #include "network.h" #include "net_dp8390.h" #include "net_3c503.h" #include "bswap.h" typedef struct { - dp8390_t dp8390; + dp8390_t *dp8390; mem_mapping_t ram_mapping; uint32_t base_address; int base_irq; uint32_t bios_addr; uint8_t maclocal[6]; /* configured MAC (local) address */ - uint8_t prom[32]; struct { uint8_t pstr; @@ -91,19 +87,14 @@ typedef struct { int dma_channel; } threec503_t; -static void threec503_rx(void *, uint8_t *, int); -static void threec503_tx(threec503_t *, uint32_t); - #ifdef ENABLE_3COM503_LOG int threec503_do_log = ENABLE_3COM503_LOG; -#endif static void threec503_log(const char *fmt, ...) { -#ifdef ENABLE_3COM503_LOG va_list ap; if (threec503_do_log) { @@ -111,13 +102,17 @@ threec503_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define threec503_log(fmt, ...) +#endif static void -threec503_interrupt(threec503_t *dev, int set) +threec503_interrupt(void *priv, int set) { + threec503_t *dev = (threec503_t *) priv; + switch (dev->base_irq) { case 2: dev->regs.idcfr = 0x10; @@ -151,7 +146,7 @@ threec503_ram_write(uint32_t addr, uint8_t val, void *priv) if ((addr & 0x3fff) >= 0x2000) return; - dev->dp8390.mem[addr & 0x1fff] = val; + dev->dp8390->mem[addr & 0x1fff] = val; } @@ -163,7 +158,7 @@ threec503_ram_read(uint32_t addr, void *priv) if ((addr & 0x3fff) >= 0x2000) return 0xff; - return dev->dp8390.mem[addr & 0x1fff]; + return dev->dp8390->mem[addr & 0x1fff]; } @@ -191,746 +186,16 @@ static void threec503_reset(void *priv) { threec503_t *dev = (threec503_t *)priv; - int i; +#ifdef ENABLE_3COM503_LOG threec503_log("3Com503: reset\n"); +#endif - /* Initialize the MAC address area by doubling the physical address */ - dev->prom[0] = dev->dp8390.physaddr[0]; - dev->prom[1] = dev->dp8390.physaddr[1]; - dev->prom[2] = dev->dp8390.physaddr[2]; - dev->prom[3] = dev->dp8390.physaddr[3]; - dev->prom[4] = dev->dp8390.physaddr[4]; - dev->prom[5] = dev->dp8390.physaddr[5]; - - /* ne1k signature */ - for (i=6; i<16; i++) - dev->prom[i] = 0x57; - - /* Zero out registers and memory */ - memset(&dev->dp8390.CR, 0x00, sizeof(dev->dp8390.CR) ); - memset(&dev->dp8390.ISR, 0x00, sizeof(dev->dp8390.ISR)); - memset(&dev->dp8390.IMR, 0x00, sizeof(dev->dp8390.IMR)); - memset(&dev->dp8390.DCR, 0x00, sizeof(dev->dp8390.DCR)); - memset(&dev->dp8390.TCR, 0x00, sizeof(dev->dp8390.TCR)); - memset(&dev->dp8390.TSR, 0x00, sizeof(dev->dp8390.TSR)); - memset(&dev->dp8390.RSR, 0x00, sizeof(dev->dp8390.RSR)); - dev->dp8390.tx_timer_active = 0; - dev->dp8390.local_dma = 0; - dev->dp8390.page_start = 0; - dev->dp8390.page_stop = 0; - dev->dp8390.bound_ptr = 0; - dev->dp8390.tx_page_start = 0; - dev->dp8390.num_coll = 0; - dev->dp8390.tx_bytes = 0; - dev->dp8390.fifo = 0; - dev->dp8390.remote_dma = 0; - dev->dp8390.remote_start = 0; - dev->dp8390.remote_bytes = 0; - dev->dp8390.tallycnt_0 = 0; - dev->dp8390.tallycnt_1 = 0; - dev->dp8390.tallycnt_2 = 0; - - dev->dp8390.curr_page = 0; - - dev->dp8390.rempkt_ptr = 0; - dev->dp8390.localpkt_ptr = 0; - dev->dp8390.address_cnt = 0; - - memset(&dev->dp8390.mem, 0x00, sizeof(dev->dp8390.mem)); - - /* Set power-up conditions */ - dev->dp8390.CR.stop = 1; - dev->dp8390.CR.rdma_cmd = 4; - dev->dp8390.ISR.reset = 1; - dev->dp8390.DCR.longaddr = 1; + dp8390_reset(dev->dp8390); memset(&dev->regs, 0, sizeof(dev->regs)); dev->regs.ctrl = 0x0a; - - threec503_interrupt(dev, 0); -} - - -/* - * Access the 32K 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 uint32_t -threec503_chipmem_read(threec503_t *dev, uint32_t addr, unsigned int len) -{ - uint32_t retval = 0; - - if (addr <= 15) { - retval = dev->prom[addr % 16]; - if (len == 2) - retval |= (dev->prom[(addr + 1) % 16] << 8); - return(retval); - } - - if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) { - retval = dev->dp8390.mem[addr - DP8390_WORD_MEMSTART]; - if (len == 2) - retval |= (dev->dp8390.mem[addr - DP8390_WORD_MEMSTART + 1] << 8); - return(retval); - } - - threec503_log("3Com503: out-of-bounds chipmem read, %04X\n", addr); - return(0xff); -} - - -static void -threec503_chipmem_write(threec503_t *dev, uint32_t addr, uint32_t val, unsigned len) -{ - if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) { - dev->dp8390.mem[addr-DP8390_WORD_MEMSTART] = val & 0xff; - if (len == 2) - dev->dp8390.mem[addr-DP8390_WORD_MEMSTART+1] = val >> 8; - } else - threec503_log("3Com503: out-of-bounds chipmem write, %04X\n", addr); -} - - -/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ -static uint32_t -threec503_page0_read(threec503_t *dev, uint32_t off, unsigned int len) -{ - uint8_t retval = 0; - - if (len > 1) { - /* encountered with win98 hardware probe */ - threec503_log("3Com503: bad length! Page0 read from register 0x%02x, len=%u\n", - off, len); - return(retval); - } - - switch(off) { - case 0x01: /* CLDA0 */ - retval = (dev->dp8390.local_dma & 0xff); - break; - - case 0x02: /* CLDA1 */ - retval = (dev->dp8390.local_dma >> 8); - break; - - case 0x03: /* BNRY */ - retval = dev->dp8390.bound_ptr; - break; - - case 0x04: /* TSR */ - retval = ((dev->dp8390.TSR.ow_coll << 7) | - (dev->dp8390.TSR.cd_hbeat << 6) | - (dev->dp8390.TSR.fifo_ur << 5) | - (dev->dp8390.TSR.no_carrier << 4) | - (dev->dp8390.TSR.aborted << 3) | - (dev->dp8390.TSR.collided << 2) | - (dev->dp8390.TSR.tx_ok)); - break; - - case 0x05: /* NCR */ - retval = dev->dp8390.num_coll; - break; - - case 0x06: /* FIFO */ - /* reading FIFO is only valid in loopback mode */ - threec503_log("3Com503: reading FIFO not supported yet\n"); - retval = dev->dp8390.fifo; - break; - - case 0x07: /* ISR */ - retval = ((dev->dp8390.ISR.reset << 7) | - (dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - break; - - case 0x08: /* CRDA0 */ - retval = (dev->dp8390.remote_dma & 0xff); - break; - - case 0x09: /* CRDA1 */ - retval = (dev->dp8390.remote_dma >> 8); - break; - - case 0x0a: /* reserved / RTL8029ID0 */ - threec503_log("3Com503: reserved Page0 read - 0x0a\n"); - retval = 0xff; - break; - - case 0x0b: /* reserved / RTL8029ID1 */ - threec503_log("3Com503: reserved Page0 read - 0x0b\n"); - retval = 0xff; - break; - - case 0x0c: /* RSR */ - retval = ((dev->dp8390.RSR.deferred << 7) | - (dev->dp8390.RSR.rx_disabled << 6) | - (dev->dp8390.RSR.rx_mbit << 5) | - (dev->dp8390.RSR.rx_missed << 4) | - (dev->dp8390.RSR.fifo_or << 3) | - (dev->dp8390.RSR.bad_falign << 2) | - (dev->dp8390.RSR.bad_crc << 1) | - (dev->dp8390.RSR.rx_ok)); - break; - - case 0x0d: /* CNTR0 */ - retval = dev->dp8390.tallycnt_0; - break; - - case 0x0e: /* CNTR1 */ - retval = dev->dp8390.tallycnt_1; - break; - - case 0x0f: /* CNTR2 */ - retval = dev->dp8390.tallycnt_2; - break; - - default: - threec503_log("3Com503: Page0 register 0x%02x out of range\n", - off); - break; - } - - threec503_log("3Com503: Page0 read from register 0x%02x, value=0x%02x\n", - off, retval); - - return(retval); -} - - -static void -threec503_page0_write(threec503_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - uint8_t val2; - - /* It appears to be a common practice to use outw on page0 regs... */ - - /* break up outw into two outb's */ - if (len == 2) { - threec503_page0_write(dev, off, (val & 0xff), 1); - if (off < 0x0f) - threec503_page0_write(dev, off+1, ((val>>8)&0xff), 1); - return; - } - - threec503_log("3Com503: Page0 write to register 0x%02x, value=0x%02x\n", - off, val); - - switch(off) { - case 0x01: /* PSTART */ - dev->dp8390.page_start = val; - break; - - case 0x02: /* PSTOP */ - dev->dp8390.page_stop = val; - break; - - case 0x03: /* BNRY */ - dev->dp8390.bound_ptr = val; - break; - - case 0x04: /* TPSR */ - dev->dp8390.tx_page_start = val; - break; - - case 0x05: /* TBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.tx_bytes &= 0xff00; - dev->dp8390.tx_bytes |= (val & 0xff); - break; - - case 0x06: /* TBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.tx_bytes &= 0x00ff; - dev->dp8390.tx_bytes |= ((val & 0xff) << 8); - break; - - case 0x07: /* ISR */ - val &= 0x7f; /* clear RST bit - status-only bit */ - /* All other values are cleared iff the ISR bit is 1 */ - dev->dp8390.ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); - dev->dp8390.ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); - dev->dp8390.ISR.rx_err &= !((int)((val & 0x04) == 0x04)); - dev->dp8390.ISR.tx_err &= !((int)((val & 0x08) == 0x08)); - dev->dp8390.ISR.overwrite &= !((int)((val & 0x10) == 0x10)); - dev->dp8390.ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); - dev->dp8390.ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); - val = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - val &= ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - if (val == 0x00) - threec503_interrupt(dev, 0); - break; - - case 0x08: /* RSAR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_start &= 0xff00; - dev->dp8390.remote_start |= (val & 0xff); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x09: /* RSAR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_start &= 0x00ff; - dev->dp8390.remote_start |= ((val & 0xff) << 8); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x0a: /* RBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_bytes &= 0xff00; - dev->dp8390.remote_bytes |= (val & 0xff); - break; - - case 0x0b: /* RBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_bytes &= 0x00ff; - dev->dp8390.remote_bytes |= ((val & 0xff) << 8); - break; - - case 0x0c: /* RCR */ - /* Check if the reserved bits are set */ - if (val & 0xc0) { - threec503_log("3Com503: RCR write, reserved bits set\n"); - } - - /* Set all other bit-fields */ - dev->dp8390.RCR.errors_ok = ((val & 0x01) == 0x01); - dev->dp8390.RCR.runts_ok = ((val & 0x02) == 0x02); - dev->dp8390.RCR.broadcast = ((val & 0x04) == 0x04); - dev->dp8390.RCR.multicast = ((val & 0x08) == 0x08); - dev->dp8390.RCR.promisc = ((val & 0x10) == 0x10); - dev->dp8390.RCR.monitor = ((val & 0x20) == 0x20); - - /* Monitor bit is a little suspicious... */ - if (val & 0x20) threec503_log("3Com503: RCR write, monitor bit set!\n"); - break; - - case 0x0d: /* TCR */ - /* Check reserved bits */ - if (val & 0xe0) threec503_log("3Com503: TCR write, reserved bits set\n"); - - /* Test loop mode (not supported) */ - if (val & 0x06) { - dev->dp8390.TCR.loop_cntl = (val & 0x6) >> 1; - threec503_log("3Com503: TCR write, loop mode %d not supported\n", - dev->dp8390.TCR.loop_cntl); - } else { - dev->dp8390.TCR.loop_cntl = 0; - } - - /* Inhibit-CRC not supported. */ - if (val & 0x01) threec503_log( - "3Com503: TCR write, inhibit-CRC not supported\n"); - - /* Auto-transmit disable very suspicious */ - if (val & 0x08) threec503_log( - "3Com503: TCR write, auto transmit disable not supported\n"); - - /* Allow collision-offset to be set, although not used */ - dev->dp8390.TCR.coll_prio = ((val & 0x08) == 0x08); - break; - - case 0x0e: /* DCR */ - /* the loopback mode is not suppported yet */ - if (! (val & 0x08)) threec503_log( - "3Com503: DCR write, loopback mode selected\n"); - - /* It is questionable to set longaddr and auto_rx, since - * they are not supported on the NE2000. Print a warning - * and continue. */ - if (val & 0x04) - threec503_log("3Com503: DCR write - LAS set ???\n"); - if (val & 0x10) - threec503_log("3Com503: DCR write - AR set ???\n"); - - /* Set other values. */ - dev->dp8390.DCR.wdsize = ((val & 0x01) == 0x01); - dev->dp8390.DCR.endian = ((val & 0x02) == 0x02); - dev->dp8390.DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ - dev->dp8390.DCR.loop = ((val & 0x08) == 0x08); - dev->dp8390.DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ - dev->dp8390.DCR.fifo_size = (val & 0x50) >> 5; - break; - - case 0x0f: /* IMR */ - /* Check for reserved bit */ - if (val & 0x80) - threec503_log("3Com503: IMR write, reserved bit set\n"); - - /* Set other values */ - dev->dp8390.IMR.rx_inte = ((val & 0x01) == 0x01); - dev->dp8390.IMR.tx_inte = ((val & 0x02) == 0x02); - dev->dp8390.IMR.rxerr_inte = ((val & 0x04) == 0x04); - dev->dp8390.IMR.txerr_inte = ((val & 0x08) == 0x08); - dev->dp8390.IMR.overw_inte = ((val & 0x10) == 0x10); - dev->dp8390.IMR.cofl_inte = ((val & 0x20) == 0x20); - dev->dp8390.IMR.rdma_inte = ((val & 0x40) == 0x40); - val2 = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - if (((val & val2) & 0x7f) == 0) - threec503_interrupt(dev, 0); - else - threec503_interrupt(dev, 1); - break; - - default: - threec503_log("3Com503: Page0 write, bad register 0x%02x\n", - off); - break; - } -} - - -/* Handle reads/writes to the first page of the DS8390 register file. */ -static uint32_t -threec503_page1_read(threec503_t *dev, uint32_t off, unsigned int len) -{ - threec503_log("3Com503: Page1 read from register 0x%02x, len=%u\n", - off, len); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - return(dev->dp8390.physaddr[off - 1]); - - case 0x07: /* CURR */ - threec503_log("3Com503: returning current page: 0x%02x\n", - (dev->dp8390.curr_page)); - return(dev->dp8390.curr_page); - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - return(dev->dp8390.mchash[off - 8]); - - default: - threec503_log("3Com503: Page1 read register 0x%02x out of range\n", - off); - return(0); - } -} - - -static void -threec503_page1_write(threec503_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - threec503_log("3Com503: Page1 write to register 0x%02x, len=%u, value=0x%04x\n", - off, len, val); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - dev->dp8390.physaddr[off - 1] = val; - if (off == 6) threec503_log( - "3Com503: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], - dev->dp8390.physaddr[2], dev->dp8390.physaddr[3], - dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); - break; - - case 0x07: /* CURR */ - dev->dp8390.curr_page = val; - break; - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - dev->dp8390.mchash[off - 8] = val; - break; - - default: - threec503_log("3Com503: Page1 write register 0x%02x out of range\n", - off); - break; - } -} - - -/* Handle reads/writes to the second page of the DS8390 register file. */ -static uint32_t -threec503_page2_read(threec503_t *dev, uint32_t off, unsigned int len) -{ - threec503_log("3Com503: Page2 read from register 0x%02x, len=%u\n", - off, len); - - switch(off) { - case 0x01: /* PSTART */ - return(dev->dp8390.page_start); - - case 0x02: /* PSTOP */ - return(dev->dp8390.page_stop); - - case 0x03: /* Remote Next-packet pointer */ - return(dev->dp8390.rempkt_ptr); - - case 0x04: /* TPSR */ - return(dev->dp8390.tx_page_start); - - case 0x05: /* Local Next-packet pointer */ - return(dev->dp8390.localpkt_ptr); - - case 0x06: /* Address counter (upper) */ - return(dev->dp8390.address_cnt >> 8); - - case 0x07: /* Address counter (lower) */ - return(dev->dp8390.address_cnt & 0xff); - - case 0x08: /* Reserved */ - case 0x09: - case 0x0a: - case 0x0b: - threec503_log("3Com503: reserved Page2 read - register 0x%02x\n", - off); - return(0xff); - - case 0x0c: /* RCR */ - return ((dev->dp8390.RCR.monitor << 5) | - (dev->dp8390.RCR.promisc << 4) | - (dev->dp8390.RCR.multicast << 3) | - (dev->dp8390.RCR.broadcast << 2) | - (dev->dp8390.RCR.runts_ok << 1) | - (dev->dp8390.RCR.errors_ok)); - - case 0x0d: /* TCR */ - return ((dev->dp8390.TCR.coll_prio << 4) | - (dev->dp8390.TCR.ext_stoptx << 3) | - ((dev->dp8390.TCR.loop_cntl & 0x3) << 1) | - (dev->dp8390.TCR.crc_disable)); - - case 0x0e: /* DCR */ - return (((dev->dp8390.DCR.fifo_size & 0x3) << 5) | - (dev->dp8390.DCR.auto_rx << 4) | - (dev->dp8390.DCR.loop << 3) | - (dev->dp8390.DCR.longaddr << 2) | - (dev->dp8390.DCR.endian << 1) | - (dev->dp8390.DCR.wdsize)); - - case 0x0f: /* IMR */ - return ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - - default: - threec503_log("3Com503: Page2 register 0x%02x out of range\n", - off); - break; - } - - return(0); -} - - -static void -threec503_page2_write(threec503_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - /* Maybe all writes here should be BX_PANIC()'d, since they - affect internal operation, but let them through for now - and print a warning. */ - threec503_log("3Com503: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", - off, len, val); - switch(off) { - case 0x01: /* CLDA0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.local_dma &= 0xff00; - dev->dp8390.local_dma |= (val & 0xff); - break; - - case 0x02: /* CLDA1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.local_dma &= 0x00ff; - dev->dp8390.local_dma |= ((val & 0xff) << 8); - break; - - case 0x03: /* Remote Next-pkt pointer */ - dev->dp8390.rempkt_ptr = val; - break; - - case 0x04: - threec503_log("page 2 write to reserved register 0x04\n"); - break; - - case 0x05: /* Local Next-packet pointer */ - dev->dp8390.localpkt_ptr = val; - break; - - case 0x06: /* Address counter (upper) */ - /* Clear out high byte and re-insert */ - dev->dp8390.address_cnt &= 0x00ff; - dev->dp8390.address_cnt |= ((val & 0xff) << 8); - break; - - case 0x07: /* Address counter (lower) */ - /* Clear out low byte and re-insert */ - dev->dp8390.address_cnt &= 0xff00; - dev->dp8390.address_cnt |= (val & 0xff); - break; - - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - threec503_log("3Com503: Page2 write to reserved register 0x%02x\n", - off); - break; - - default: - threec503_log("3Com503: Page2 write, illegal register 0x%02x\n", - off); - break; - } -} - - -/* Routines for handling reads/writes to the Command Register. */ -static uint32_t -threec503_read_cr(threec503_t *dev) -{ - uint32_t retval; - - retval = (((dev->dp8390.CR.pgsel & 0x03) << 6) | - ((dev->dp8390.CR.rdma_cmd & 0x07) << 3) | - (dev->dp8390.CR.tx_packet << 2) | - (dev->dp8390.CR.start << 1) | - (dev->dp8390.CR.stop)); - threec503_log("3Com503: read CR returns 0x%02x\n", retval); - - return(retval); -} - - -static void -threec503_write_cr(threec503_t *dev, uint32_t val) -{ - threec503_log("3Com503: wrote 0x%02x to CR\n", val); - - /* Validate remote-DMA */ - if ((val & 0x38) == 0x00) { - threec503_log("3Com503: CR write - invalid rDMA value 0\n"); - val |= 0x20; /* dma_cmd == 4 is a safe default */ - } - - /* Check for s/w reset */ - if (val & 0x01) { - dev->dp8390.ISR.reset = 1; - dev->dp8390.CR.stop = 1; - } else - dev->dp8390.CR.stop = 0; - - dev->dp8390.CR.rdma_cmd = (val & 0x38) >> 3; - - /* If start command issued, the RST bit in the ISR */ - /* must be cleared */ - if ((val & 0x02) && !dev->dp8390.CR.start) - dev->dp8390.ISR.reset = 0; - - dev->dp8390.CR.start = ((val & 0x02) == 0x02); - dev->dp8390.CR.pgsel = (val & 0xc0) >> 6; - - /* Check for send-packet command */ - if (dev->dp8390.CR.rdma_cmd == 3) { - /* Set up DMA read from receive ring */ - dev->dp8390.remote_start = dev->dp8390.remote_dma = dev->dp8390.bound_ptr * 256; - dev->dp8390.remote_bytes = (uint16_t) threec503_chipmem_read(dev, dev->dp8390.bound_ptr * 256 + 2, 2); - threec503_log("3Com503: sending buffer %x length %d\n", - dev->dp8390.remote_start, dev->dp8390.remote_bytes); - } - - /* Check for start-tx */ - if ((val & 0x04) && dev->dp8390.TCR.loop_cntl) { - if (dev->dp8390.TCR.loop_cntl != 1) { - threec503_log("3Com503: loop mode %d not supported\n", - dev->dp8390.TCR.loop_cntl); - } else { - threec503_rx(dev, - &dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - } - } else if (val & 0x04) { - if (dev->dp8390.CR.stop || (!dev->dp8390.CR.start)) { - if (dev->dp8390.tx_bytes == 0) /* njh@bandsman.co.uk */ - return; /* Solaris9 probe */ - threec503_log("3Com503: CR write - tx start, dev in reset\n"); - } - - if (dev->dp8390.tx_bytes == 0) - threec503_log("3Com503: CR write - tx start, tx bytes == 0\n"); - - /* Send the packet to the system driver */ - dev->dp8390.CR.tx_packet = 1; - network_tx(&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - - /* some more debug */ - if (dev->dp8390.tx_timer_active) - threec503_log("3Com503: CR write, tx timer still active\n"); - - threec503_tx(dev, val); - } - - /* 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 (dev->dp8390.CR.rdma_cmd == 0x01 && dev->dp8390.CR.start && dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) { - threec503_interrupt(dev, 1); - threec503_interrupt(dev, 0); - } - } } @@ -945,18 +210,18 @@ threec503_nic_lo_read(uint16_t addr, void *priv) case 0x00: threec503_log("Read offset=%04x\n", off); if (off == 0x00) - retval = threec503_read_cr(dev); - else switch(dev->dp8390.CR.pgsel) { + retval = dp8390_read_cr(dev->dp8390); + else switch(dev->dp8390->CR.pgsel) { case 0x00: - retval = threec503_page0_read(dev, off, 1); + retval = dp8390_page0_read(dev->dp8390, off, 1); break; case 0x01: - retval = threec503_page1_read(dev, off, 1); + retval = dp8390_page1_read(dev->dp8390, off, 1); break; case 0x02: - retval = threec503_page2_read(dev, off, 1); + retval = dp8390_page2_read(dev->dp8390, off, 1); break; case 0x03: @@ -966,11 +231,11 @@ threec503_nic_lo_read(uint16_t addr, void *priv) break; case 0x01: - retval = dev->prom[off]; + retval = dev->dp8390->macaddr[off]; break; case 0x02: - retval = dev->prom[off + 0x10]; + retval = dev->dp8390->macaddr[off + 0x10]; break; case 0x03: @@ -995,18 +260,18 @@ threec503_nic_lo_write(uint16_t addr, uint8_t val, void *priv) page being selected by the PS0,PS1 registers in the command register */ if (off == 0x00) - threec503_write_cr(dev, val); - else switch(dev->dp8390.CR.pgsel) { + dp8390_write_cr(dev->dp8390, val); + else switch(dev->dp8390->CR.pgsel) { case 0x00: - threec503_page0_write(dev, off, val, 1); + dp8390_page0_write(dev->dp8390, off, val, 1); break; case 0x01: - threec503_page1_write(dev, off, val, 1); + dp8390_page1_write(dev->dp8390, off, val, 1); break; case 0x02: - threec503_page2_write(dev, off, val, 1); + dp8390_page2_write(dev->dp8390, off, val, 1); break; case 0x03: @@ -1136,7 +401,7 @@ threec503_nic_hi_read(uint16_t addr, void *priv) threec503_set_drq(dev); - return threec503_chipmem_read(dev, dev->regs.da++, 1); + return dp8390_chipmem_read(dev->dp8390, dev->regs.da++, 1); } return 0; @@ -1165,11 +430,10 @@ threec503_nic_hi_write(uint16_t addr, uint8_t val, void *priv) case 0x05: if ((dev->regs.gacfr & 0x0f) != (val & 0x0f)) { - mem_mapping_disable(&dev->ram_mapping); - switch (val & 0x0f) { case 0: /*ROM mapping*/ /* FIXME: Implement this when a BIOS is found/generated. */ + mem_mapping_disable(&dev->ram_mapping); break; case 9: /*RAM mapping*/ @@ -1177,6 +441,7 @@ threec503_nic_hi_write(uint16_t addr, uint8_t val, void *priv) break; default: /*No ROM mapping*/ + mem_mapping_disable(&dev->ram_mapping); break; } } @@ -1192,7 +457,7 @@ threec503_nic_hi_write(uint16_t addr, uint8_t val, void *priv) case 0x06: if (val & 1) { threec503_reset(dev); - dev->dp8390.ISR.reset = 1; + dev->dp8390->ISR.reset = 1; dev->regs.ctrl = 0x0b; return; } @@ -1266,25 +531,12 @@ threec503_nic_hi_write(uint16_t addr, uint8_t val, void *priv) threec503_set_drq(dev); - threec503_chipmem_write(dev, dev->regs.da++, val, 1); + dp8390_chipmem_write(dev->dp8390, dev->regs.da++, val, 1); break; } } -static void -threec503_nic_ioremove(threec503_t *dev, uint16_t addr) -{ - io_removehandler(addr, 0x10, - threec503_nic_lo_read, NULL, NULL, - threec503_nic_lo_write, NULL, NULL, dev); - - io_removehandler(addr+0x400, 0x10, - threec503_nic_hi_read, NULL, NULL, - threec503_nic_hi_write, NULL, NULL, dev); -} - - static void threec503_nic_ioset(threec503_t *dev, uint16_t addr) { @@ -1298,174 +550,6 @@ threec503_nic_ioset(threec503_t *dev, uint16_t addr) } -static void -threec503_tx(threec503_t *dev, uint32_t val) -{ - dev->dp8390.CR.tx_packet = 0; - dev->dp8390.TSR.tx_ok = 1; - dev->dp8390.ISR.pkt_tx = 1; - - /* Generate an interrupt if not masked */ - if (dev->dp8390.IMR.tx_inte) - threec503_interrupt(dev, 1); - dev->dp8390.tx_timer_active = 0; -} - - -/* - * 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. - */ -static void -threec503_rx(void *priv, uint8_t *buf, int io_len) -{ - static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; - threec503_t *dev = (threec503_t *)priv; - uint8_t pkthdr[4]; - uint8_t *startptr; - int rx_pages, avail; - int idx, nextpage; - int endbytes; - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 1); - - if (io_len != 60) - threec503_log("3Com503: rx_frame with length %d\n", io_len); - - if ((dev->dp8390.CR.stop != 0) || (dev->dp8390.page_start == 0)) return; - - /* - * Add the pkt header + CRC to the length, and work - * out how many 256-byte pages the frame would occupy. - */ - rx_pages = (io_len + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; - if (dev->dp8390.curr_page < dev->dp8390.bound_ptr) { - avail = dev->dp8390.bound_ptr - dev->dp8390.curr_page; - } else { - avail = (dev->dp8390.page_stop - dev->dp8390.page_start) - - (dev->dp8390.curr_page - dev->dp8390.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 < rx_pages) -#if NE2K_NEVER_FULL_RING - || (avail == rx_pages) -#endif - ) { - threec503_log("3Com503: no space\n"); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - if ((io_len < 40/*60*/) && !dev->dp8390.RCR.runts_ok) { - threec503_log("3Com503: rejected small packet, length %d\n", io_len); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Some computers don't care... */ - if (io_len < 60) - io_len = 60; - - threec503_log("3Com503: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", - buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - io_len); - - /* Do address filtering if not in promiscuous mode. */ - if (! dev->dp8390.RCR.promisc) { - /* If this is a broadcast frame.. */ - if (! memcmp(buf, bcast_addr, 6)) { - /* Broadcast not enabled, we're done. */ - if (! dev->dp8390.RCR.broadcast) { - threec503_log("3Com503: RX BC disabled\n"); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* If this is a multicast frame.. */ - else if (buf[0] & 0x01) { - /* Multicast not enabled, we're done. */ - if (! dev->dp8390.RCR.multicast) { -#if 1 - threec503_log("3Com503: RX MC disabled\n"); -#endif - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Are we listening to this multicast address? */ - idx = mcast_index(buf); - if (! (dev->dp8390.mchash[idx>>3] & (1<<(idx&0x7)))) { - threec503_log("3Com503: RX MC not listed\n"); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* Unicast, must be for us.. */ - else if (memcmp(buf, dev->dp8390.physaddr, 6)) return; - } else - threec503_log("3Com503: RX promiscuous receive\n"); - - nextpage = dev->dp8390.curr_page + rx_pages; - if (nextpage >= dev->dp8390.page_stop) - nextpage -= (dev->dp8390.page_stop - dev->dp8390.page_start); - - /* Set up packet header. */ - pkthdr[0] = 0x01; /* RXOK - packet is OK */ - if (buf[0] & 0x01) - pkthdr[0] |= 0x20; /* MULTICAST packet */ - pkthdr[1] = nextpage; /* ptr to next packet */ - pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ - pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ - threec503_log("3Com503: RX pkthdr [%02x %02x %02x %02x]\n", - pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); - - /* Copy into buffer, update curpage, and signal interrupt if config'd */ - startptr = &dev->dp8390.mem[(dev->dp8390.curr_page * 256) - DP8390_WORD_MEMSTART]; - memcpy(startptr, pkthdr, sizeof(pkthdr)); - if ((nextpage > dev->dp8390.curr_page) || - ((dev->dp8390.curr_page + rx_pages) == dev->dp8390.page_stop)) { - memcpy(startptr+sizeof(pkthdr), buf, io_len); - } else { - endbytes = (dev->dp8390.page_stop - dev->dp8390.curr_page) * 256; - memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); - startptr = &dev->dp8390.mem[(dev->dp8390.page_start * 256) - DP8390_WORD_MEMSTART]; - memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); - } - dev->dp8390.curr_page = nextpage; - - dev->dp8390.RSR.rx_ok = 1; - dev->dp8390.RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; - dev->dp8390.ISR.pkt_rx = 1; - - if (dev->dp8390.IMR.rx_inte) - threec503_interrupt(dev, 1); - - /* FIXME: move to upper layer */ - ui_sb_update_icon(SB_NETWORK, 0); -} - - static void * threec503_nic_init(const device_t *info) { @@ -1482,7 +566,7 @@ threec503_nic_init(const device_t *info) dev->base_irq = device_get_config_int("irq"); dev->dma_channel = device_get_config_int("dma"); dev->bios_addr = device_get_config_hex20("bios_addr"); - + /* See if we have a local MAC address configured. */ mac = device_get_config_mac("mac", -1); @@ -1507,25 +591,33 @@ threec503_nic_init(const device_t *info) dev->maclocal[4] = (mac>>8) & 0xff; dev->maclocal[5] = (mac & 0xff); } - memcpy(dev->dp8390.physaddr, dev->maclocal, sizeof(dev->maclocal)); + + dev->dp8390 = device_add(&dp8390_device); + dev->dp8390->priv = dev; + dev->dp8390->interrupt = threec503_interrupt; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CHECK_CR | DP8390_FLAG_CLEAR_IRQ); + dp8390_mem_alloc(dev->dp8390, 0x2000, 0x2000); + + memcpy(dev->dp8390->physaddr, dev->maclocal, sizeof(dev->maclocal)); threec503_log("I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", dev->base_address, dev->base_irq, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], dev->dp8390.physaddr[2], - dev->dp8390.physaddr[3], dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); + dev->dp8390->physaddr[0], dev->dp8390->physaddr[1], dev->dp8390->physaddr[2], + dev->dp8390->physaddr[3], dev->dp8390->physaddr[4], dev->dp8390->physaddr[5]); /* Reset the board. */ threec503_reset(dev); - /* Attach ourselves to the network module. */ - network_attach(dev, dev->dp8390.physaddr, threec503_rx); - /* Map this system into the memory map. */ mem_mapping_add(&dev->ram_mapping, dev->bios_addr, 0x4000, threec503_ram_read, NULL, NULL, threec503_ram_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, dev); - mem_mapping_disable(&dev->ram_mapping); + // mem_mapping_disable(&dev->ram_mapping); + dev->regs.gacfr = 0x09; /* Start with RAM mapping enabled. */ + + /* Attach ourselves to the network module. */ + network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx); return(dev); } @@ -1535,13 +627,10 @@ static void threec503_nic_close(void *priv) { threec503_t *dev = (threec503_t *)priv; - - /* Make sure the platform layer is shut down. */ - network_close(); - - threec503_nic_ioremove(dev, dev->base_address); +#ifdef ENABLE_3COM503_LOG threec503_log("3Com503: closed\n"); +#endif free(dev); } diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index ee24ecd1e..3c30a23e5 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -1,3 +1,20 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the DP8390 Network Interface Controller used by + * the WD family, NE1000/NE2000 family, and 3Com 3C503 NIC's. + * + * Version: @(#)net_dp8390.c 1.0.2 2018/10/21 + * + * Authors: Miran Grca, + * Bochs project, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Bochs project. + */ #include #include #include @@ -6,12 +23,40 @@ #include #include #define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "network.h" +#include "net_dp8390.h" + + +static void dp8390_tx(dp8390_t *dev, uint32_t val); +void dp8390_rx(void *priv, uint8_t *buf, int io_len); + + +#ifdef ENABLE_DP8390_LOG +int dp8390_do_log = ENABLE_DP8390_LOG; + +static void +dp8390_log(const char *fmt, ...) +{ + va_list ap; + + if (dp8390_do_log >= lvl) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define dp8390_log(lvl, fmt, ...) +#endif + /* * Return the 6-bit index into the multicast * table. Stolen unashamedly from FreeBSD's if_ed.c */ -int +static int mcast_index(const void *dst) { #define POLYNOMIAL 0x04c11db6 @@ -33,3 +78,1026 @@ mcast_index(const void *dst) return(crc >> 26); #undef POLYNOMIAL } + + +/* + * Access the 32K 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 contain the MAC address at even locations, + * and there is 16K of buffer memory starting at 16K. + */ +uint32_t +dp8390_chipmem_read(dp8390_t *dev, uint32_t addr, unsigned int len) +{ + int i; + uint32_t retval = 0; + +#ifdef ENABLE_DP8390_LOG + if ((len > 1) && (addr & (len - 1)) + dp3890_log("DP8390: unaligned chipmem word read\n"); +#endif + + dp8390_log("DP8390: Chipmem Read Address=%04x\n", addr); + + /* ROM'd MAC address */ + for (i = 0; i < len; i++) { + if ((addr >= dev->mem_start) && (addr < dev->mem_end)) + retval |= (uint32_t) (dev->mem[addr - dev->mem_start]) << (i << 3); + else if (addr < dev->macaddr_size) + retval |= ((uint32_t) dev->macaddr[addr & (dev->macaddr_size - 1)]) << (i << 3); + else { + dp8390_log("DP8390: out-of-bounds chipmem read, %04X\n", addr); + retval |= 0xff << (i << 3); + } + addr++; + } + + return(retval); +} + + +void +dp8390_chipmem_write(dp8390_t *dev, uint32_t addr, uint32_t val, unsigned len) +{ + int i; + +#ifdef ENABLE_DP8390_LOG + if ((len > 1) && (addr & (len - 1)) + dp8390_log("DP8390: unaligned chipmem word write\n"); +#endif + + dp8390_log("DP8390: Chipmem Write Address=%04x\n", addr); + + for (i = 0; i < len; i++) { + if ((addr < dev->mem_start) || (addr >= dev->mem_end)) { + dp8390_log("DP8390: out-of-bounds chipmem write, %04X\n", addr); + return; + } + + dev->mem[addr - dev->mem_start] = val & 0xff; + val >>= 8; + addr++; + } +} + + +/* Routines for handling reads/writes to the Command Register. */ +uint32_t +dp8390_read_cr(dp8390_t *dev) +{ + uint32_t retval; + + retval = (((dev->CR.pgsel & 0x03) << 6) | + ((dev->CR.rdma_cmd & 0x07) << 3) | + (dev->CR.tx_packet << 2) | + (dev->CR.start << 1) | + (dev->CR.stop)); + dp8390_log("DP8390: read CR returns 0x%02x\n", retval); + + return(retval); +} + + +void +dp8390_write_cr(dp8390_t *dev, uint32_t val) +{ + dp8390_log("DP8390: wrote 0x%02x to CR\n", val); + + /* Validate remote-DMA */ + if ((val & 0x38) == 0x00) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: CR write - invalid rDMA value 0\n"); +#endif + val |= 0x20; /* dma_cmd == 4 is a safe default */ + } + + /* Check for s/w reset */ + if (val & 0x01) { + dev->ISR.reset = 1; + dev->CR.stop = 1; + } else { + dev->CR.stop = 0; + } + + dev->CR.rdma_cmd = (val & 0x38) >> 3; + + /* If start command issued, the RST bit in the ISR */ + /* must be cleared */ + if ((val & 0x02) && !dev->CR.start) + dev->ISR.reset = 0; + + dev->CR.start = ((val & 0x02) == 0x02); + dev->CR.pgsel = (val & 0xc0) >> 6; + + /* Check for send-packet command */ + if (dev->CR.rdma_cmd == 3) { + /* Set up DMA read from receive ring */ + dev->remote_start = dev->remote_dma = dev->bound_ptr * 256; + dev->remote_bytes = (uint16_t) dp8390_chipmem_read(dev, dev->bound_ptr * 256 + 2, 2); + dp8390_log("DP8390: sending buffer #x%x length %d\n", + dev->dp8390.remote_start, dev->dp8390.remote_bytes); + } + + /* Check for start-tx */ + if ((val & 0x04) && dev->TCR.loop_cntl) { + if (dev->TCR.loop_cntl) { + dp8390_rx(dev, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], + dev->tx_bytes); + } + } else if (val & 0x04) { + if (dev->CR.stop || (!dev->CR.start && (dev->flags & DP8390_FLAG_CHECK_CR))) { + if (dev->tx_bytes == 0) /* njh@bandsman.co.uk */ + return; /* Solaris9 probe */ +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: CR write - tx start, dev in reset\n"); +#endif + } + +#ifdef ENABLE_DP8390_LOG + if (dev->tx_bytes == 0) + dp8390_log("DP8390: CR write - tx start, tx bytes == 0\n"); +#endif + + /* Send the packet to the system driver */ + dev->CR.tx_packet = 1; + + network_tx(&dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes); + + /* some more debug */ +#ifdef ENABLE_DP8390_LOG + if (dev->tx_timer_active) + dp8390_log("DP8390: CR write, tx timer still active\n"); +#endif + + dp8390_tx(dev, val); + } + + /* 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 ((dev->CR.rdma_cmd == 0x01) && dev->CR.start && + (dev->remote_bytes == 0)) { + dev->ISR.rdma_done = 1; + if (dev->IMR.rdma_inte && dev->interrupt) { + dev->interrupt(dev->priv, 1); + if (dev->flags & DP8390_FLAG_CLEAR_IRQ) + dev->interrupt(dev->priv, 0); + } + } +} + + +static void +dp8390_tx(dp8390_t *dev, uint32_t val) +{ + dev->CR.tx_packet = 0; + dev->TSR.tx_ok = 1; + dev->ISR.pkt_tx = 1; + + /* Generate an interrupt if not masked */ + if (dev->IMR.tx_inte && dev->interrupt) + dev->interrupt(dev->priv, 1); + dev->tx_timer_active = 0; +} + + +/* + * 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 +dp8390_rx(void *priv, uint8_t *buf, int io_len) +{ + dp8390_t *dev = (dp8390_t *)priv; + static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; + uint8_t pkthdr[4]; + uint8_t *startptr; + int pages, avail; + int idx, nextpage; + int endbytes; + + if (io_len != 60) + dp8390_log("%s: rx_frame with length %d\n", dev->name, io_len); + + if ((dev->CR.stop != 0) || (dev->page_start == 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 + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; + if (dev->curr_page < dev->bound_ptr) { + avail = dev->bound_ptr - dev->curr_page; + } else { + avail = (dev->page_stop - dev->page_start) - + (dev->curr_page - dev->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 DP8390_NEVER_FULL_RING + || (avail == pages) +#endif + ) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: no space\n"); +#endif + + return; + } + + if ((io_len < 40/*60*/) && !dev->RCR.runts_ok) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: rejected small packet, length %d\n", io_len); +#endif + + return; + } + + /* Some computers don't care... */ + if (io_len < 60) + io_len = 60; + + dp8390_log("DP8390: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", + buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + io_len); + + /* Do address filtering if not in promiscuous mode. */ + if (! dev->RCR.promisc) { + /* If this is a broadcast frame.. */ + if (! memcmp(buf, bcast_addr, 6)) { + /* Broadcast not enabled, we're done. */ + if (! dev->RCR.broadcast) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: RX BC disabled\n"); +#endif + return; + } + } + + /* If this is a multicast frame.. */ + else if (buf[0] & 0x01) { + /* Multicast not enabled, we're done. */ + if (! dev->RCR.multicast) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: RX MC disabled\n"); +#endif + return; + } + + /* Are we listening to this multicast address? */ + idx = mcast_index(buf); + if (! (dev->mchash[idx>>3] & (1<<(idx&0x7)))) { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: RX MC not listed\n"); +#endif + return; + } + } + + /* Unicast, must be for us.. */ + else if (memcmp(buf, dev->physaddr, 6)) return; + } else { +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: RX promiscuous receive\n"); +#endif + } + + nextpage = dev->curr_page + pages; + if (nextpage >= dev->page_stop) + nextpage -= (dev->page_stop - dev->page_start); + + /* Set up packet header. */ + pkthdr[0] = 0x01; /* RXOK - packet is OK */ + if (buf[0] & 0x01) + pkthdr[0] |= 0x20; /* MULTICAST packet */ + pkthdr[1] = nextpage; /* ptr to next packet */ + pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ + pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ + dp8390_log("DP8390: RX pkthdr [%02x %02x %02x %02x]\n", + pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); + + /* Copy into buffer, update curpage, and signal interrupt if config'd */ + startptr = &dev->mem[(dev->curr_page * 256) - dev->mem_start]; + memcpy(startptr, pkthdr, sizeof(pkthdr)); + if ((nextpage > dev->curr_page) || + ((dev->curr_page + pages) == dev->page_stop)) { + memcpy(startptr+sizeof(pkthdr), buf, io_len); + } else { + endbytes = (dev->page_stop - dev->curr_page) * 256; + memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); + startptr = &dev->mem[(dev->page_start * 256) - dev->mem_start]; + memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); + } + dev->curr_page = nextpage; + + dev->RSR.rx_ok = 1; + dev->RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; + dev->ISR.pkt_rx = 1; + + if (dev->IMR.rx_inte && dev->interrupt) + dev->interrupt(dev->priv, 1); +} + + +/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ +uint32_t +dp8390_page0_read(dp8390_t *dev, uint32_t off, unsigned int len) +{ + uint8_t retval = 0; + + if (len > 1) { + /* encountered with win98 hardware probe */ + dp8390_log("DP8390: bad length! Page0 read from register 0x%02x, len=%u\n", + off, len); + return(retval); + } + + switch(off) { + case 0x01: /* CLDA0 */ + retval = (dev->local_dma & 0xff); + break; + + case 0x02: /* CLDA1 */ + retval = (dev->local_dma >> 8); + break; + + case 0x03: /* BNRY */ + retval = dev->bound_ptr; + break; + + case 0x04: /* TSR */ + retval = ((dev->TSR.ow_coll << 7) | + (dev->TSR.cd_hbeat << 6) | + (dev->TSR.fifo_ur << 5) | + (dev->TSR.no_carrier << 4) | + (dev->TSR.aborted << 3) | + (dev->TSR.collided << 2) | + (dev->TSR.tx_ok)); + break; + + case 0x05: /* NCR */ + retval = dev->num_coll; + break; + + case 0x06: /* FIFO */ + /* reading FIFO is only valid in loopback mode */ +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: reading FIFO not supported yet\n"); +#endif + retval = dev->fifo; + break; + + case 0x07: /* ISR */ + retval = ((dev->ISR.reset << 7) | + (dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + break; + + case 0x08: /* CRDA0 */ + retval = (dev->remote_dma & 0xff); + break; + + case 0x09: /* CRDA1 */ + retval = (dev->remote_dma >> 8); + break; + + case 0x0a: /* reserved / RTL8029ID0 */ + retval = dev->id0; + break; + + case 0x0b: /* reserved / RTL8029ID1 */ + retval = dev->id1; + break; + + case 0x0c: /* RSR */ + retval = ((dev->RSR.deferred << 7) | + (dev->RSR.rx_disabled << 6) | + (dev->RSR.rx_mbit << 5) | + (dev->RSR.rx_missed << 4) | + (dev->RSR.fifo_or << 3) | + (dev->RSR.bad_falign << 2) | + (dev->RSR.bad_crc << 1) | + (dev->RSR.rx_ok)); + break; + + case 0x0d: /* CNTR0 */ + retval = dev->tallycnt_0; + break; + + case 0x0e: /* CNTR1 */ + retval = dev->tallycnt_1; + break; + + case 0x0f: /* CNTR2 */ + retval = dev->tallycnt_2; + break; + + default: + dp8390_log("DP8390: Page0 register 0x%02x out of range\n", off); + break; + } + + dp8390_log("DP8390: Page0 read from register 0x%02x, value=0x%02x\n", off, + retval); + + return(retval); +} + + +void +dp8390_page0_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + uint8_t val2; + + dp8390_log("DP839: Page0 write to register 0x%02x, value=0x%02x\n", + off, val); + + switch(off) { + case 0x01: /* PSTART */ + dev->page_start = val; + dp8390_log("DP8390: Starting RAM address: %04X\n", val << 8); + break; + + case 0x02: /* PSTOP */ + dev->page_stop = val; + dp8390_log("DP8390: Stopping RAM address: %04X\n", val << 8); + break; + + case 0x03: /* BNRY */ + dev->bound_ptr = val; + break; + + case 0x04: /* TPSR */ + dev->tx_page_start = val; + break; + + case 0x05: /* TBCR0 */ + /* Clear out low byte and re-insert */ + dev->tx_bytes &= 0xff00; + dev->tx_bytes |= (val & 0xff); + break; + + case 0x06: /* TBCR1 */ + /* Clear out high byte and re-insert */ + dev->tx_bytes &= 0x00ff; + dev->tx_bytes |= ((val & 0xff) << 8); + break; + + case 0x07: /* ISR */ + val &= 0x7f; /* clear RST bit - status-only bit */ + /* All other values are cleared iff the ISR bit is 1 */ + dev->ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); + dev->ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); + dev->ISR.rx_err &= !((int)((val & 0x04) == 0x04)); + dev->ISR.tx_err &= !((int)((val & 0x08) == 0x08)); + dev->ISR.overwrite &= !((int)((val & 0x10) == 0x10)); + dev->ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); + dev->ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); + val = ((dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + val &= ((dev->IMR.rdma_inte << 6) | + (dev->IMR.cofl_inte << 5) | + (dev->IMR.overw_inte << 4) | + (dev->IMR.txerr_inte << 3) | + (dev->IMR.rxerr_inte << 2) | + (dev->IMR.tx_inte << 1) | + (dev->IMR.rx_inte)); + if ((val == 0x00) && dev->interrupt) + dev->interrupt(dev->priv, 0); + break; + + case 0x08: /* RSAR0 */ + /* Clear out low byte and re-insert */ + dev->remote_start &= 0xff00; + dev->remote_start |= (val & 0xff); + dev->remote_dma = dev->remote_start; + break; + + case 0x09: /* RSAR1 */ + /* Clear out high byte and re-insert */ + dev->remote_start &= 0x00ff; + dev->remote_start |= ((val & 0xff) << 8); + dev->remote_dma = dev->remote_start; + break; + + case 0x0a: /* RBCR0 */ + /* Clear out low byte and re-insert */ + dev->remote_bytes &= 0xff00; + dev->remote_bytes |= (val & 0xff); + break; + + case 0x0b: /* RBCR1 */ + /* Clear out high byte and re-insert */ + dev->remote_bytes &= 0x00ff; + dev->remote_bytes |= ((val & 0xff) << 8); + break; + + case 0x0c: /* RCR */ + /* Check if the reserved bits are set */ +#ifdef ENABLE_DP8390_LOG + if (val & 0xc0) + dp8390_log("DP8390: RCR write, reserved bits set\n"); +#endif + + /* Set all other bit-fields */ + dev->RCR.errors_ok = ((val & 0x01) == 0x01); + dev->RCR.runts_ok = ((val & 0x02) == 0x02); + dev->RCR.broadcast = ((val & 0x04) == 0x04); + dev->RCR.multicast = ((val & 0x08) == 0x08); + dev->RCR.promisc = ((val & 0x10) == 0x10); + dev->RCR.monitor = ((val & 0x20) == 0x20); + + /* Monitor bit is a little suspicious... */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x20) + dp8390_log("DP8390: RCR write, monitor bit set!\n"); +#endif + break; + + case 0x0d: /* TCR */ + /* Check reserved bits */ +#ifdef ENABLE_DP8390_LOG + if (val & 0xe0) + dp8390_log("DP8390: TCR write, reserved bits set\n"); +#endif + + /* Test loop mode (not supported) */ + if (val & 0x06) { + dev->TCR.loop_cntl = (val & 0x6) >> 1; + dp8390_log("DP8390: TCR write, loop mode %d not supported\n", + dev->TCR.loop_cntl); + } else + dev->TCR.loop_cntl = 0; + + /* Inhibit-CRC not supported. */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x01) + dp8390_log("DP8390: TCR write, inhibit-CRC not supported\n"); +#endif + + /* Auto-transmit disable very suspicious */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x08) + dp8390_log("DP8390: TCR write, auto transmit disable not supported\n"); +#endif + + /* Allow collision-offset to be set, although not used */ + dev->TCR.coll_prio = ((val & 0x08) == 0x08); + break; + + case 0x0e: /* DCR */ + /* the loopback mode is not suppported yet */ +#ifdef ENABLE_DP8390_LOG + if (! (val & 0x08)) + dp8390_log("DP8390: DCR write, loopback mode selected\n"); +#endif + + /* It is questionable to set longaddr and auto_rx, since + * they are not supported on the NE2000. Print a warning + * and continue. */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x04) + dp8390_log("DP8390: DCR write - LAS set ???\n"); + if (val & 0x10) + dp8390_log("DP8390: DCR write - AR set ???\n"); +#endif + + /* Set other values. */ + dev->DCR.wdsize = ((val & 0x01) == 0x01); + dev->DCR.endian = ((val & 0x02) == 0x02); + dev->DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ + dev->DCR.loop = ((val & 0x08) == 0x08); + dev->DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ + dev->DCR.fifo_size = (val & 0x50) >> 5; + break; + + case 0x0f: /* IMR */ + /* Check for reserved bit */ +#ifdef ENABLE_DP8390_LOG + if (val & 0x80) + dp8390_log("DP8390: IMR write, reserved bit set\n"); +#endif + + /* Set other values */ + dev->IMR.rx_inte = ((val & 0x01) == 0x01); + dev->IMR.tx_inte = ((val & 0x02) == 0x02); + dev->IMR.rxerr_inte = ((val & 0x04) == 0x04); + dev->IMR.txerr_inte = ((val & 0x08) == 0x08); + dev->IMR.overw_inte = ((val & 0x10) == 0x10); + dev->IMR.cofl_inte = ((val & 0x20) == 0x20); + dev->IMR.rdma_inte = ((val & 0x40) == 0x40); + val2 = ((dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + if (dev->interrupt) { + if (((val & val2) & 0x7f) == 0) + dev->interrupt(dev->priv, 0); + else + dev->interrupt(dev->priv, 1); + } + break; + + default: + dp8390_log("DP8390: Page0 write, bad register 0x%02x\n", off); + break; + } +} + + +/* Handle reads/writes to the first page of the DS8390 register file. */ +uint32_t +dp8390_page1_read(dp8390_t *dev, uint32_t off, unsigned int len) +{ + dp8390_log("DP8390: Page1 read from register 0x%02x, len=%u\n", + off, len); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + return(dev->physaddr[off - 1]); + + case 0x07: /* CURR */ + dp8390_log("DP8390: returning current page: 0x%02x\n", + (dev->curr_page)); + return(dev->curr_page); + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + return(dev->mchash[off - 8]); + + default: + dp8390_log("DP8390: Page1 read register 0x%02x out of range\n", + off); + return(0); + } +} + + +void +dp8390_page1_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + dp8390_log("DP8390: Page1 write to register 0x%02x, len=%u, value=0x%04x\n", + off, len, val); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + dev->physaddr[off - 1] = val; + if (off == 6) + dp8390_log("DP8390: Physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->dp8390->physaddr[0], dev->dp8390.physaddr[1], + dev->dp8390->physaddr[2], dev->dp8390.physaddr[3], + dev->dp8390->physaddr[4], dev->dp8390.physaddr[5]); + break; + + case 0x07: /* CURR */ + dev->curr_page = val; + break; + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + dev->mchash[off - 8] = val; + break; + + default: + dp8390_log("DP8390: Page1 write register 0x%02x out of range\n", + off); + break; + } +} + + +/* Handle reads/writes to the second page of the DS8390 register file. */ +uint32_t +dp8390_page2_read(dp8390_t *dev, uint32_t off, unsigned int len) +{ + dp8390_log("DP8390: Page2 read from register 0x%02x, len=%u\n", + off, len); + + switch(off) { + case 0x01: /* PSTART */ + return(dev->page_start); + + case 0x02: /* PSTOP */ + return(dev->page_stop); + + case 0x03: /* Remote Next-packet pointer */ + return(dev->rempkt_ptr); + + case 0x04: /* TPSR */ + return(dev->tx_page_start); + + case 0x05: /* Local Next-packet pointer */ + return(dev->localpkt_ptr); + + case 0x06: /* Address counter (upper) */ + return(dev->address_cnt >> 8); + + case 0x07: /* Address counter (lower) */ + return(dev->address_cnt & 0xff); + + case 0x08: /* Reserved */ + case 0x09: + case 0x0a: + case 0x0b: + dp8390_log("DP8390: reserved Page2 read - register 0x%02x\n", + off); + return(0xff); + + case 0x0c: /* RCR */ + return ((dev->RCR.monitor << 5) | + (dev->RCR.promisc << 4) | + (dev->RCR.multicast << 3) | + (dev->RCR.broadcast << 2) | + (dev->RCR.runts_ok << 1) | + (dev->RCR.errors_ok)); + + case 0x0d: /* TCR */ + return ((dev->TCR.coll_prio << 4) | + (dev->TCR.ext_stoptx << 3) | + ((dev->TCR.loop_cntl & 0x3) << 1) | + (dev->TCR.crc_disable)); + + case 0x0e: /* DCR */ + return (((dev->DCR.fifo_size & 0x3) << 5) | + (dev->DCR.auto_rx << 4) | + (dev->DCR.loop << 3) | + (dev->DCR.longaddr << 2) | + (dev->DCR.endian << 1) | + (dev->DCR.wdsize)); + + case 0x0f: /* IMR */ + return ((dev->IMR.rdma_inte << 6) | + (dev->IMR.cofl_inte << 5) | + (dev->IMR.overw_inte << 4) | + (dev->IMR.txerr_inte << 3) | + (dev->IMR.rxerr_inte << 2) | + (dev->IMR.tx_inte << 1) | + (dev->IMR.rx_inte)); + + default: + dp8390_log("DP8390: Page2 register 0x%02x out of range\n", + off); + break; + } + + return(0); +} + + +void +dp8390_page2_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len) +{ +/* Maybe all writes here should be BX_PANIC()'d, since they + affect internal operation, but let them through for now + and print a warning. */ + dp8390_log("DP8390: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", + off, len, val); + + switch(off) { + case 0x01: /* CLDA0 */ + /* Clear out low byte and re-insert */ + dev->local_dma &= 0xff00; + dev->local_dma |= (val & 0xff); + break; + + case 0x02: /* CLDA1 */ + /* Clear out high byte and re-insert */ + dev->local_dma &= 0x00ff; + dev->local_dma |= ((val & 0xff) << 8); + break; + + case 0x03: /* Remote Next-pkt pointer */ + dev->rempkt_ptr = val; + break; + + case 0x04: +#ifdef ENABLE_DP8390_LOG + dp8390_log("DP8390: Page 2 write to reserved register 0x04\n"); +#endif + break; + + case 0x05: /* Local Next-packet pointer */ + dev->localpkt_ptr = val; + break; + + case 0x06: /* Address counter (upper) */ + /* Clear out high byte and re-insert */ + dev->address_cnt &= 0x00ff; + dev->address_cnt |= ((val & 0xff) << 8); + break; + + case 0x07: /* Address counter (lower) */ + /* Clear out low byte and re-insert */ + dev->address_cnt &= 0xff00; + dev->address_cnt |= (val & 0xff); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + dp8390_log("DP8390: Page2 write to reserved register 0x%02x\n", + off); + break; + + default: + dp8390_log("DP8390: Page2 write, illegal register 0x%02x\n", + off); + break; + } +} + + +void +dp8390_set_defaults(dp8390_t *dev, uint8_t flags) +{ + dev->macaddr_size = (flags & DP8390_FLAG_EVEN_MAC) ? 32 : 16; + + dev->flags = flags; +} + + +void +dp8390_mem_alloc(dp8390_t *dev, uint32_t start, uint32_t size) +{ + dev->mem = (uint8_t *) malloc(size * sizeof(uint8_t)); + memset(dev->mem, 0, size * sizeof(uint8_t)); + dev->mem_start = start; + dev->mem_end = start + size; + dev->mem_size = size; + dp8390_log("DP8390: Mapped %i bytes of memory at address %04X in the address space\n", size, start); +} + + +void +dp8390_set_id(dp8390_t *dev, uint8_t id0, uint8_t id1) +{ + dev->id0 = id0; + dev->id1 = id1; +} + + +void +dp8390_reset(dp8390_t *dev) +{ + int i, max, shift = 0; + + if (dev->flags & DP8390_FLAG_EVEN_MAC) + shift = 1; + + max = 16 << shift; + + /* Initialize the MAC address area by doubling the physical address */ + for (i = 0; i < max; i++) { + if (i < (6 << shift)) + dev->macaddr[i] = dev->physaddr[i >> shift]; + else /* Signature */ + dev->macaddr[i] = 0x57; + } + + /* Zero out registers and memory */ + memset(&dev->CR, 0x00, sizeof(dev->CR) ); + memset(&dev->ISR, 0x00, sizeof(dev->ISR)); + memset(&dev->IMR, 0x00, sizeof(dev->IMR)); + memset(&dev->DCR, 0x00, sizeof(dev->DCR)); + memset(&dev->TCR, 0x00, sizeof(dev->TCR)); + memset(&dev->TSR, 0x00, sizeof(dev->TSR)); + memset(&dev->RSR, 0x00, sizeof(dev->RSR)); + dev->tx_timer_active = 0; + dev->local_dma = 0; + dev->page_start = 0; + dev->page_stop = 0; + dev->bound_ptr = 0; + dev->tx_page_start = 0; + dev->num_coll = 0; + dev->tx_bytes = 0; + dev->fifo = 0; + dev->remote_dma = 0; + dev->remote_start = 0; + + dev->remote_bytes = 0; + + dev->tallycnt_0 = 0; + dev->tallycnt_1 = 0; + dev->tallycnt_2 = 0; + + dev->curr_page = 0; + + dev->rempkt_ptr = 0; + dev->localpkt_ptr = 0; + dev->address_cnt = 0; + + memset(dev->mem, 0x00, dev->mem_size); + + /* Set power-up conditions */ + dev->CR.stop = 1; + dev->CR.rdma_cmd = 4; + dev->ISR.reset = 1; + dev->DCR.longaddr = 1; + + if (dev->interrupt) + dev->interrupt(dev->priv, 0); +} + + +void +dp8390_soft_reset(dp8390_t *dev) +{ + memset(&(dev->ISR), 0x00, sizeof(dev->ISR)); + dev->ISR.reset = 1; +} + + +static void * +dp8390_init(const device_t *info) +{ + dp8390_t *dp8390 = (dp8390_t *) malloc(sizeof(dp8390_t)); + memset(dp8390, 0, sizeof(dp8390_t)); + + /* Set values assuming WORD and only the clear IRQ flag - + - the NIC can then call dp8390_set_defaults() again to + change that. */ + dp8390_set_defaults(dp8390, DP8390_FLAG_CLEAR_IRQ); + + /* Set the two registers some NIC's use as ID bytes, + to their default values of 0xFF. */ + dp8390_set_id(dp8390, 0xff, 0xff); + + return dp8390; +} + + +static void +dp8390_close(void *priv) +{ + dp8390_t *dp8390 = (dp8390_t *) priv; + + /* Make sure the platform layer is shut down. */ + network_close(); + + if (dp8390) { + if (dp8390->mem) + free(dp8390->mem); + + free(dp8390); + } +} + + +const device_t dp8390_device = +{ + "DP8390 Network Interface Controller", + 0, 0, + dp8390_init, dp8390_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/network/net_dp8390.h b/src/network/net_dp8390.h index 16b2d0188..313538b5a 100644 --- a/src/network/net_dp8390.h +++ b/src/network/net_dp8390.h @@ -1,3 +1,21 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Header of the emulation of the DP8390 Network Interface + * Controller used by the WD family, NE1000/NE2000 family, and + * 3Com 3C503 NIC's. + * + * Version: @(#)net_dp8390.h 1.0.1 2018/10/20 + * + * Authors: Miran Grca, + * Bochs project, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Bochs project. + */ #ifndef NET_DP8390_H # define NET_DP8390_H @@ -13,6 +31,10 @@ #define DP8390_WORD_MEMSTART (8*1024) #define DP8390_WORD_MEMEND (DP8390_WORD_MEMSTART+DP8390_WORD_MEMSIZ) +#define DP8390_FLAG_EVEN_MAC 0x01 +#define DP8390_FLAG_CHECK_CR 0x02 +#define DP8390_FLAG_CLEAR_IRQ 0x04 + typedef struct { /* Page 0 */ @@ -145,14 +167,49 @@ typedef struct { /* Page 3 - should never be modified. */ - /* Novell ASIC state */ - uint8_t mem[DP8390_DWORD_MEMSIZ]; /* on-chip packet memory */ - + /* DP8390 memory */ + uint8_t *mem; /* on-chip packet memory */ + + uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ + uint8_t macaddr_size, /* Defaults to 16 but can be 32 */ + flags, /* Flags affecting some behaviors. */ + id0, /* 0x50 for the Realtek NIC's, otherwise + 0xFF. */ + id1; /* 0x70 for the RTL8019AS, 0x43 for the + RTL8029AS, otherwise 0xFF. */ + int mem_size, mem_start, mem_end; + int tx_timer_index; int tx_timer_active; - + + void *priv; + + void (*interrupt)(void *priv, int set); } dp8390_t; -extern int mcast_index(const void *dst); +extern const device_t dp8390_device; + + +extern uint32_t dp8390_chipmem_read(dp8390_t *dev, uint32_t addr, unsigned int len); +extern void dp8390_chipmem_write(dp8390_t *dev, uint32_t addr, uint32_t val, unsigned len); + +extern uint32_t dp8390_read_cr(dp8390_t *dev); +extern void dp8390_write_cr(dp8390_t *dev, uint32_t val); + +extern void dp8390_rx(void *priv, uint8_t *buf, int io_len); + +extern uint32_t dp8390_page0_read(dp8390_t *dev, uint32_t off, unsigned int len); +extern void dp8390_page0_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len); +extern uint32_t dp8390_page1_read(dp8390_t *dev, uint32_t off, unsigned int len); +extern void dp8390_page1_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len); +extern uint32_t dp8390_page2_read(dp8390_t *dev, uint32_t off, unsigned int len); +extern void dp8390_page2_write(dp8390_t *dev, uint32_t off, uint32_t val, unsigned len); + +extern void dp8390_set_defaults(dp8390_t *dev, uint8_t flags); +extern void dp8390_mem_alloc(dp8390_t *dev, uint32_t start, uint32_t size); +extern void dp8390_set_id(dp8390_t *dev, uint8_t id0, uint8_t id1); +extern void dp8390_reset(dp8390_t *dev); +extern void dp8390_soft_reset(dp8390_t *dev); + #endif /*NET_DP8390_H*/ diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 3860149f4..0fd45626c 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -9,10 +9,11 @@ * Implementation of the following network controllers: * - Novell NE1000 (ISA 8-bit); * - Novell NE2000 (ISA 16-bit); + * - Novell NE/2 compatible (NetWorth Inc. Ethernext/MC) (MCA 16-bit); * - Realtek RTL8019AS (ISA 16-bit, PnP); * - Realtek RTL8029AS (PCI). * - * Version: @(#)net_ne2000.c 1.0.7 2018/07/24 + * Version: @(#)net_ne2000.c 1.0.11 2018/10/20 * * Based on @(#)ne2k.cc v1.56.2.1 2004/02/02 22:37:22 cbothamy * @@ -52,8 +53,6 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../config.h" -#include "../machine/machine.h" #include "../io.h" #include "../mem.h" #include "../rom.h" @@ -62,7 +61,6 @@ #include "../pic.h" #include "../random.h" #include "../device.h" -#include "../ui.h" #include "network.h" #include "net_dp8390.h" #include "net_ne2000.h" @@ -97,25 +95,23 @@ uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE, typedef struct { - dp8390_t dp8390; - uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ + dp8390_t *dp8390; + const char *name; int board; int is_pci, is_mca, is_8bit; - const char *name; uint32_t base_address; int base_irq; uint32_t bios_addr, bios_size, bios_mask; + int card; /* PCI card slot */ + int has_bios, pad; uint8_t pnp_regs[256]; uint8_t pnp_res_data[256]; bar_t pci_bar[2]; uint8_t pci_regs[PCI_REGSIZE]; - uint8_t maclocal[6]; /* configured MAC (local) address */ uint8_t eeprom[128]; /* for RTL8029AS */ rom_t bios_rom; - int card; /* PCI card slot */ - int has_bios; uint8_t pnp_phase; uint8_t pnp_magic_count; uint8_t pnp_address; @@ -124,33 +120,30 @@ typedef struct { uint8_t pnp_activate; uint8_t pnp_io_check; uint8_t pnp_csnsav; - uint16_t pnp_read; - uint64_t pnp_id; uint8_t pnp_id_checksum; uint8_t pnp_serial_read_pos; uint8_t pnp_serial_read_pair; uint8_t pnp_serial_read; + uint8_t maclocal[6]; /* configured MAC (local) address */ + uint16_t pnp_read; + uint64_t pnp_id; /* RTL8019AS/RTL8029AS registers */ uint8_t config0, config2, config3; uint8_t _9346cr; - - /* POS registers, MCA boards only */ - uint8_t pos_regs[8]; + uint32_t pad0; + + /* POS registers, MCA boards only */ + uint8_t pos_regs[8]; } nic_t; -static void nic_rx(void *, uint8_t *, int); -static void nic_tx(nic_t *, uint32_t); - #ifdef ENABLE_NIC_LOG int nic_do_log = ENABLE_NIC_LOG; -#endif static void nelog(int lvl, const char *fmt, ...) { -#ifdef ENABLE_NIC_LOG va_list ap; if (nic_do_log >= lvl) { @@ -158,14 +151,18 @@ nelog(int lvl, const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define nelog(lvl, fmt, ...) +#endif static void -nic_interrupt(nic_t *dev, int set) +nic_interrupt(void *priv, int set) { - if (PCI && dev->is_pci) { + nic_t *dev = (nic_t *) priv; + + if (dev->is_pci) { if (set) pci_set_irq(dev->card, PCI_INTA); else @@ -184,86 +181,10 @@ static void nic_reset(void *priv) { nic_t *dev = (nic_t *)priv; - int i; nelog(1, "%s: reset\n", dev->name); - if (dev->board == NE2K_NE1000) - { - /* Initialize the MAC address area by doubling the physical address */ - dev->macaddr[0] = dev->dp8390.physaddr[0]; - dev->macaddr[1] = dev->dp8390.physaddr[1]; - dev->macaddr[2] = dev->dp8390.physaddr[2]; - dev->macaddr[3] = dev->dp8390.physaddr[3]; - dev->macaddr[4] = dev->dp8390.physaddr[4]; - dev->macaddr[5] = dev->dp8390.physaddr[5]; - - /* ne1k signature */ - for (i=6; i<16; i++) - dev->macaddr[i] = 0x57; - } - else - { - /* Initialize the MAC address area by doubling the physical address */ - dev->macaddr[0] = dev->dp8390.physaddr[0]; - dev->macaddr[1] = dev->dp8390.physaddr[0]; - dev->macaddr[2] = dev->dp8390.physaddr[1]; - dev->macaddr[3] = dev->dp8390.physaddr[1]; - dev->macaddr[4] = dev->dp8390.physaddr[2]; - dev->macaddr[5] = dev->dp8390.physaddr[2]; - dev->macaddr[6] = dev->dp8390.physaddr[3]; - dev->macaddr[7] = dev->dp8390.physaddr[3]; - dev->macaddr[8] = dev->dp8390.physaddr[4]; - dev->macaddr[9] = dev->dp8390.physaddr[4]; - dev->macaddr[10] = dev->dp8390.physaddr[5]; - dev->macaddr[11] = dev->dp8390.physaddr[5]; - - /* ne2k signature */ - for (i=12; i<32; i++) - dev->macaddr[i] = 0x57; - } - - /* Zero out registers and memory */ - memset(&dev->dp8390.CR, 0x00, sizeof(dev->dp8390.CR) ); - memset(&dev->dp8390.ISR, 0x00, sizeof(dev->dp8390.ISR)); - memset(&dev->dp8390.IMR, 0x00, sizeof(dev->dp8390.IMR)); - memset(&dev->dp8390.DCR, 0x00, sizeof(dev->dp8390.DCR)); - memset(&dev->dp8390.TCR, 0x00, sizeof(dev->dp8390.TCR)); - memset(&dev->dp8390.TSR, 0x00, sizeof(dev->dp8390.TSR)); - memset(&dev->dp8390.RSR, 0x00, sizeof(dev->dp8390.RSR)); - dev->dp8390.tx_timer_active = 0; - dev->dp8390.local_dma = 0; - dev->dp8390.page_start = 0; - dev->dp8390.page_stop = 0; - dev->dp8390.bound_ptr = 0; - dev->dp8390.tx_page_start = 0; - dev->dp8390.num_coll = 0; - dev->dp8390.tx_bytes = 0; - dev->dp8390.fifo = 0; - dev->dp8390.remote_dma = 0; - dev->dp8390.remote_start = 0; - - dev->dp8390.remote_bytes = 0; - - dev->dp8390.tallycnt_0 = 0; - dev->dp8390.tallycnt_1 = 0; - dev->dp8390.tallycnt_2 = 0; - - dev->dp8390.curr_page = 0; - - dev->dp8390.rempkt_ptr = 0; - dev->dp8390.localpkt_ptr = 0; - dev->dp8390.address_cnt = 0; - - memset(&dev->dp8390.mem, 0x00, sizeof(dev->dp8390.mem)); - - /* Set power-up conditions */ - dev->dp8390.CR.stop = 1; - dev->dp8390.CR.rdma_cmd = 4; - dev->dp8390.ISR.reset = 1; - dev->dp8390.DCR.longaddr = 1; - - nic_interrupt(dev, 0); + dp8390_reset(dev->dp8390); } @@ -272,123 +193,7 @@ nic_soft_reset(void *priv) { nic_t *dev = (nic_t *)priv; - memset(&(dev->dp8390.ISR), 0x00, sizeof(dev->dp8390.ISR)); - dev->dp8390.ISR.reset = 1; -} - - -/* - * Access the 32K 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 contain the MAC address at even locations, - * and there is 16K of buffer memory starting at 16K. - */ -static uint32_t -chipmem_read(nic_t *dev, uint32_t addr, unsigned int len) -{ - uint32_t retval = 0; - - if ((len == 2) && (addr & 0x1)) { - nelog(3, "%s: unaligned chipmem word read\n", dev->name); - } - - nelog(3, "Chipmem Read Address=%04x\n", addr); - - /* ROM'd MAC address */ - if (dev->board != NE2K_NE1000) { - if (addr <= 31) { - retval = dev->macaddr[addr % 32]; - if ((len == 2) || (len == 4)) { - retval |= (dev->macaddr[(addr + 1) % 32] << 8); - } - if (len == 4) { - retval |= (dev->macaddr[(addr + 2) % 32] << 16); - retval |= (dev->macaddr[(addr + 3) % 32] << 24); - } - return(retval); - } - - if ((addr >= DP8390_DWORD_MEMSTART) && (addr < DP8390_DWORD_MEMEND)) { - retval = dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART]; - if ((len == 2) || (len == 4)) { - retval |= (dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART + 1] << 8); - } - if (len == 4) { - retval |= (dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART + 2] << 16); - retval |= (dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART + 3] << 24); - } - return(retval); - } - } else { - if (addr <= 15) { - retval = dev->macaddr[addr % 16]; - if (len == 2) { - retval |= (dev->macaddr[(addr + 1) % 16] << 8); - } - return(retval); - } - - if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) { - retval = dev->dp8390.mem[addr - DP8390_WORD_MEMSTART]; - if (len == 2) { - retval |= (dev->dp8390.mem[addr - DP8390_WORD_MEMSTART + 1] << 8); - } - return(retval); - } - } - - nelog(3, "%s: out-of-bounds chipmem read, %04X\n", dev->name, addr); - - if (dev->is_pci) { - return(0xff); - } else { - switch(len) { - case 1: - return(0xff); - case 2: - return(0xffff); - } - } - - return(0xffff); -} - - -static void -chipmem_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) -{ - if ((len == 2) && (addr & 0x1)) { - nelog(3, "%s: unaligned chipmem word write\n", dev->name); - } - - nelog(3, "Chipmem Write Address=%04x\n", addr); - - if (dev->board != NE2K_NE1000) { - if ((addr >= DP8390_DWORD_MEMSTART) && (addr < DP8390_DWORD_MEMEND)) { - dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART] = val & 0xff; - if ((len == 2) || (len == 4)) { - dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART+1] = val >> 8; - } - if (len == 4) { - dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART+2] = val >> 16; - dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART+3] = val >> 24; - } - } else { - nelog(3, "%s: out-of-bounds chipmem write, %04X\n", dev->name, addr); - } - } else { - if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) { - dev->dp8390.mem[addr-DP8390_WORD_MEMSTART] = val & 0xff; - if (len == 2) { - dev->dp8390.mem[addr-DP8390_WORD_MEMSTART+1] = val >> 8; - } - } else { - nelog(3, "%s: out-of-bounds chipmem write, %04X\n", dev->name, addr); - } - } + dp8390_soft_reset(dev->dp8390); } @@ -415,43 +220,43 @@ asic_read(nic_t *dev, uint32_t off, unsigned int len) /* A read remote-DMA command must have been issued, and the source-address and length registers must have been initialised. */ - if (len > dev->dp8390.remote_bytes) { + if (len > dev->dp8390->remote_bytes) { nelog(3, "%s: DMA read underrun iolen=%d remote_bytes=%d\n", - dev->name, len, dev->dp8390.remote_bytes); + dev->name, len, dev->dp8390->remote_bytes); } nelog(3, "%s: DMA read: addr=%4x remote_bytes=%d\n", - dev->name, dev->dp8390.remote_dma,dev->dp8390.remote_bytes); - retval = chipmem_read(dev, dev->dp8390.remote_dma, len); + dev->name, dev->dp8390->remote_dma,dev->dp8390->remote_bytes); + retval = dp8390_chipmem_read(dev->dp8390, dev->dp8390->remote_dma, len); /* 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). */ if (len == 4) { - dev->dp8390.remote_dma += len; + dev->dp8390->remote_dma += len; } else { - dev->dp8390.remote_dma += (dev->dp8390.DCR.wdsize + 1); + dev->dp8390->remote_dma += (dev->dp8390->DCR.wdsize + 1); } - if (dev->dp8390.remote_dma == dev->dp8390.page_stop << 8) { - dev->dp8390.remote_dma = dev->dp8390.page_start << 8; + if (dev->dp8390->remote_dma == dev->dp8390->page_stop << 8) { + dev->dp8390->remote_dma = dev->dp8390->page_start << 8; } /* keep s.remote_bytes from underflowing */ - if (dev->dp8390.remote_bytes > dev->dp8390.DCR.wdsize) { + if (dev->dp8390->remote_bytes > dev->dp8390->DCR.wdsize) { if (len == 4) { - dev->dp8390.remote_bytes -= len; + dev->dp8390->remote_bytes -= len; } else { - dev->dp8390.remote_bytes -= (dev->dp8390.DCR.wdsize + 1); + dev->dp8390->remote_bytes -= (dev->dp8390->DCR.wdsize + 1); } } else { - dev->dp8390.remote_bytes = 0; + dev->dp8390->remote_bytes = 0; } /* If all bytes have been written, signal remote-DMA complete */ - if (dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) + if (dev->dp8390->remote_bytes == 0) { + dev->dp8390->ISR.rdma_done = 1; + if (dev->dp8390->IMR.rdma_inte) nic_interrupt(dev, 1); } break; @@ -459,25 +264,6 @@ asic_read(nic_t *dev, uint32_t off, unsigned int len) case 0x0f: /* Reset register */ nic_soft_reset(dev); break; - - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: - retval = 0; - break; default: nelog(3, "%s: ASIC read invalid address %04x\n", @@ -496,60 +282,42 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) switch(off) { case 0x00: /* Data register - see asic_read for a description */ - if ((len > 1) && (dev->dp8390.DCR.wdsize == 0)) { + if ((len > 1) && (dev->dp8390->DCR.wdsize == 0)) { nelog(3, "%s: DMA write length %d on byte mode operation\n", dev->name, len); break; } - if (dev->dp8390.remote_bytes == 0) + if (dev->dp8390->remote_bytes == 0) nelog(3, "%s: DMA write, byte count 0\n", dev->name); - chipmem_write(dev, dev->dp8390.remote_dma, val, len); + dp8390_chipmem_write(dev->dp8390, dev->dp8390->remote_dma, val, len); if (len == 4) - dev->dp8390.remote_dma += len; - else - dev->dp8390.remote_dma += (dev->dp8390.DCR.wdsize + 1); + dev->dp8390->remote_dma += len; + else + dev->dp8390->remote_dma += (dev->dp8390->DCR.wdsize + 1); - if (dev->dp8390.remote_dma == dev->dp8390.page_stop << 8) - dev->dp8390.remote_dma = dev->dp8390.page_start << 8; + if (dev->dp8390->remote_dma == dev->dp8390->page_stop << 8) + dev->dp8390->remote_dma = dev->dp8390->page_start << 8; if (len == 4) - dev->dp8390.remote_bytes -= len; - else - dev->dp8390.remote_bytes -= (dev->dp8390.DCR.wdsize + 1); + dev->dp8390->remote_bytes -= len; + else + dev->dp8390->remote_bytes -= (dev->dp8390->DCR.wdsize + 1); - if (dev->dp8390.remote_bytes > DP8390_DWORD_MEMSIZ) - dev->dp8390.remote_bytes = 0; + if (dev->dp8390->remote_bytes > dev->dp8390->mem_size) + dev->dp8390->remote_bytes = 0; /* If all bytes have been written, signal remote-DMA complete */ - if (dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) + if (dev->dp8390->remote_bytes == 0) { + dev->dp8390->ISR.rdma_done = 1; + if (dev->dp8390->IMR.rdma_inte) nic_interrupt(dev, 1); } break; case 0x0f: /* Reset register */ /* end of reset pulse */ - break; - - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: - break; + break; default: /* this is invalid, but happens under win95 device detection */ nelog(3, "%s: ASIC write invalid address %04x, ignoring\n", @@ -559,550 +327,6 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) } -/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ -static uint32_t -page0_read(nic_t *dev, uint32_t off, unsigned int len) -{ - uint8_t retval = 0; - - if (len > 1) { - /* encountered with win98 hardware probe */ - nelog(3, "%s: bad length! Page0 read from register 0x%02x, len=%u\n", - dev->name, off, len); - return(retval); - } - - switch(off) { - case 0x01: /* CLDA0 */ - retval = (dev->dp8390.local_dma & 0xff); - break; - - case 0x02: /* CLDA1 */ - retval = (dev->dp8390.local_dma >> 8); - break; - - case 0x03: /* BNRY */ - retval = dev->dp8390.bound_ptr; - break; - - case 0x04: /* TSR */ - retval = ((dev->dp8390.TSR.ow_coll << 7) | - (dev->dp8390.TSR.cd_hbeat << 6) | - (dev->dp8390.TSR.fifo_ur << 5) | - (dev->dp8390.TSR.no_carrier << 4) | - (dev->dp8390.TSR.aborted << 3) | - (dev->dp8390.TSR.collided << 2) | - (dev->dp8390.TSR.tx_ok)); - break; - - case 0x05: /* NCR */ - retval = dev->dp8390.num_coll; - break; - - case 0x06: /* FIFO */ - /* reading FIFO is only valid in loopback mode */ - nelog(3, "%s: reading FIFO not supported yet\n", dev->name); - retval = dev->dp8390.fifo; - break; - - case 0x07: /* ISR */ - retval = ((dev->dp8390.ISR.reset << 7) | - (dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - break; - - case 0x08: /* CRDA0 */ - retval = (dev->dp8390.remote_dma & 0xff); - break; - - case 0x09: /* CRDA1 */ - retval = (dev->dp8390.remote_dma >> 8); - break; - - case 0x0a: /* reserved / RTL8029ID0 */ - if (dev->board == NE2K_RTL8019AS) { - retval = 0x50; - } else if (dev->board == NE2K_RTL8029AS) { - retval = 0x50; - } else { - nelog(3, "%s: reserved Page0 read - 0x0a\n", dev->name); - retval = 0xff; - } - break; - - case 0x0b: /* reserved / RTL8029ID1 */ - if (dev->board == NE2K_RTL8019AS) { - retval = 0x70; - } else if (dev->board == NE2K_RTL8029AS) { - retval = 0x43; - } else { - nelog(3, "%s: reserved Page0 read - 0x0b\n", dev->name); - retval = 0xff; - } - break; - - case 0x0c: /* RSR */ - retval = ((dev->dp8390.RSR.deferred << 7) | - (dev->dp8390.RSR.rx_disabled << 6) | - (dev->dp8390.RSR.rx_mbit << 5) | - (dev->dp8390.RSR.rx_missed << 4) | - (dev->dp8390.RSR.fifo_or << 3) | - (dev->dp8390.RSR.bad_falign << 2) | - (dev->dp8390.RSR.bad_crc << 1) | - (dev->dp8390.RSR.rx_ok)); - break; - - case 0x0d: /* CNTR0 */ - retval = dev->dp8390.tallycnt_0; - break; - - case 0x0e: /* CNTR1 */ - retval = dev->dp8390.tallycnt_1; - break; - - case 0x0f: /* CNTR2 */ - retval = dev->dp8390.tallycnt_2; - break; - - default: - nelog(3, "%s: Page0 register 0x%02x out of range\n", - dev->name, off); - break; - } - - nelog(3, "%s: Page0 read from register 0x%02x, value=0x%02x\n", - dev->name, off, retval); - - return(retval); -} - - -static void -page0_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - uint8_t val2; - - nelog(3, "%s: Page0 write to register 0x%02x, value=0x%02x\n", - dev->name, off, val); - - switch(off) { - case 0x01: /* PSTART */ - dev->dp8390.page_start = val; - break; - - case 0x02: /* PSTOP */ - dev->dp8390.page_stop = val; - break; - - case 0x03: /* BNRY */ - dev->dp8390.bound_ptr = val; - break; - - case 0x04: /* TPSR */ - dev->dp8390.tx_page_start = val; - break; - - case 0x05: /* TBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.tx_bytes &= 0xff00; - dev->dp8390.tx_bytes |= (val & 0xff); - break; - - case 0x06: /* TBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.tx_bytes &= 0x00ff; - dev->dp8390.tx_bytes |= ((val & 0xff) << 8); - break; - - case 0x07: /* ISR */ - val &= 0x7f; /* clear RST bit - status-only bit */ - /* All other values are cleared iff the ISR bit is 1 */ - dev->dp8390.ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); - dev->dp8390.ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); - dev->dp8390.ISR.rx_err &= !((int)((val & 0x04) == 0x04)); - dev->dp8390.ISR.tx_err &= !((int)((val & 0x08) == 0x08)); - dev->dp8390.ISR.overwrite &= !((int)((val & 0x10) == 0x10)); - dev->dp8390.ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); - dev->dp8390.ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); - val = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - val &= ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - if (val == 0x00) - nic_interrupt(dev, 0); - break; - - case 0x08: /* RSAR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_start &= 0xff00; - dev->dp8390.remote_start |= (val & 0xff); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x09: /* RSAR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_start &= 0x00ff; - dev->dp8390.remote_start |= ((val & 0xff) << 8); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x0a: /* RBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_bytes &= 0xff00; - dev->dp8390.remote_bytes |= (val & 0xff); - break; - - case 0x0b: /* RBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_bytes &= 0x00ff; - dev->dp8390.remote_bytes |= ((val & 0xff) << 8); - break; - - case 0x0c: /* RCR */ - /* Check if the reserved bits are set */ - if (val & 0xc0) { - nelog(3, "%s: RCR write, reserved bits set\n", - dev->name); - } - - /* Set all other bit-fields */ - dev->dp8390.RCR.errors_ok = ((val & 0x01) == 0x01); - dev->dp8390.RCR.runts_ok = ((val & 0x02) == 0x02); - dev->dp8390.RCR.broadcast = ((val & 0x04) == 0x04); - dev->dp8390.RCR.multicast = ((val & 0x08) == 0x08); - dev->dp8390.RCR.promisc = ((val & 0x10) == 0x10); - dev->dp8390.RCR.monitor = ((val & 0x20) == 0x20); - - /* Monitor bit is a little suspicious... */ - if (val & 0x20) nelog(3, "%s: RCR write, monitor bit set!\n", - dev->name); - break; - - case 0x0d: /* TCR */ - /* Check reserved bits */ - if (val & 0xe0) nelog(3, "%s: TCR write, reserved bits set\n", - dev->name); - - /* Test loop mode (not supported) */ - if (val & 0x06) { - dev->dp8390.TCR.loop_cntl = (val & 0x6) >> 1; - nelog(3, "%s: TCR write, loop mode %d not supported\n", - dev->name, dev->dp8390.TCR.loop_cntl); - } else { - dev->dp8390.TCR.loop_cntl = 0; - } - - /* Inhibit-CRC not supported. */ - if (val & 0x01) nelog(3, - "%s: TCR write, inhibit-CRC not supported\n",dev->name); - - /* Auto-transmit disable very suspicious */ - if (val & 0x08) nelog(3, - "%s: TCR write, auto transmit disable not supported\n", - dev->name); - - /* Allow collision-offset to be set, although not used */ - dev->dp8390.TCR.coll_prio = ((val & 0x08) == 0x08); - break; - - case 0x0e: /* DCR */ - /* the loopback mode is not suppported yet */ - if (! (val & 0x08)) nelog(3, - "%s: DCR write, loopback mode selected\n", dev->name); - - /* It is questionable to set longaddr and auto_rx, since - * they are not supported on the NE2000. Print a warning - * and continue. */ - if (val & 0x04) - nelog(3, "%s: DCR write - LAS set ???\n", dev->name); - if (val & 0x10) - nelog(3, "%s: DCR write - AR set ???\n", dev->name); - - /* Set other values. */ - dev->dp8390.DCR.wdsize = ((val & 0x01) == 0x01); - dev->dp8390.DCR.endian = ((val & 0x02) == 0x02); - dev->dp8390.DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ - dev->dp8390.DCR.loop = ((val & 0x08) == 0x08); - dev->dp8390.DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ - dev->dp8390.DCR.fifo_size = (val & 0x50) >> 5; - break; - - case 0x0f: /* IMR */ - /* Check for reserved bit */ - if (val & 0x80) - nelog(3, "%s: IMR write, reserved bit set\n",dev->name); - - /* Set other values */ - dev->dp8390.IMR.rx_inte = ((val & 0x01) == 0x01); - dev->dp8390.IMR.tx_inte = ((val & 0x02) == 0x02); - dev->dp8390.IMR.rxerr_inte = ((val & 0x04) == 0x04); - dev->dp8390.IMR.txerr_inte = ((val & 0x08) == 0x08); - dev->dp8390.IMR.overw_inte = ((val & 0x10) == 0x10); - dev->dp8390.IMR.cofl_inte = ((val & 0x20) == 0x20); - dev->dp8390.IMR.rdma_inte = ((val & 0x40) == 0x40); - val2 = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - if (((val & val2) & 0x7f) == 0) - nic_interrupt(dev, 0); - else - nic_interrupt(dev, 1); - break; - - default: - nelog(3, "%s: Page0 write, bad register 0x%02x\n", - dev->name, off); - break; - } -} - - -/* Handle reads/writes to the first page of the DS8390 register file. */ -static uint32_t -page1_read(nic_t *dev, uint32_t off, unsigned int len) -{ - nelog(3, "%s: Page1 read from register 0x%02x, len=%u\n", - dev->name, off, len); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - return(dev->dp8390.physaddr[off - 1]); - - case 0x07: /* CURR */ - nelog(3, "%s: returning current page: 0x%02x\n", - dev->name, (dev->dp8390.curr_page)); - return(dev->dp8390.curr_page); - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - return(dev->dp8390.mchash[off - 8]); - - default: - nelog(3, "%s: Page1 read register 0x%02x out of range\n", - dev->name, off); - return(0); - } -} - - -static void -page1_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) -{ - nelog(3, "%s: Page1 write to register 0x%02x, len=%u, value=0x%04x\n", - dev->name, off, len, val); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - dev->dp8390.physaddr[off - 1] = val; - if (off == 6) nelog(3, - "%s: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], - dev->dp8390.physaddr[2], dev->dp8390.physaddr[3], - dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); - break; - - case 0x07: /* CURR */ - dev->dp8390.curr_page = val; - break; - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - dev->dp8390.mchash[off - 8] = val; - break; - - default: - nelog(3, "%s: Page1 write register 0x%02x out of range\n", - dev->name, off); - break; - } -} - - -/* Handle reads/writes to the second page of the DS8390 register file. */ -static uint32_t -page2_read(nic_t *dev, uint32_t off, unsigned int len) -{ - nelog(3, "%s: Page2 read from register 0x%02x, len=%u\n", - dev->name, off, len); - - switch(off) { - case 0x01: /* PSTART */ - return(dev->dp8390.page_start); - - case 0x02: /* PSTOP */ - return(dev->dp8390.page_stop); - - case 0x03: /* Remote Next-packet pointer */ - return(dev->dp8390.rempkt_ptr); - - case 0x04: /* TPSR */ - return(dev->dp8390.tx_page_start); - - case 0x05: /* Local Next-packet pointer */ - return(dev->dp8390.localpkt_ptr); - - case 0x06: /* Address counter (upper) */ - return(dev->dp8390.address_cnt >> 8); - - case 0x07: /* Address counter (lower) */ - return(dev->dp8390.address_cnt & 0xff); - - case 0x08: /* Reserved */ - case 0x09: - case 0x0a: - case 0x0b: - nelog(3, "%s: reserved Page2 read - register 0x%02x\n", - dev->name, off); - return(0xff); - - case 0x0c: /* RCR */ - return ((dev->dp8390.RCR.monitor << 5) | - (dev->dp8390.RCR.promisc << 4) | - (dev->dp8390.RCR.multicast << 3) | - (dev->dp8390.RCR.broadcast << 2) | - (dev->dp8390.RCR.runts_ok << 1) | - (dev->dp8390.RCR.errors_ok)); - - case 0x0d: /* TCR */ - return ((dev->dp8390.TCR.coll_prio << 4) | - (dev->dp8390.TCR.ext_stoptx << 3) | - ((dev->dp8390.TCR.loop_cntl & 0x3) << 1) | - (dev->dp8390.TCR.crc_disable)); - - case 0x0e: /* DCR */ - return (((dev->dp8390.DCR.fifo_size & 0x3) << 5) | - (dev->dp8390.DCR.auto_rx << 4) | - (dev->dp8390.DCR.loop << 3) | - (dev->dp8390.DCR.longaddr << 2) | - (dev->dp8390.DCR.endian << 1) | - (dev->dp8390.DCR.wdsize)); - - case 0x0f: /* IMR */ - return ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - - default: - nelog(3, "%s: Page2 register 0x%02x out of range\n", - dev->name, off); - break; - } - - return(0); -} - - -static void -page2_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) -{ -/* Maybe all writes here should be BX_PANIC()'d, since they - affect internal operation, but let them through for now - and print a warning. */ - nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", - dev->name, off, len, val); - switch(off) { - case 0x01: /* CLDA0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.local_dma &= 0xff00; - dev->dp8390.local_dma |= (val & 0xff); - break; - - case 0x02: /* CLDA1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.local_dma &= 0x00ff; - dev->dp8390.local_dma |= ((val & 0xff) << 8); - break; - - case 0x03: /* Remote Next-pkt pointer */ - dev->dp8390.rempkt_ptr = val; - break; - - case 0x04: - nelog(3, "page 2 write to reserved register 0x04\n"); - break; - - case 0x05: /* Local Next-packet pointer */ - dev->dp8390.localpkt_ptr = val; - break; - - case 0x06: /* Address counter (upper) */ - /* Clear out high byte and re-insert */ - dev->dp8390.address_cnt &= 0x00ff; - dev->dp8390.address_cnt |= ((val & 0xff) << 8); - break; - - case 0x07: /* Address counter (lower) */ - /* Clear out low byte and re-insert */ - dev->dp8390.address_cnt &= 0xff00; - dev->dp8390.address_cnt |= (val & 0xff); - break; - - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - nelog(3, "%s: Page2 write to reserved register 0x%02x\n", - dev->name, off); - break; - - default: - nelog(3, "%s: Page2 write, illegal register 0x%02x\n", - dev->name, off); - break; - } -} - - /* Writes to this page are illegal. */ static uint32_t page3_read(nic_t *dev, uint32_t off, unsigned int len) @@ -1171,119 +395,6 @@ page3_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) } -/* Routines for handling reads/writes to the Command Register. */ -static uint32_t -read_cr(nic_t *dev) -{ - uint32_t retval; - - retval = (((dev->dp8390.CR.pgsel & 0x03) << 6) | - ((dev->dp8390.CR.rdma_cmd & 0x07) << 3) | - (dev->dp8390.CR.tx_packet << 2) | - (dev->dp8390.CR.start << 1) | - (dev->dp8390.CR.stop)); - nelog(3, "%s: read CR returns 0x%02x\n", dev->name, retval); - - return(retval); -} - - -static void -write_cr(nic_t *dev, uint32_t val) -{ - nelog(3, "%s: wrote 0x%02x to CR\n", dev->name, val); - - /* Validate remote-DMA */ - if ((val & 0x38) == 0x00) { - nelog(3, "%s: CR write - invalid rDMA value 0\n", dev->name); - val |= 0x20; /* dma_cmd == 4 is a safe default */ - } - - /* Check for s/w reset */ - if (val & 0x01) { - dev->dp8390.ISR.reset = 1; - dev->dp8390.CR.stop = 1; - } else { - dev->dp8390.CR.stop = 0; - } - - dev->dp8390.CR.rdma_cmd = (val & 0x38) >> 3; - - /* If start command issued, the RST bit in the ISR */ - /* must be cleared */ - if ((val & 0x02) && !dev->dp8390.CR.start) - dev->dp8390.ISR.reset = 0; - - dev->dp8390.CR.start = ((val & 0x02) == 0x02); - dev->dp8390.CR.pgsel = (val & 0xc0) >> 6; - - /* Check for send-packet command */ - if (dev->dp8390.CR.rdma_cmd == 3) { - /* Set up DMA read from receive ring */ - dev->dp8390.remote_start = dev->dp8390.remote_dma = dev->dp8390.bound_ptr * 256; - dev->dp8390.remote_bytes = (uint16_t) chipmem_read(dev, dev->dp8390.bound_ptr * 256 + 2, 2); - nelog(3, "%s: sending buffer #x%x length %d\n", - dev->name, dev->dp8390.remote_start, dev->dp8390.remote_bytes); - } - - /* Check for start-tx */ - if ((val & 0x04) && dev->dp8390.TCR.loop_cntl) { - if (dev->dp8390.TCR.loop_cntl != 1) { - nelog(3, "%s: loop mode %d not supported\n", - dev->name, dev->dp8390.TCR.loop_cntl); - } else { - if (dev->board >= NE2K_NE2000) { - nic_rx(dev, - &dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_DWORD_MEMSTART], - dev->dp8390.tx_bytes); - } else { - nic_rx(dev, - &dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - } - } - } else if (val & 0x04) { - if (dev->dp8390.CR.stop || (!dev->dp8390.CR.start && (dev->board < NE2K_RTL8019AS))) { - if (dev->dp8390.tx_bytes == 0) /* njh@bandsman.co.uk */ { - return; /* Solaris9 probe */ - } - nelog(3, "%s: CR write - tx start, dev in reset\n", dev->name); - } - - if (dev->dp8390.tx_bytes == 0) - nelog(3, "%s: CR write - tx start, tx bytes == 0\n", dev->name); - - /* Send the packet to the system driver */ - dev->dp8390.CR.tx_packet = 1; - if (dev->board >= NE2K_NE2000) { - network_tx(&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_DWORD_MEMSTART], - dev->dp8390.tx_bytes); - } else { - network_tx(&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - } - - /* some more debug */ - if (dev->dp8390.tx_timer_active) - nelog(3, "%s: CR write, tx timer still active\n", dev->name); - - nic_tx(dev, val); - } - - /* 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 (dev->dp8390.CR.rdma_cmd == 0x01 && dev->dp8390.CR.start && dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) { - nic_interrupt(dev, 1); - if (!dev->is_pci) - nic_interrupt(dev, 0); - } - } -} - - static uint32_t nic_read(nic_t *dev, uint32_t addr, unsigned len) { @@ -1292,33 +403,29 @@ nic_read(nic_t *dev, uint32_t addr, unsigned len) nelog(3, "%s: read addr %x, len %d\n", dev->name, addr, len); - if (off >= 0x10) { - retval = asic_read(dev, off - 0x10, len); - } else if (off == 0x00) { - retval = read_cr(dev); - } else switch(dev->dp8390.CR.pgsel) { + if (off >= 0x10) + retval = asic_read(dev, off - 0x10, len); + else if (off == 0x00) + retval = dp8390_read_cr(dev->dp8390); + else switch(dev->dp8390->CR.pgsel) { case 0x00: - retval = page0_read(dev, off, len); + retval = dp8390_page0_read(dev->dp8390, off, len); break; - case 0x01: - retval = page1_read(dev, off, len); + retval = dp8390_page1_read(dev->dp8390, off, len); break; - case 0x02: - retval = page2_read(dev, off, len); + retval = dp8390_page2_read(dev->dp8390, off, len); break; - case 0x03: retval = page3_read(dev, off, len); break; - default: nelog(3, "%s: unknown value of pgsel in read - %d\n", - dev->name, dev->dp8390.CR.pgsel); + dev->name, dev->dp8390->CR.pgsel); break; - } - + } + return(retval); } @@ -1333,12 +440,7 @@ nic_readb(uint16_t addr, void *priv) static uint16_t nic_readw(uint16_t addr, void *priv) { - nic_t *dev = (nic_t *)priv; - - if (dev->dp8390.DCR.wdsize & 1) - return(nic_read(dev, addr, 2)); - else - return(nic_read(dev, addr, 1)); + return(nic_read((nic_t *)priv, addr, 2)); } @@ -1356,34 +458,30 @@ nic_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) nelog(3, "%s: write addr %x, value %x len %d\n", dev->name, addr, val, len); - /* 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 (off >= 0x10) { - asic_write(dev, off - 0x10, val, len); - } else if (off == 0x00) { - write_cr(dev, val); - } else switch(dev->dp8390.CR.pgsel) { + /* 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 (off >= 0x10) + asic_write(dev, off - 0x10, val, len); + else if (off == 0x00) + dp8390_write_cr(dev->dp8390, val); + else switch(dev->dp8390->CR.pgsel) { case 0x00: - page0_write(dev, off, val, len); + dp8390_page0_write(dev->dp8390, off, val, len); break; - case 0x01: - page1_write(dev, off, val, len); + dp8390_page1_write(dev->dp8390, off, val, len); break; - case 0x02: - page2_write(dev, off, val, len); + dp8390_page2_write(dev->dp8390, off, val, len); break; - case 0x03: page3_write(dev, off, val, len); break; - default: nelog(3, "%s: unknown value of pgsel in write - %d\n", - dev->name, dev->dp8390.CR.pgsel); + dev->name, dev->dp8390->CR.pgsel); break; } } @@ -1399,12 +497,7 @@ nic_writeb(uint16_t addr, uint8_t val, void *priv) static void nic_writew(uint16_t addr, uint16_t val, void *priv) { - nic_t *dev = (nic_t *)priv; - - if (dev->dp8390.DCR.wdsize & 1) - nic_write(dev, addr, val, 2); - else - nic_write(dev, addr, val, 1); + nic_write((nic_t *)priv, addr, val, 2); } @@ -1739,18 +832,7 @@ nic_iocheckremove(nic_t *dev, uint16_t addr) static void nic_ioset(nic_t *dev, uint16_t addr) { - if (dev->is_mca) { - io_sethandler(addr, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - io_sethandler(addr+16, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - io_sethandler(addr+0x1f, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - } - else if (dev->is_pci) { + if (dev->is_pci) { io_sethandler(addr, 16, nic_readb, nic_readw, nic_readl, nic_writeb, nic_writew, nic_writel, dev); @@ -1783,18 +865,7 @@ nic_ioset(nic_t *dev, uint16_t addr) static void nic_ioremove(nic_t *dev, uint16_t addr) { - if (dev->is_mca) { - io_removehandler(addr, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - io_removehandler(addr+16, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - io_removehandler(addr+0x1f, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); - } - else if (dev->is_pci) { + if (dev->is_pci) { io_removehandler(addr, 16, nic_readb, nic_readw, nic_readl, nic_writeb, nic_writew, nic_writel, dev); @@ -1833,7 +904,7 @@ nic_update_bios(nic_t *dev) if (! dev->has_bios) return; - if (PCI && dev->is_pci) + if (dev->is_pci) reg_bios_enable = dev->pci_bar[1].addr_regs[0] & 0x01; /* PCI BIOS stuff, just enable_disable. */ @@ -1890,21 +961,6 @@ nic_pci_read(int func, int addr, void *priv) ret = dev->pci_regs[addr]; break; -#if 0 - case 0x0C: /* (reserved) */ - ret = dev->pci_regs[addr]; - break; - - case 0x0D: /* PCI_LTR */ - case 0x0E: /* PCI_HTR */ - ret = dev->pci_regs[addr]; - break; - - case 0x0F: /* (reserved) */ - ret = dev->pci_regs[addr]; - break; -#endif - case 0x10: /* PCI_BAR 7:5 */ ret = (dev->pci_bar[0].addr_regs[0] & 0xe0) | 0x01; break; @@ -1975,32 +1031,9 @@ nic_pci_write(int func, int addr, uint8_t val, void *priv) nic_ioset(dev, dev->base_address); } } -#if 0 - if (val & PCI_COMMAND_MEMORY) { - ... - } -#endif dev->pci_regs[addr] = val & 0x03; break; -#if 0 - case 0x0C: /* (reserved) */ - dev->pci_regs[addr] = val; - break; - - case 0x0D: /* PCI_LTR */ - dev->pci_regs[addr] = val; - break; - - case 0x0E: /* PCI_HTR */ - dev->pci_regs[addr] = val; - break; - - case 0x0F: /* (reserved) */ - dev->pci_regs[addr] = val; - break; -#endif - case 0x10: /* PCI_BAR */ val &= 0xe0; /* 0xe0 acc to RTL DS */ val |= 0x01; /* re-enable IOIN bit */ @@ -2051,182 +1084,6 @@ nic_pci_write(int func, int addr, uint8_t val, void *priv) } -static void -nic_tx(nic_t *dev, uint32_t val) -{ - dev->dp8390.CR.tx_packet = 0; - dev->dp8390.TSR.tx_ok = 1; - dev->dp8390.ISR.pkt_tx = 1; - - /* Generate an interrupt if not masked */ - if (dev->dp8390.IMR.tx_inte) - nic_interrupt(dev, 1); - dev->dp8390.tx_timer_active = 0; -} - - -/* - * 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. - */ -static void -nic_rx(void *priv, uint8_t *buf, int io_len) -{ - static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; - nic_t *dev = (nic_t *)priv; - uint8_t pkthdr[4]; - uint8_t *startptr; - int pages, avail; - int idx, nextpage; - int endbytes; - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 1); - - if (io_len != 60) - nelog(2, "%s: rx_frame with length %d\n", dev->name, io_len); - - if ((dev->dp8390.CR.stop != 0) || (dev->dp8390.page_start == 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 + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; - if (dev->dp8390.curr_page < dev->dp8390.bound_ptr) { - avail = dev->dp8390.bound_ptr - dev->dp8390.curr_page; - } else { - avail = (dev->dp8390.page_stop - dev->dp8390.page_start) - - (dev->dp8390.curr_page - dev->dp8390.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 NE2K_NEVER_FULL_RING - || (avail == pages) -#endif - ) { - nelog(1, "%s: no space\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - if ((io_len < 40/*60*/) && !dev->dp8390.RCR.runts_ok) { - nelog(1, "%s: rejected small packet, length %d\n", dev->name, io_len); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Some computers don't care... */ - if (io_len < 60) - io_len = 60; - - nelog(2, "%s: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", - dev->name, - buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - io_len); - - /* Do address filtering if not in promiscuous mode. */ - if (! dev->dp8390.RCR.promisc) { - /* If this is a broadcast frame.. */ - if (! memcmp(buf, bcast_addr, 6)) { - /* Broadcast not enabled, we're done. */ - if (! dev->dp8390.RCR.broadcast) { - nelog(2, "%s: RX BC disabled\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* If this is a multicast frame.. */ - else if (buf[0] & 0x01) { - /* Multicast not enabled, we're done. */ - if (! dev->dp8390.RCR.multicast) { -#if 1 - nelog(2, "%s: RX MC disabled\n", dev->name); -#endif - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Are we listening to this multicast address? */ - idx = mcast_index(buf); - if (! (dev->dp8390.mchash[idx>>3] & (1<<(idx&0x7)))) { - nelog(2, "%s: RX MC not listed\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* Unicast, must be for us.. */ - else if (memcmp(buf, dev->dp8390.physaddr, 6)) return; - } else { - nelog(2, "%s: RX promiscuous receive\n", dev->name); - } - - nextpage = dev->dp8390.curr_page + pages; - if (nextpage >= dev->dp8390.page_stop) - nextpage -= (dev->dp8390.page_stop - dev->dp8390.page_start); - - /* Set up packet header. */ - pkthdr[0] = 0x01; /* RXOK - packet is OK */ - if (buf[0] & 0x01) - pkthdr[0] |= 0x20; /* MULTICAST packet */ - pkthdr[1] = nextpage; /* ptr to next packet */ - pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ - pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ - nelog(2, "%s: RX pkthdr [%02x %02x %02x %02x]\n", - dev->name, pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); - - /* Copy into buffer, update curpage, and signal interrupt if config'd */ - if (dev->board >= NE2K_NE2000) - startptr = &dev->dp8390.mem[(dev->dp8390.curr_page * 256) - DP8390_DWORD_MEMSTART]; - else - startptr = &dev->dp8390.mem[(dev->dp8390.curr_page * 256) - DP8390_WORD_MEMSTART]; - memcpy(startptr, pkthdr, sizeof(pkthdr)); - if ((nextpage > dev->dp8390.curr_page) || - ((dev->dp8390.curr_page + pages) == dev->dp8390.page_stop)) { - memcpy(startptr+sizeof(pkthdr), buf, io_len); - } else { - endbytes = (dev->dp8390.page_stop - dev->dp8390.curr_page) * 256; - memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); - if (dev->board >= NE2K_NE2000) - startptr = &dev->dp8390.mem[(dev->dp8390.page_start * 256) - DP8390_DWORD_MEMSTART]; - else - startptr = &dev->dp8390.mem[(dev->dp8390.page_start * 256) - DP8390_WORD_MEMSTART]; - memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); - } - dev->dp8390.curr_page = nextpage; - - dev->dp8390.RSR.rx_ok = 1; - dev->dp8390.RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; - dev->dp8390.ISR.pkt_rx = 1; - - if (dev->dp8390.IMR.rx_inte) - nic_interrupt(dev, 1); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); -} - - static void nic_rom_init(nic_t *dev, wchar_t *s) { @@ -2272,17 +1129,17 @@ nic_mca_read(int port, void *priv) return(dev->pos_regs[port & 7]); } -#define MCA_7154_IO_PORTS { 0x1000, 0x2020, 0x8020, 0xa0a0, 0xb0b0, 0xc0c0, \ - 0xc3d0 } +#define MCA_611F_IO_PORTS { 0x300, 0x340, 0x320, 0x360, 0x1300, 0x1340, \ + 0x1320, 0x1360 } -#define MCA_7154_IRQS { 3, 4, 5, 9 } +#define MCA_611F_IRQS { 2, 3, 4, 5, 10, 11, 12, 15 } static void nic_mca_write(int port, uint8_t val, void *priv) { nic_t *dev = (nic_t *)priv; - uint16_t novell_base[7] = MCA_7154_IO_PORTS; - int8_t novell_irq[4] = MCA_7154_IRQS; + uint16_t base[] = MCA_611F_IO_PORTS; + int8_t irq[] = MCA_611F_IRQS; /* MCA does not write registers below 0x0100. */ if (port < 0x0102) return; @@ -2290,14 +1147,14 @@ nic_mca_write(int port, uint8_t val, void *priv) /* Save the MCA register value. */ dev->pos_regs[port & 7] = val; - nic_ioremove(dev, dev->base_address); - + nic_ioremove(dev, dev->base_address); + /* This is always necessary so that the old handler doesn't remain. */ /* Get the new assigned I/O base address. */ - dev->base_address = novell_base[((dev->pos_regs[2] & 0xE) >> 1) - 1]; + dev->base_address = base[(dev->pos_regs[2] & 0xE0) >> 4]; /* Save the new IRQ values. */ - dev->base_irq = novell_irq[(dev->pos_regs[2] & 0x60) >> 5]; + dev->base_irq = irq[(dev->pos_regs[2] & 0xE) >> 1]; dev->bios_addr = 0x0000; dev->has_bios = 0; @@ -2315,9 +1172,24 @@ nic_mca_write(int port, uint8_t val, void *priv) /* Card enabled; register (new) I/O handler. */ nic_ioset(dev, dev->base_address); + + nic_reset(dev); + + nelog(2, "EtherNext/MC: Port=%04x, IRQ=%d\n", dev->base_address, dev->base_irq); + } } + +static uint8_t +nic_mca_feedb(void *priv) +{ + nic_t *dev = (nic_t *)priv; + + return (dev->pos_regs[2] & 0x01); +} + + static void * nic_init(const device_t *info) { @@ -2342,38 +1214,6 @@ nic_init(const device_t *info) dev->name = info->name; dev->board = info->local; rom = NULL; - switch(dev->board) { - case NE2K_NE1000: - dev->is_8bit = 1; - /*FALLTHROUGH*/ - - case NE2K_NE2000: - dev->maclocal[0] = 0x00; /* 00:00:D8 (Novell OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0xD8; - rom = (dev->board == NE2K_NE1000) ? NULL : ROM_PATH_NE2000; - break; - - case NE2K_NE2_MCA: - nelog(3, "NE/2 adapter\n"); - dev->is_mca = 1; - dev->maclocal[0] = 0x00; /* 00:00:D8 (Novell OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0xD8; - dev->pos_regs[0] = 0x54; - dev->pos_regs[1] = 0x71; - rom = NULL; - break; - - case NE2K_RTL8019AS: - case NE2K_RTL8029AS: - dev->is_pci = (dev->board == NE2K_RTL8029AS) ? 1 : 0; - dev->maclocal[0] = 0x00; /* 00:E0:4C (Realtek OID) */ - dev->maclocal[1] = 0xE0; - dev->maclocal[2] = 0x4C; - rom = (dev->board == NE2K_RTL8019AS) ? ROM_PATH_RTL8019 : ROM_PATH_RTL8029; - break; - } if (dev->board >= NE2K_RTL8019AS) { dev->base_address = 0x340; @@ -2386,7 +1226,7 @@ nic_init(const device_t *info) dev->has_bios = 0; } } else { - if (dev->board != NE2K_NE2_MCA) { + if (dev->board != NE2K_ETHERNEXT_MC) { dev->base_address = device_get_config_hex16("base"); dev->base_irq = device_get_config_int("irq"); if (dev->board == NE2K_NE2000) { @@ -2398,23 +1238,13 @@ nic_init(const device_t *info) } } else { - mca_add(nic_mca_read, nic_mca_write, dev); + mca_add(nic_mca_read, nic_mca_write, nic_mca_feedb, dev); } } /* See if we have a local MAC address configured. */ mac = device_get_config_mac("mac", -1); - /* - * Make this device known to the I/O system. - * PnP and PCI devices start with address spaces inactive. - */ - if (dev->board < NE2K_RTL8019AS && dev->board != NE2K_NE2_MCA) - nic_ioset(dev, dev->base_address); - - /* Set up our BIOS ROM space, if any. */ - nic_rom_init(dev, rom); - /* Set up our BIA. */ if (mac & 0xff000000) { /* Generate new local MAC. */ @@ -2430,12 +1260,72 @@ nic_init(const device_t *info) dev->maclocal[4] = (mac>>8) & 0xff; dev->maclocal[5] = (mac & 0xff); } - memcpy(dev->dp8390.physaddr, dev->maclocal, sizeof(dev->maclocal)); - nelog(0, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->dp8390 = device_add(&dp8390_device); + dev->dp8390->priv = dev; + dev->dp8390->interrupt = nic_interrupt; + + memcpy(dev->dp8390->physaddr, dev->maclocal, sizeof(dev->maclocal)); + + nelog(2, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, dev->base_address, dev->base_irq, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], dev->dp8390.physaddr[2], - dev->dp8390.physaddr[3], dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); + dev->dp8390->physaddr[0], dev->dp8390->physaddr[1], dev->dp8390->physaddr[2], + dev->dp8390->physaddr[3], dev->dp8390->physaddr[4], dev->dp8390->physaddr[5]); + + switch(dev->board) { + case NE2K_NE1000: + dev->is_8bit = 1; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CHECK_CR | DP8390_FLAG_CLEAR_IRQ); + dp8390_mem_alloc(dev->dp8390, 0x2000, 0x2000); + /*FALLTHROUGH*/ + + case NE2K_NE2000: + dev->maclocal[0] = 0x00; /* 00:00:D8 (Novell OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xD8; + rom = (dev->board == NE2K_NE1000) ? NULL : ROM_PATH_NE2000; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_EVEN_MAC | DP8390_FLAG_CHECK_CR | + DP8390_FLAG_CLEAR_IRQ); + dp8390_mem_alloc(dev->dp8390, 0x4000, 0x4000); + break; + + case NE2K_ETHERNEXT_MC: + dev->maclocal[0] = 0x00; /* 00:00:D8 (Networth Inc. OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0x79; + dev->pos_regs[0] = 0x1F; + dev->pos_regs[1] = 0x61; + rom = NULL; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_EVEN_MAC | DP8390_FLAG_CHECK_CR | + DP8390_FLAG_CLEAR_IRQ); + dp8390_mem_alloc(dev->dp8390, 0x4000, 0x4000); + break; + + case NE2K_RTL8019AS: + case NE2K_RTL8029AS: + dev->is_pci = (dev->board == NE2K_RTL8029AS) ? 1 : 0; + dev->maclocal[0] = 0x00; /* 00:E0:4C (Realtek OID) */ + dev->maclocal[1] = 0xE0; + dev->maclocal[2] = 0x4C; + rom = (dev->board == NE2K_RTL8019AS) ? ROM_PATH_RTL8019 : ROM_PATH_RTL8029; + if (dev->is_pci) + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_EVEN_MAC); + else + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_EVEN_MAC | DP8390_FLAG_CLEAR_IRQ); + dp8390_set_id(dev->dp8390, 0x50, (dev->board == NE2K_RTL8019AS) ? 0x70 : 0x43); + dp8390_mem_alloc(dev->dp8390, 0x4000, 0x8000); + break; + } + + /* + * Make this device known to the I/O system. + * PnP and PCI devices start with address spaces inactive. + */ + if (dev->board < NE2K_RTL8019AS && dev->board != NE2K_ETHERNEXT_MC) + nic_ioset(dev, dev->base_address); + + /* Set up our BIOS ROM space, if any. */ + nic_rom_init(dev, rom); if (dev->board >= NE2K_RTL8019AS) { if (dev->is_pci) { @@ -2570,11 +1460,12 @@ nic_init(const device_t *info) } } - /* Reset the board. */ + if (dev->board != NE2K_ETHERNEXT_MC) + /* Reset the board. */ nic_reset(dev); /* Attach ourselves to the network module. */ - network_attach(dev, dev->dp8390.physaddr, nic_rx); + network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx); nelog(1, "%s: %s attached IO=0x%X IRQ=%d\n", dev->name, dev->is_pci?"PCI":"ISA", dev->base_address, dev->base_irq); @@ -2588,11 +1479,6 @@ nic_close(void *priv) { nic_t *dev = (nic_t *)priv; - /* Make sure the platform layer is shut down. */ - network_close(); - - nic_ioremove(dev, dev->base_address); - nelog(1, "%s: closed\n", dev->name); free(dev); @@ -2796,10 +1682,10 @@ const device_t ne2000_device = { ne2000_config }; -const device_t ne2_device = { - "Novell NE/2", +const device_t ethernext_mc_device = { + "NetWorth EtherNext/MC", DEVICE_MCA, - NE2K_NE2_MCA, + NE2K_ETHERNEXT_MC, nic_init, nic_close, NULL, NULL, NULL, NULL, mca_mac_config diff --git a/src/network/net_ne2000.h b/src/network/net_ne2000.h index 6740fd446..f87943122 100644 --- a/src/network/net_ne2000.h +++ b/src/network/net_ne2000.h @@ -8,7 +8,7 @@ * * Definitions for the NE2000 ethernet controller. * - * Version: @(#)net_ne2000.h 1.0.3 2018/07/19 + * Version: @(#)net_ne2000.h 1.0.4 2018/08/11 * * Authors: Fred N. van Kempen, * @@ -40,7 +40,7 @@ enum { NE2K_NONE = 0, NE2K_NE1000 = 1, /* 8-bit ISA NE1000 */ NE2K_NE2000 = 2, /* 16-bit ISA NE2000 */ - NE2K_NE2_MCA = 3, /* 16-bit MCA NE/2 */ + NE2K_ETHERNEXT_MC = 3, /* 16-bit MCA EtherNext/MC */ NE2K_RTL8019AS = 4, /* 16-bit ISA PnP Realtek 8019AS */ NE2K_RTL8029AS = 5 /* 32-bit PCI Realtek 8029AS */ }; @@ -48,7 +48,7 @@ enum { extern const device_t ne1000_device; extern const device_t ne2000_device; -extern const device_t ne2_device; +extern const device_t ethernext_mc_device; extern const device_t rtl8019as_device; extern const device_t rtl8029as_device; diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index 78cf72f91..5acc9c170 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -8,11 +8,11 @@ * * Handle WinPcap library processing. * - * Version: @(#)net_pcap.c 1.0.4 2018/04/29 + * Version: @(#)net_pcap.c 1.0.10 2019/11/14 * * Author: Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -52,10 +52,10 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../config.h" #include "../device.h" #include "../plat.h" #include "../plat_dynld.h" +// #include "../ui.h" #include "network.h" @@ -139,22 +139,22 @@ static dllimp_t pcap_imports[] = { #ifdef ENABLE_PCAP_LOG int pcap_do_log = ENABLE_PCAP_LOG; -#endif static void -pcap_log(const char *format, ...) +pcap_log(const char *fmt, ...) { -#ifdef ENABLE_PCAP_LOG va_list ap; if (pcap_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define pcap_log(fmt, ...) +#endif /* Handle the receiving of frames from the channel. */ @@ -185,8 +185,13 @@ poll_thread(void *arg) if (pcap == NULL) break; /* Wait for the next packet to arrive. */ - data = (uint8_t *)f_pcap_next((void *)pcap, &h); + if (network_get_wait()) + data = NULL; + else + data = (uint8_t *)f_pcap_next((void *)pcap, &h); if (data != NULL) { + // ui_sb_update_icon(SB_NETWORK, 1); + /* Received MAC. */ mac_cmp32[0] = *(uint32_t *)(data+6); mac_cmp16[0] = *(uint16_t *)(data+10); @@ -205,8 +210,10 @@ poll_thread(void *arg) } /* If we did not get anything, wait a while. */ - if (data == NULL) + if (data == NULL) { + // ui_sb_update_icon(SB_NETWORK, 0); thread_wait_event(evt, 10); + } /* Release ownership of the device. */ network_wait(0); @@ -320,6 +327,8 @@ net_pcap_close(void) { void *pc; + // ui_sb_update_icon(SB_NETWORK, 0); + if (pcap == NULL) return; pcap_log("PCAP: closing.\n"); @@ -375,6 +384,8 @@ net_pcap_reset(const netcard_t *card, uint8_t *mac) char filter_exp[255]; struct bpf_program fp; + // ui_sb_update_icon(SB_NETWORK, 0); + /* Open a PCAP live channel. */ if ((pcap = f_pcap_open_live(network_host, /* interface name */ 1518, /* max packet size */ @@ -423,9 +434,13 @@ net_pcap_in(uint8_t *bufp, int len) { if (pcap == NULL) return; + // ui_sb_update_icon(SB_NETWORK, 1); + network_busy(1); f_pcap_sendpacket((void *)pcap, bufp, len); network_busy(0); + + // ui_sb_update_icon(SB_NETWORK, 0); } diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c new file mode 100644 index 000000000..fa5cab9d6 --- /dev/null +++ b/src/network/net_pcnet.c @@ -0,0 +1,2753 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the AMD PCnet LANCE NIC controller for both the ISA, VLB, + * and PCI buses. + * + * Version: @(#)net_pcnet.c 1.0.0 2019/11/09 + * + * Authors: Miran Grca, + * TheCollector1995, + * Antony T Curtis + * + * Copyright 2004-2019 Antony T Curtis + * Copyright 2016-2019 Miran Grca. + */ +#ifdef _WIN32 +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../timer.h" +#include "../dma.h" +#include "../mem.h" +#include "../rom.h" +#include "../pci.h" +#include "../pic.h" +#include "../random.h" +#include "../device.h" +#include "network.h" +#include "net_pcnet.h" +#include "bswap.h" + + +/* PCI info. */ +#define PCI_VENDID 0x1022 /* AMD */ +#define PCI_DEVID 0x2000 /* PCnet-PCI II (Am79c970A) */ +#define PCI_REGSIZE 256 /* size of PCI space */ + +#pragma pack(1) +typedef struct RTNETETHERHDR +{ + uint8_t DstMac[6]; + uint8_t SrcMac[6]; + /** Ethernet frame type or frame size, depending on the kind of ethernet. + * This is big endian on the wire. */ + uint16_t EtherType; +} RTNETETHERHDR; +#pragma pack() + +#define BCR_MAX_RAP 50 +#define MII_MAX_REG 32 +#define CSR_MAX_REG 128 + +/** Maximum frame size we handle */ +#define MAX_FRAME 1536 + + +/** @name Bus configuration registers + * @{ */ +#define BCR_MSRDA 0 +#define BCR_MSWRA 1 +#define BCR_MC 2 +#define BCR_RESERVED3 3 +#define BCR_LNKST 4 +#define BCR_LED1 5 +#define BCR_LED2 6 +#define BCR_LED3 7 +#define BCR_RESERVED8 8 +#define BCR_FDC 9 +/* 10 - 15 = reserved */ +#define BCR_IOBASEL 16 /* Reserved */ +#define BCR_IOBASEU 16 /* Reserved */ +#define BCR_BSBC 18 +#define BCR_EECAS 19 +#define BCR_SWS 20 +#define BCR_INTCON 21 /* Reserved */ +#define BCR_PLAT 22 +#define BCR_PCISVID 23 +#define BCR_PCISID 24 +#define BCR_SRAMSIZ 25 +#define BCR_SRAMB 26 +#define BCR_SRAMIC 27 +#define BCR_EBADDRL 28 +#define BCR_EBADDRU 29 +#define BCR_EBD 30 +#define BCR_STVAL 31 +#define BCR_MIICAS 32 +#define BCR_MIIADDR 33 +#define BCR_MIIMDR 34 +#define BCR_PCIVID 35 +#define BCR_PMC_A 36 +#define BCR_DATA0 37 +#define BCR_DATA1 38 +#define BCR_DATA2 39 +#define BCR_DATA3 40 +#define BCR_DATA4 41 +#define BCR_DATA5 42 +#define BCR_DATA6 43 +#define BCR_DATA7 44 +#define BCR_PMR1 45 +#define BCR_PMR2 46 +#define BCR_PMR3 47 +/** @} */ + +/** @name Bus configuration sub register accessors. + * @{ */ +#define BCR_DWIO(S) ((S)->aBCR[BCR_BSBC] & 0x0080) +#define BCR_SSIZE32(S) ((S)->aBCR[BCR_SWS ] & 0x0100) +#define BCR_SWSTYLE(S) ((S)->aBCR[BCR_SWS ] & 0x00FF) +/** @} */ + +/** @name CSR subregister accessors. + * @{ */ +#define CSR_INIT(S) ((S)->aCSR[0] & 0x0001) /**< Init assertion */ +#define CSR_STRT(S) ((S)->aCSR[0] & 0x0002) /**< Start assertion */ +#define CSR_STOP(S) ((S)->aCSR[0] & 0x0004) /**< Stop assertion */ +#define CSR_TDMD(S) ((S)->aCSR[0] & 0x0008) /**< Transmit demand. (perform xmit poll now (readable, settable, not clearable) */ +#define CSR_TXON(S) ((S)->aCSR[0] & 0x0010) /**< Transmit on (readonly) */ +#define CSR_RXON(S) ((S)->aCSR[0] & 0x0020) /**< Receive On */ +#define CSR_INEA(S) ((S)->aCSR[0] & 0x0040) /**< Interrupt Enable */ +#define CSR_LAPPEN(S) ((S)->aCSR[3] & 0x0020) /**< Look Ahead Packet Processing Enable */ +#define CSR_DXSUFLO(S) ((S)->aCSR[3] & 0x0040) /**< Disable Transmit Stop on Underflow error */ +#define CSR_ASTRP_RCV(S) ((S)->aCSR[4] & 0x0400) /**< Auto Strip Receive */ +#define CSR_DPOLL(S) ((S)->aCSR[4] & 0x1000) /**< Disable Transmit Polling */ +#define CSR_SPND(S) ((S)->aCSR[5] & 0x0001) /**< Suspend */ +#define CSR_LTINTEN(S) ((S)->aCSR[5] & 0x4000) /**< Last Transmit Interrupt Enable */ +#define CSR_TOKINTD(S) ((S)->aCSR[5] & 0x8000) /**< Transmit OK Interrupt Disable */ + +#define CSR_STINT ((S)->aCSR[7] & 0x0800) /**< Software Timer Interrupt */ +#define CSR_STINTE ((S)->aCSR[7] & 0x0400) /**< Software Timer Interrupt Enable */ + +#define CSR_DRX(S) ((S)->aCSR[15] & 0x0001) /**< Disable Receiver */ +#define CSR_DTX(S) ((S)->aCSR[15] & 0x0002) /**< Disable Transmit */ +#define CSR_LOOP(S) ((S)->aCSR[15] & 0x0004) /**< Loopback Enable */ +#define CSR_DRCVPA(S) ((S)->aCSR[15] & 0x2000) /**< Disable Receive Physical Address */ +#define CSR_DRCVBC(S) ((S)->aCSR[15] & 0x4000) /**< Disable Receive Broadcast */ +#define CSR_PROM(S) ((S)->aCSR[15] & 0x8000) /**< Promiscuous Mode */ + +/** @name CSR register accessors. + * @{ */ +#define CSR_IADR(S) (*(uint32_t*)((S)->aCSR + 1)) /**< Initialization Block Address */ +#define CSR_CRBA(S) (*(uint32_t*)((S)->aCSR + 18)) /**< Current Receive Buffer Address */ +#define CSR_CXBA(S) (*(uint32_t*)((S)->aCSR + 20)) /**< Current Transmit Buffer Address */ +#define CSR_NRBA(S) (*(uint32_t*)((S)->aCSR + 22)) /**< Next Receive Buffer Address */ +#define CSR_BADR(S) (*(uint32_t*)((S)->aCSR + 24)) /**< Base Address of Receive Ring */ +#define CSR_NRDA(S) (*(uint32_t*)((S)->aCSR + 26)) /**< Next Receive Descriptor Address */ +#define CSR_CRDA(S) (*(uint32_t*)((S)->aCSR + 28)) /**< Current Receive Descriptor Address */ +#define CSR_BADX(S) (*(uint32_t*)((S)->aCSR + 30)) /**< Base Address of Transmit Descriptor */ +#define CSR_NXDA(S) (*(uint32_t*)((S)->aCSR + 32)) /**< Next Transmit Descriptor Address */ +#define CSR_CXDA(S) (*(uint32_t*)((S)->aCSR + 34)) /**< Current Transmit Descriptor Address */ +#define CSR_NNRD(S) (*(uint32_t*)((S)->aCSR + 36)) /**< Next Next Receive Descriptor Address */ +#define CSR_NNXD(S) (*(uint32_t*)((S)->aCSR + 38)) /**< Next Next Transmit Descriptor Address */ +#define CSR_CRBC(S) ((S)->aCSR[40]) /**< Current Receive Byte Count */ +#define CSR_CRST(S) ((S)->aCSR[41]) /**< Current Receive Status */ +#define CSR_CXBC(S) ((S)->aCSR[42]) /**< Current Transmit Byte Count */ +#define CSR_CXST(S) ((S)->aCSR[43]) /**< Current transmit status */ +#define CSR_NRBC(S) ((S)->aCSR[44]) /**< Next Receive Byte Count */ +#define CSR_NRST(S) ((S)->aCSR[45]) /**< Next Receive Status */ +#define CSR_POLL(S) ((S)->aCSR[46]) /**< Transmit Poll Time Counter */ +#define CSR_PINT(S) ((S)->aCSR[47]) /**< Transmit Polling Interval */ +#define CSR_PXDA(S) (*(uint32_t*)((S)->aCSR + 60)) /**< Previous Transmit Descriptor Address*/ +#define CSR_PXBC(S) ((S)->aCSR[62]) /**< Previous Transmit Byte Count */ +#define CSR_PXST(S) ((S)->aCSR[63]) /**< Previous Transmit Status */ +#define CSR_NXBA(S) (*(uint32_t*)((S)->aCSR + 64)) /**< Next Transmit Buffer Address */ +#define CSR_NXBC(S) ((S)->aCSR[66]) /**< Next Transmit Byte Count */ +#define CSR_NXST(S) ((S)->aCSR[67]) /**< Next Transmit Status */ +#define CSR_RCVRC(S) ((S)->aCSR[72]) /**< Receive Descriptor Ring Counter */ +#define CSR_XMTRC(S) ((S)->aCSR[74]) /**< Transmit Descriptor Ring Counter */ +#define CSR_RCVRL(S) ((S)->aCSR[76]) /**< Receive Descriptor Ring Length */ +#define CSR_XMTRL(S) ((S)->aCSR[78]) /**< Transmit Descriptor Ring Length */ +#define CSR_MISSC(S) ((S)->aCSR[112]) /**< Missed Frame Count */ + +/** Calculates the full physical address. */ +#define PHYSADDR(S,A) ((A) | (S)->GCUpperPhys) + + +typedef struct { + mem_mapping_t mmio_mapping; + const char *name; + int board; + int is_pci, is_vlb; + int PCIBase; + int MMIOBase; + uint32_t base_address; + int base_irq; + int dma_channel; + int card; /* PCI card slot */ + int xmit_pos; + /** Register Address Pointer */ + uint32_t u32RAP; + /** Internal interrupt service */ + int32_t iISR; + /** ??? */ + uint32_t u32Lnkst; + /** Address of the RX descriptor table (ring). Loaded at init. */ + uint32_t GCRDRA; + /** Address of the TX descriptor table (ring). Loaded at init. */ + uint32_t GCTDRA; + uint8_t aPROM[16]; + uint16_t aCSR[CSR_MAX_REG]; + uint16_t aBCR[BCR_MAX_RAP]; + /** The loopback transmit buffer (avoid stack allocations). */ + uint8_t abLoopBuf[4096]; + /** The recv buffer. */ + uint8_t abRecvBuf[4096]; + /** Size of a RX/TX descriptor (8 or 16 bytes according to SWSTYLE */ + int iLog2DescSize; + /** Bits 16..23 in 16-bit mode */ + uint32_t GCUpperPhys; + /** True if we signal the guest that RX packets are missing. */ + int fSignalRxMiss; + /** Link speed to be reported through CSR68. */ + uint32_t u32LinkSpeed; + /** Error counter for bad receive descriptors. */ + uint32_t uCntBadRMD; + uint8_t maclocal[6]; /* configured MAC (local) address */ + pc_timer_t poll_timer; +} nic_t; + +/** @todo All structs: big endian? */ + +struct INITBLK16 +{ + uint16_t mode; /**< copied into csr15 */ + uint16_t padr1; /**< MAC 0..15 */ + uint16_t padr2; /**< MAC 16..32 */ + uint16_t padr3; /**< MAC 33..47 */ + uint16_t ladrf1; /**< logical address filter 0..15 */ + uint16_t ladrf2; /**< logical address filter 16..31 */ + uint16_t ladrf3; /**< logical address filter 32..47 */ + uint16_t ladrf4; /**< logical address filter 48..63 */ + uint32_t rdra:24; /**< address of receive descriptor ring */ + uint32_t res1:5; /**< reserved */ + uint32_t rlen:3; /**< number of receive descriptor ring entries */ + uint32_t tdra:24; /**< address of transmit descriptor ring */ + uint32_t res2:5; /**< reserved */ + uint32_t tlen:3; /**< number of transmit descriptor ring entries */ +}; + +/** bird: I've changed the type for the bitfields. They should only be 16-bit all together. + * frank: I've changed the bitfiled types to uint32_t to prevent compiler warnings. */ +struct INITBLK32 +{ + uint16_t mode; /**< copied into csr15 */ + uint16_t res1:4; /**< reserved */ + uint16_t rlen:4; /**< number of receive descriptor ring entries */ + uint16_t res2:4; /**< reserved */ + uint16_t tlen:4; /**< number of transmit descriptor ring entries */ + uint16_t padr1; /**< MAC 0..15 */ + uint16_t padr2; /**< MAC 16..31 */ + uint16_t padr3; /**< MAC 32..47 */ + uint16_t res3; /**< reserved */ + uint16_t ladrf1; /**< logical address filter 0..15 */ + uint16_t ladrf2; /**< logical address filter 16..31 */ + uint16_t ladrf3; /**< logical address filter 32..47 */ + uint16_t ladrf4; /**< logical address filter 48..63 */ + uint32_t rdra; /**< address of receive descriptor ring */ + uint32_t tdra; /**< address of transmit descriptor ring */ +}; + +/** Transmit Message Descriptor */ +typedef struct TMD +{ + struct + { + uint32_t tbadr; /**< transmit buffer address */ + } tmd0; + struct + { + uint32_t bcnt:12; /**< buffer byte count (two's complement) */ + uint32_t ones:4; /**< must be 1111b */ + uint32_t res:7; /**< reserved */ + uint32_t bpe:1; /**< bus parity error */ + uint32_t enp:1; /**< end of packet */ + uint32_t stp:1; /**< start of packet */ + uint32_t def:1; /**< deferred */ + uint32_t one:1; /**< exactly one retry was needed to transmit a frame */ + uint32_t ltint:1; /**< suppress interrupts after successful transmission */ + uint32_t nofcs:1; /**< when set, the state of DXMTFCS is ignored and + transmitter FCS generation is activated. */ + uint32_t err:1; /**< error occurred */ + uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */ + } tmd1; + struct + { + uint32_t trc:4; /**< transmit retry count */ + uint32_t res:12; /**< reserved */ + uint32_t tdr:10; /**< ??? */ + uint32_t rtry:1; /**< retry error */ + uint32_t lcar:1; /**< loss of carrier */ + uint32_t lcol:1; /**< late collision */ + uint32_t exdef:1; /**< excessive deferral */ + uint32_t uflo:1; /**< underflow error */ + uint32_t buff:1; /**< out of buffers (ENP not found) */ + } tmd2; + struct + { + uint32_t res; /**< reserved for user defined space */ + } tmd3; +} TMD; + +/** Receive Message Descriptor */ +typedef struct RMD +{ + struct + { + uint32_t rbadr; /**< receive buffer address */ + } rmd0; + struct + { + uint32_t bcnt:12; /**< buffer byte count (two's complement) */ + uint32_t ones:4; /**< must be 1111b */ + uint32_t res:4; /**< reserved */ + uint32_t bam:1; /**< broadcast address match */ + uint32_t lafm:1; /**< logical filter address match */ + uint32_t pam:1; /**< physical address match */ + uint32_t bpe:1; /**< bus parity error */ + uint32_t enp:1; /**< end of packet */ + uint32_t stp:1; /**< start of packet */ + uint32_t buff:1; /**< buffer error */ + uint32_t crc:1; /**< crc error on incoming frame */ + uint32_t oflo:1; /**< overflow error (lost all or part of incoming frame) */ + uint32_t fram:1; /**< frame error */ + uint32_t err:1; /**< error occurred */ + uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */ + } rmd1; + struct + { + uint32_t mcnt:12; /**< message byte count */ + uint32_t zeros:4; /**< 0000b */ + uint32_t rpc:8; /**< receive frame tag */ + uint32_t rcc:8; /**< receive frame tag + reserved */ + } rmd2; + struct + { + uint32_t res; /**< reserved for user defined space */ + } rmd3; +} RMD; + +static bar_t pcnet_pci_bar[3]; +static uint8_t pcnet_pci_regs[PCI_REGSIZE]; + +static void pcnetAsyncTransmit(nic_t *dev); +static void pcnetPollRxTx(nic_t *dev); +static void pcnetPollTimer(nic_t *dev); +static void pcnetUpdateIrq(nic_t *dev); +static uint16_t pcnet_bcr_readw(nic_t *dev, uint16_t rap); +static void pcnet_bcr_writew(nic_t *dev, uint16_t rap, uint16_t val); +static void pcnet_csr_writew(nic_t *dev, uint16_t rap, uint16_t val); +static void pcnetCanReceive(nic_t *dev); + + +#ifdef ENABLE_PCNET_LOG +int pcnet_do_log = ENABLE_PCNET_LOG; + +static void +pcnetlog(int lvl, const char *fmt, ...) +{ + va_list ap; + + if (pcnet_do_log >= lvl) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pcnetlog(lvl, fmt, ...) +#endif + + +static void +pcnet_do_irq(nic_t *dev, int issue) +{ + if (dev->is_pci) { + if (issue) + pci_set_irq(dev->card, PCI_INTA); + else + pci_clear_irq(dev->card, PCI_INTA); + } else { + if (issue) + picint(1<base_irq); + else + picintc(1<base_irq); + } +} + + +/** + * Load transmit message descriptor + * Make sure we read the own flag first. + * + * @param pThis adapter private data + * @param addr physical address of the descriptor + * @param fRetIfNotOwn return immediately after reading the own flag if we don't own the descriptor + * @return true if we own the descriptor, false otherwise + */ +static __inline int +pcnetTmdLoad(nic_t *dev, TMD *tmd, uint32_t addr, int fRetIfNotOwn) +{ + uint8_t ownbyte; + + if (BCR_SWSTYLE(dev) == 0) { + uint16_t xda[4]; + + DMAPageRead(addr+3, &ownbyte, 1); + if (!(ownbyte & 0x80) && fRetIfNotOwn) + return 0; + DMAPageRead(addr, (uint8_t*)&xda[0], sizeof(xda)); + ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16); + ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16); + ((uint32_t *)tmd)[2] = (uint32_t)xda[3] << 16; + ((uint32_t *)tmd)[3] = 0; + } else if (BCR_SWSTYLE(dev) != 3) { + DMAPageRead(addr+7, &ownbyte, 1); + if (!(ownbyte & 0x80) && fRetIfNotOwn) + return 0; + DMAPageRead(addr, (uint8_t*)tmd, 16); + } else { + uint32_t xda[4]; + DMAPageRead(addr+7, &ownbyte, 1); + if (!(ownbyte & 0x80) && fRetIfNotOwn) + return 0; + DMAPageRead(addr, (uint8_t*)&xda[0], sizeof(xda)); + ((uint32_t *)tmd)[0] = xda[2]; + ((uint32_t *)tmd)[1] = xda[1]; + ((uint32_t *)tmd)[2] = xda[0]; + ((uint32_t *)tmd)[3] = xda[3]; + } + /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */ + if (tmd->tmd1.own == 1 && !(ownbyte & 0x80)) + pcnetlog(3, "%s: pcnetTmdLoad: own bit flipped while reading!!\n", dev->name); + if (!(ownbyte & 0x80)) + tmd->tmd1.own = 0; + + return !!tmd->tmd1.own; +} + + +/** + * Store transmit message descriptor and hand it over to the host (the VM guest). + * Make sure that all data are transmitted before we clear the own flag. + */ +static __inline void +pcnetTmdStorePassHost(nic_t *dev, TMD *tmd, uint32_t addr) +{ + if (BCR_SWSTYLE(dev) == 0) { + uint16_t xda[4]; + xda[0] = ((uint32_t *)tmd)[0] & 0xffff; + xda[1] = ((((uint32_t *)tmd)[0] >> 16) & 0xff) | ((((uint32_t *)tmd)[1]>>16) & 0xff00); + xda[2] = ((uint32_t *)tmd)[1] & 0xffff; + xda[3] = ((uint32_t *)tmd)[2] >> 16; + xda[1] |= 0x8000; + DMAPageWrite(addr, (uint8_t*)&xda[0], sizeof(xda)); + xda[1] &= ~0x8000; + DMAPageWrite(addr+3, (uint8_t*)xda + 3, 1); + } else if (BCR_SWSTYLE(dev) != 3) { + ((uint32_t*)tmd)[1] |= 0x80000000; + DMAPageWrite(addr, (uint8_t*)tmd, 12); + ((uint32_t*)tmd)[1] &= ~0x80000000; + DMAPageWrite(addr+7, (uint8_t*)tmd + 7, 1); + } else { + uint32_t xda[3]; + xda[0] = ((uint32_t *)tmd)[2]; + xda[1] = ((uint32_t *)tmd)[1]; + xda[2] = ((uint32_t *)tmd)[0]; + xda[1] |= 0x80000000; + DMAPageWrite(addr, (uint8_t*)&xda[0], sizeof(xda)); + xda[1] &= ~0x80000000; + DMAPageWrite(addr+7, (uint8_t*)xda + 7, 1); + } +} + + +/** + * Load receive message descriptor + * Make sure we read the own flag first. + * + * @param pThis adapter private data + * @param addr physical address of the descriptor + * @param fRetIfNotOwn return immediately after reading the own flag if we don't own the descriptor + * @return true if we own the descriptor, false otherwise + */ +static __inline int +pcnetRmdLoad(nic_t *dev, RMD *rmd, uint32_t addr, int fRetIfNotOwn) +{ + uint8_t ownbyte; + + if (BCR_SWSTYLE(dev) == 0) { + uint16_t rda[4]; + DMAPageRead(addr+3, &ownbyte, 1); + if (!(ownbyte & 0x80) && fRetIfNotOwn) + return 0; + DMAPageRead(addr, (uint8_t*)&rda[0], sizeof(rda)); + ((uint32_t *)rmd)[0] = (uint32_t)rda[0] | ((rda[1] & 0x00ff) << 16); + ((uint32_t *)rmd)[1] = (uint32_t)rda[2] | ((rda[1] & 0xff00) << 16); + ((uint32_t *)rmd)[2] = (uint32_t)rda[3]; + ((uint32_t *)rmd)[3] = 0; + } else if (BCR_SWSTYLE(dev) != 3) { + DMAPageRead(addr+7, &ownbyte, 1); + if (!(ownbyte & 0x80) && fRetIfNotOwn) + return 0; + DMAPageRead(addr, (uint8_t*)rmd, 16); + } else { + uint32_t rda[4]; + DMAPageRead(addr+7, &ownbyte, 1); + if (!(ownbyte & 0x80) && fRetIfNotOwn) + return 0; + DMAPageRead(addr, (uint8_t*)&rda[0], sizeof(rda)); + ((uint32_t *)rmd)[0] = rda[2]; + ((uint32_t *)rmd)[1] = rda[1]; + ((uint32_t *)rmd)[2] = rda[0]; + ((uint32_t *)rmd)[3] = rda[3]; + } + /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */ + if (rmd->rmd1.own == 1 && !(ownbyte & 0x80)) + pcnetlog(3, "%s: pcnetRmdLoad: own bit flipped while reading!!\n", dev->name); + + if (!(ownbyte & 0x80)) + rmd->rmd1.own = 0; + + return !!rmd->rmd1.own; +} + + +/** + * Store receive message descriptor and hand it over to the host (the VM guest). + * Make sure that all data are transmitted before we clear the own flag. + */ +static __inline void +pcnetRmdStorePassHost(nic_t *dev, RMD *rmd, uint32_t addr) +{ + if (BCR_SWSTYLE(dev) == 0) { + uint16_t rda[4]; + rda[0] = ((uint32_t *)rmd)[0] & 0xffff; + rda[1] = ((((uint32_t *)rmd)[0]>>16) & 0xff) | ((((uint32_t *)rmd)[1]>>16) & 0xff00); + rda[2] = ((uint32_t *)rmd)[1] & 0xffff; + rda[3] = ((uint32_t *)rmd)[2] & 0xffff; + rda[1] |= 0x8000; + DMAPageWrite(addr, (uint8_t*)&rda[0], sizeof(rda)); + rda[1] &= ~0x8000; + DMAPageWrite(addr+3, (uint8_t*)rda + 3, 1); + } else if (BCR_SWSTYLE(dev) != 3) { + ((uint32_t*)rmd)[1] |= 0x80000000; + DMAPageWrite(addr, (uint8_t*)rmd, 12); + ((uint32_t*)rmd)[1] &= ~0x80000000; + DMAPageWrite(addr+7, (uint8_t*)rmd + 7, 1); + } else { + uint32_t rda[3]; + rda[0] = ((uint32_t *)rmd)[2]; + rda[1] = ((uint32_t *)rmd)[1]; + rda[2] = ((uint32_t *)rmd)[0]; + rda[1] |= 0x80000000; + DMAPageWrite(addr, (uint8_t*)&rda[0], sizeof(rda)); + rda[1] &= ~0x80000000; + DMAPageWrite(addr+7, (uint8_t*)rda + 7, 1); + } +} + + +/** + * Read+Write a TX/RX descriptor to prevent DMAPageWrite() allocating + * pages later when we shouldn't schedule to EMT. Temporarily hack. + */ +static void +pcnetDescTouch(nic_t *dev, uint32_t addr) +{ + uint8_t aBuf[16]; + int cbDesc; + if (BCR_SWSTYLE(dev) == 0) + cbDesc = 8; + else + cbDesc = 16; + DMAPageRead(addr, aBuf, cbDesc); + DMAPageWrite(addr, aBuf, cbDesc); +} + + +/** Checks if it's a bad (as in invalid) RMD.*/ +#define IS_RMD_BAD(rmd) ((rmd).rmd1.ones != 15) + +/** The network card is the owner of the RDTE/TDTE, actually it is this driver */ +#define CARD_IS_OWNER(desc) (((desc) & 0x8000)) + +/** The host is the owner of the RDTE/TDTE -- actually the VM guest. */ +#define HOST_IS_OWNER(desc) (!((desc) & 0x8000)) + +#ifndef ETHER_IS_MULTICAST /* Net/Open BSD macro it seems */ +#define ETHER_IS_MULTICAST(a) ((*(uint8_t *)(a)) & 1) +#endif + +#define ETHER_ADDR_LEN ETH_ALEN +#define ETH_ALEN 6 +#pragma pack(1) +struct ether_header /** @todo Use RTNETETHERHDR */ +{ + uint8_t ether_dhost[ETH_ALEN]; /**< destination ethernet address */ + uint8_t ether_shost[ETH_ALEN]; /**< source ethernet address */ + uint16_t ether_type; /**< packet type ID field */ +}; +#pragma pack() + +#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) + +#define MULTICAST_FILTER_LEN 8 + +static __inline uint32_t +lnc_mchash(const uint8_t *ether_addr) +{ +#define LNC_POLYNOMIAL 0xEDB88320UL + uint32_t crc = 0xFFFFFFFF; + int idx, bit; + uint8_t data; + + for (idx = 0; idx < ETHER_ADDR_LEN; idx++) + { + for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) + { + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0); + data >>= 1; + } + } + return crc; +#undef LNC_POLYNOMIAL +} + +#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) + +/* generated using the AUTODIN II polynomial + * x^32 + x^26 + x^23 + x^22 + x^16 + + * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 + */ +static const uint32_t crctab[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + + +static __inline int +padr_match(nic_t *dev, const uint8_t *buf, int size) +{ + struct ether_header *hdr = (struct ether_header *)buf; + int result; + uint8_t padr[6]; + padr[0] = dev->aCSR[12] & 0xff; + padr[1] = dev->aCSR[12] >> 8; + padr[2] = dev->aCSR[13] & 0xff; + padr[3] = dev->aCSR[13] >> 8; + padr[4] = dev->aCSR[14] & 0xff; + padr[5] = dev->aCSR[14] >> 8; + result = !CSR_DRCVPA(dev) && !memcmp(hdr->ether_dhost, padr, 6); + + pcnetlog(3, "%s: packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " + "padr=%02x:%02x:%02x:%02x:%02x:%02x => %d\n", dev->name, + hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], + hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], + padr[0],padr[1],padr[2],padr[3],padr[4],padr[5], result); + + return result; +} + + +static __inline int +padr_bcast(nic_t *dev, const uint8_t *buf, size_t size) +{ + static uint8_t aBCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct ether_header *hdr = (struct ether_header *)buf; + int result = !CSR_DRCVBC(dev) && !memcmp(hdr->ether_dhost, aBCAST, 6); + pcnetlog(3, "%s: padr_bcast result=%d\n", dev->name, result); + return result; +} + + +static int +ladr_match(nic_t *dev, const uint8_t *buf, size_t size) +{ + struct ether_header *hdr = (struct ether_header *)buf; + if ((hdr->ether_dhost[0] & 0x01) && ((uint64_t *)&dev->aCSR[8])[0] != 0LL) { + int index; + uint8_t ladr[8]; + ladr[0] = dev->aCSR[8] & 0xff; + ladr[1] = dev->aCSR[8] >> 8; + ladr[2] = dev->aCSR[9] & 0xff; + ladr[3] = dev->aCSR[9] >> 8; + ladr[4] = dev->aCSR[10] & 0xff; + ladr[5] = dev->aCSR[10] >> 8; + ladr[6] = dev->aCSR[11] & 0xff; + ladr[7] = dev->aCSR[11] >> 8; + index = lnc_mchash(hdr->ether_dhost) >> 26; + return (ladr[index >> 3] & (1 << (index & 7))); + } + return 0; +} + + +/** + * Get the receive descriptor ring address with a given index. + */ +static __inline uint32_t +pcnetRdraAddr(nic_t *dev, int idx) +{ + return dev->GCRDRA + ((CSR_RCVRL(dev) - idx) << dev->iLog2DescSize); +} + + +/** + * Get the transmit descriptor ring address with a given index. + */ +static __inline uint32_t +pcnetTdraAddr(nic_t *dev, int idx) +{ + return dev->GCTDRA + ((CSR_XMTRL(dev) - idx) << dev->iLog2DescSize); +} + + +static void +pcnetSoftReset(nic_t *dev) +{ + pcnetlog(3, "%s: pcnetSoftReset\n", dev->name); + + dev->u32Lnkst = 0x40; + dev->GCRDRA = 0; + dev->GCTDRA = 0; + dev->u32RAP = 0; + + dev->aCSR[0] = 0x0004; + dev->aCSR[3] = 0x0000; + dev->aCSR[4] = 0x0115; + dev->aCSR[5] = 0x0000; + dev->aCSR[6] = 0x0000; + dev->aCSR[8] = 0; + dev->aCSR[9] = 0; + dev->aCSR[10] = 0; + dev->aCSR[11] = 0; + dev->aCSR[12] = le16_to_cpu(((uint16_t *)&dev->aPROM[0])[0]); + dev->aCSR[13] = le16_to_cpu(((uint16_t *)&dev->aPROM[0])[1]); + dev->aCSR[14] = le16_to_cpu(((uint16_t *)&dev->aPROM[0])[2]); + dev->aCSR[15] &= 0x21c4; + CSR_RCVRC(dev) = 1; + CSR_XMTRC(dev) = 1; + CSR_RCVRL(dev) = 1; + CSR_XMTRL(dev) = 1; + dev->aCSR[80] = 0x1410; + if (dev->is_pci) { + dev->aCSR[88] = 0x1003; + dev->aCSR[89] = 0x0262; + } else { + dev->aCSR[88] = 0x3003; + dev->aCSR[89] = 0x0000; + } + dev->aCSR[94] = 0x0000; + dev->aCSR[100] = 0x0200; + dev->aCSR[103] = 0x0105; + CSR_MISSC(dev) = 0; + dev->aCSR[114] = 0x0000; + dev->aCSR[122] = 0x0000; + dev->aCSR[124] = 0x0000; +} + + +static void +pcnetUpdateIrq(nic_t *dev) +{ + dev->iISR = 0; + + dev->aCSR[0] &= ~0x0080; /* clear INTR */ + + if ((!(dev->aCSR[3] & 0x4000) && (dev->aCSR[0] & 0x4000)) /* BABL */ || + (!(dev->aCSR[3] & 0x1000) && (dev->aCSR[0] & 0x1000)) /* MISS */ || + (!(dev->aCSR[3] & 0x0100) && (dev->aCSR[0] & 0x0100)) /* IDON */ || + (!(dev->aCSR[3] & 0x0200) && (dev->aCSR[0] & 0x0200)) /* TINT */ || + (!(dev->aCSR[3] & 0x0400) && (dev->aCSR[0] & 0x0400)) /* RINT */ || + (!(dev->aCSR[3] & 0x0800) && (dev->aCSR[0] & 0x0800)) /* MERR */ || + (!(dev->aCSR[4] & 0x0001) && (dev->aCSR[4] & 0x0002)) /* JAB */ || + (!(dev->aCSR[4] & 0x0004) && (dev->aCSR[4] & 0x0008)) /* TXSTRT */ || + (!(dev->aCSR[4] & 0x0010) && (dev->aCSR[4] & 0x0020)) /* RCVO */ || + (!(dev->aCSR[4] & 0x0100) && (dev->aCSR[4] & 0x0200)) /* MFCO */ || + ((dev->aCSR[5] & 0x0040) && (dev->aCSR[5] & 0x0080)) /* EXDINT */ || + ((dev->aCSR[5] & 0x0008) && (dev->aCSR[5] & 0x0010)) /* MPINT */) { + dev->iISR = CSR_INEA(dev); /* CSR_INEA */ + dev->aCSR[0] |= 0x0080; /* set INTR */ + } + + if (dev->aCSR[4] & 0x0080) { /* UINT */ + dev->aCSR[4] &= ~0x0080; + dev->aCSR[4] |= 0x0040; + dev->iISR = 1; /* CSR_INEA */ + dev->aCSR[0] |= 0x0080; /* set INTR */ + pcnetlog(3, "%s: user int\n", dev->name); + } + + if (((dev->aCSR[5] & 0x0400) && (dev->aCSR[5] & 0x0800)) /* SINT */ || + ((dev->aCSR[5] & 0x0100) && (dev->aCSR[5] & 0x0200)) /* SLPINT */ ) { + dev->iISR = 1; /* CSR_INEA */ + dev->aCSR[0] |= 0x0080; /* set INTR */ + } + + pcnetlog(3, "%s: pcnetUpdateIrq: set irq isr=%02x, TINT=%04x\n", dev->name, !!dev->iISR, dev->aCSR[0] & 0x0200); + + /* normal path is to _not_ change the IRQ status */ + if (dev->iISR) + pcnet_do_irq(dev, 1); +} + + +static void +pcnetInit(nic_t *dev) +{ + int i; + pcnetlog(3, "%s: pcnetInit: init_addr=%#010x\n", dev->name, PHYSADDR(dev, CSR_IADR(dev))); + + /** @todo Documentation says that RCVRL and XMTRL are stored as two's complement! + * Software is allowed to write these registers directly. */ +#define PCNET_INIT() do { \ + DMAPageRead(PHYSADDR(dev, CSR_IADR(dev)), \ + (uint8_t *)&initblk, sizeof(initblk)); \ + dev->aCSR[15] = le32_to_cpu(initblk.mode); \ + CSR_RCVRL(dev) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \ + CSR_XMTRL(dev) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \ + dev->aCSR[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \ + dev->aCSR[ 8] = le32_to_cpu(initblk.ladrf1); \ + dev->aCSR[ 9] = le32_to_cpu(initblk.ladrf2); \ + dev->aCSR[10] = le32_to_cpu(initblk.ladrf3); \ + dev->aCSR[11] = le32_to_cpu(initblk.ladrf4); \ + dev->aCSR[12] = le32_to_cpu(initblk.padr1); \ + dev->aCSR[13] = le32_to_cpu(initblk.padr2); \ + dev->aCSR[14] = le32_to_cpu(initblk.padr3); \ + dev->GCRDRA = PHYSADDR(dev, initblk.rdra); \ + dev->GCTDRA = PHYSADDR(dev, initblk.tdra); \ +} while (0) + + if (BCR_SSIZE32(dev)) { + struct INITBLK32 initblk; + dev->GCUpperPhys = 0; + PCNET_INIT(); + pcnetlog(3, "%s: initblk.rlen=%#04x, initblk.tlen=%#04x\n", + dev->name, initblk.rlen, initblk.tlen); + } else { + struct INITBLK16 initblk; + dev->GCUpperPhys = (0xff00 & (uint32_t)dev->aCSR[2]) << 16; + PCNET_INIT(); + pcnetlog(3, "%s: initblk.rlen=%#04x, initblk.tlen=%#04x\n", + dev->name, initblk.rlen, initblk.tlen); + } + +#undef PCNET_INIT + + int cbRxBuffers = 0; + for (i = CSR_RCVRL(dev); i >= 1; i--) { + RMD rmd; + uint32_t rdaddr = PHYSADDR(dev, pcnetRdraAddr(dev, i)); + + pcnetDescTouch(dev, rdaddr); + /* At this time it is not guaranteed that the buffers are already initialized. */ + if (pcnetRmdLoad(dev, &rmd, rdaddr, 0)) { + uint32_t cbBuf = 4096U-rmd.rmd1.bcnt; + cbRxBuffers += cbBuf; + } + } + + for (i = CSR_XMTRL(dev); i >= 1; i--) { + uint32_t tdaddr = PHYSADDR(dev, pcnetTdraAddr(dev, i)); + + pcnetDescTouch(dev, tdaddr); + } + + /* + * Heuristics: The Solaris pcn driver allocates too few RX buffers (128 buffers of a + * size of 128 bytes are 16KB in summary) leading to frequent RX buffer overflows. In + * that case we don't signal RX overflows through the CSR0_MISS flag as the driver + * re-initializes the device on every miss. Other guests use at least 32 buffers of + * usually 1536 bytes and should therefore not run into condition. If they are still + * short in RX buffers we notify this condition. + */ + dev->fSignalRxMiss = (cbRxBuffers == 0 || cbRxBuffers >= 32*128); + + CSR_RCVRC(dev) = CSR_RCVRL(dev); + CSR_XMTRC(dev) = CSR_XMTRL(dev); + + /* Reset cached RX and TX states */ + CSR_CRST(dev) = CSR_CRBC(dev) = CSR_NRST(dev) = CSR_NRBC(dev) = 0; + CSR_CXST(dev) = CSR_CXBC(dev) = CSR_NXST(dev) = CSR_NXBC(dev) = 0; + + pcnetlog(1, "%s: Init: SWSTYLE=%d GCRDRA=%#010x[%d] GCTDRA=%#010x[%d]%s\n", + dev->name, BCR_SWSTYLE(dev), + dev->GCRDRA, CSR_RCVRL(dev), dev->GCTDRA, CSR_XMTRL(dev), + !dev->fSignalRxMiss ? " (CSR0_MISS disabled)" : ""); + + if (dev->GCRDRA & (dev->iLog2DescSize - 1)) + pcnetlog(1, "%s: Warning: Misaligned RDRA\n", dev->name); + if (dev->GCTDRA & (dev->iLog2DescSize - 1)) + pcnetlog(1, "%s: Warning: Misaligned TDRA\n", dev->name); + + dev->aCSR[0] |= 0x0101; /* Initialization done */ + dev->aCSR[0] &= ~0x0004; /* clear STOP bit */ +} + + +/** + * Start RX/TX operation. + */ +static void +pcnetStart(nic_t *dev) +{ + pcnetlog(3, "%s: pcnetStart: Poll timer\n", dev->name); + + /* Reset any cached RX/TX descriptor state. */ + CSR_CRDA(dev) = CSR_CRBA(dev) = CSR_NRDA(dev) = CSR_NRBA(dev) = 0; + CSR_CRBC(dev) = CSR_NRBC(dev) = CSR_CRST(dev) = 0; + + if (!CSR_DTX(dev)) + dev->aCSR[0] |= 0x0010; /* set TXON */ + if (!CSR_DRX(dev)) + dev->aCSR[0] |= 0x0020; /* set RXON */ + dev->aCSR[0] &= ~0x0004; /* clear STOP bit */ + dev->aCSR[0] |= 0x0002; /* STRT */ + pcnetPollTimer(dev); +} + + +/** + * Stop RX/TX operation. + */ +static void +pcnetStop(nic_t *dev) +{ + pcnetlog(3, "%s: pcnetStop: Poll timer\n", dev->name); + dev->aCSR[0] = 0x0004; + dev->aCSR[4] &= ~0x02c2; + dev->aCSR[5] &= ~0x0011; + pcnetPollTimer(dev); +} + + +/** + * Poll Receive Descriptor Table Entry and cache the results in the appropriate registers. + * Note: Once a descriptor belongs to the network card (this driver), it cannot be changed + * by the host (the guest driver) anymore. Well, it could but the results are undefined by + * definition. + * @param fSkipCurrent if true, don't scan the current RDTE. + */ +static void +pcnetRdtePoll(nic_t *dev) +{ + /* assume lack of a next receive descriptor */ + CSR_NRST(dev) = 0; + + if (dev->GCRDRA) { + /* + * The current receive message descriptor. + */ + RMD rmd; + int i = CSR_RCVRC(dev); + uint32_t addr; + + if (i < 1) + i = CSR_RCVRL(dev); + + addr = pcnetRdraAddr(dev, i); + CSR_CRDA(dev) = CSR_CRBA(dev) = 0; + CSR_CRBC(dev) = CSR_CRST(dev) = 0; + if (!pcnetRmdLoad(dev, &rmd, PHYSADDR(dev, addr), 1)) + return; + if (!IS_RMD_BAD(rmd)) { + CSR_CRDA(dev) = addr; /* Receive Descriptor Address */ + CSR_CRBA(dev) = rmd.rmd0.rbadr; /* Receive Buffer Address */ + CSR_CRBC(dev) = rmd.rmd1.bcnt; /* Receive Byte Count */ + CSR_CRST(dev) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */ + pcnetCanReceive(dev); + } else { + /* This is not problematic since we don't own the descriptor + * We actually do own it, otherwise pcnetRmdLoad would have returned false. + * Don't flood the release log with errors. + */ + if (++dev->uCntBadRMD < 50) + pcnetlog(1, "%s: BAD RMD ENTRIES AT %#010x (i=%d)\n", + dev->name, addr, i); + return; + } + + /* + * The next descriptor. + */ + if (--i < 1) + i = CSR_RCVRL(dev); + addr = pcnetRdraAddr(dev, i); + CSR_NRDA(dev) = CSR_NRBA(dev) = 0; + CSR_NRBC(dev) = 0; + if (!pcnetRmdLoad(dev, &rmd, PHYSADDR(dev, addr), 1)) + return; + if (!IS_RMD_BAD(rmd)) { + CSR_NRDA(dev) = addr; /* Receive Descriptor Address */ + CSR_NRBA(dev) = rmd.rmd0.rbadr; /* Receive Buffer Address */ + CSR_NRBC(dev) = rmd.rmd1.bcnt; /* Receive Byte Count */ + CSR_NRST(dev) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */ + } else { + /* This is not problematic since we don't own the descriptor + * We actually do own it, otherwise pcnetRmdLoad would have returned false. + * Don't flood the release log with errors. + */ + if (++dev->uCntBadRMD < 50) + pcnetlog(1, "%s: BAD RMD ENTRIES + AT %#010x (i=%d)\n", + dev->name, addr, i); + return; + } + + /** + * @todo NNRD + */ + } else { + CSR_CRDA(dev) = CSR_CRBA(dev) = CSR_NRDA(dev) = CSR_NRBA(dev) = 0; + CSR_CRBC(dev) = CSR_NRBC(dev) = CSR_CRST(dev) = 0; + } +} + + +/** + * Poll Transmit Descriptor Table Entry + * @return true if transmit descriptors available + */ +static int +pcnetTdtePoll(nic_t *dev, TMD *tmd) +{ + if (dev->GCTDRA) { + uint32_t cxda = pcnetTdraAddr(dev, CSR_XMTRC(dev)); + + if (!pcnetTmdLoad(dev, tmd, PHYSADDR(dev, cxda), 1)) + return 0; + + if (tmd->tmd1.ones != 15) { + pcnetlog(1, "%s: BAD TMD XDA=%#010x\n", + dev->name, PHYSADDR(dev, cxda)); + return 0; + } + + /* previous xmit descriptor */ + CSR_PXDA(dev) = CSR_CXDA(dev); + CSR_PXBC(dev) = CSR_CXBC(dev); + CSR_PXST(dev) = CSR_CXST(dev); + + /* set current transmit descriptor. */ + CSR_CXDA(dev) = cxda; + CSR_CXBC(dev) = tmd->tmd1.bcnt; + CSR_CXST(dev) = ((uint32_t *)tmd)[1] >> 16; + return CARD_IS_OWNER(CSR_CXST(dev)); + } else { + /** @todo consistency with previous receive descriptor */ + CSR_CXDA(dev) = 0; + CSR_CXBC(dev) = CSR_CXST(dev) = 0; + return 0; + } +} + + +/** + * Poll Transmit Descriptor Table Entry + * @return true if transmit descriptors available + */ +static int +pcnetCalcPacketLen(nic_t *dev, int cb) +{ + TMD tmd; + int cbPacket = cb; + uint32_t iDesc = CSR_XMTRC(dev); + uint32_t iFirstDesc = iDesc; + + do + { + /* Advance the ring counter */ + if (iDesc < 2) + iDesc = CSR_XMTRL(dev); + else + iDesc--; + + if (iDesc == iFirstDesc) + break; + + uint32_t addrDesc = pcnetTdraAddr(dev, iDesc); + + if (!pcnetTmdLoad(dev, &tmd, PHYSADDR(dev, addrDesc), 1)) { + /* + * No need to count further since this packet won't be sent anyway + * due to underflow. + */ + pcnetlog(3, "%s: pcnetCalcPacketLen: underflow, return %u\n", dev->name, cbPacket); + return cbPacket; + } + if (tmd.tmd1.ones != 15) { + pcnetlog(1, "%s: BAD TMD XDA=%#010x\n", + dev->name, PHYSADDR(dev, addrDesc)); + pcnetlog(3, "%s: pcnetCalcPacketLen: bad TMD, return %u\n", dev->name, cbPacket); + return cbPacket; + } + pcnetlog(3, "%s: pcnetCalcPacketLen: got valid TMD, cb=%u\n", dev->name, 4096 - tmd.tmd1.bcnt); + cbPacket += 4096 - tmd.tmd1.bcnt; + } while (!tmd.tmd1.enp); + + pcnetlog(3, "#%d pcnetCalcPacketLen: return %u\n", dev->name, cbPacket); + return cbPacket; +} + + +/** + * Write data into guest receive buffers. + */ +static void +pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) +{ + nic_t *dev = (nic_t *)priv; + int is_padr = 0, is_bcast = 0, is_ladr = 0; + uint32_t iRxDesc; + int cbPacket; + uint8_t buf1[60]; + + + if (CSR_DRX(dev) || CSR_STOP(dev) || CSR_SPND(dev) || !size) + return; + + /* if too small buffer, then expand it */ + if (size < 60) { + memcpy(buf1, buf, size); + memset(buf1 + size, 0, 60 - size); + buf = buf1; + size = 60; + } + + pcnetlog(1, "%s: pcnetReceiveNoSync: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", dev->name, + buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + size); + + /* + * Perform address matching. + */ + if (CSR_PROM(dev) + || (is_padr = padr_match(dev, buf, size)) + || (is_bcast = padr_bcast(dev, buf, size)) + || (is_ladr = ladr_match(dev, buf, size))) { + + if (HOST_IS_OWNER(CSR_CRST(dev))) + pcnetRdtePoll(dev); + + if (HOST_IS_OWNER(CSR_CRST(dev))) { + /* Not owned by controller. This should not be possible as + * we already called pcnetCanReceive(). */ + const uint32_t cb = 1 << dev->iLog2DescSize; + uint32_t GCPhys = dev->GCRDRA; + iRxDesc = CSR_RCVRL(dev); + + while (iRxDesc-- > 0) { + RMD rmd; + pcnetRmdLoad(dev, &rmd, PHYSADDR(dev, GCPhys), 0); + GCPhys += cb; + } + dev->aCSR[0] |= 0x1000; /* Set MISS flag */ + CSR_MISSC(dev)++; + pcnetlog(2, "%s: pcnetReceiveNoSync: packet missed\n", dev->name); + } else { + RTNETETHERHDR *pEth = (RTNETETHERHDR *)buf; + int fStrip = 0; + int len_802_3; + uint8_t *src = &dev->abRecvBuf[8]; + uint32_t crda = CSR_CRDA(dev); + uint32_t next_crda; + RMD rmd, next_rmd; + + /* + * Ethernet framing considers these two octets to be + * payload type; 802.3 framing considers them to be + * payload length. IEEE 802.3x-1997 restricts Ethernet + * type to be greater than or equal to 1536 (0x0600), so + * that both framings can coexist on the wire. + * + * NB: CSR_ASTRP_RCV bit affects only 802.3 frames! + */ + len_802_3 = cpu_to_be16(pEth->EtherType); + if (len_802_3 < 46 && CSR_ASTRP_RCV(dev)) { + size = MIN(sizeof(RTNETETHERHDR) + len_802_3, size); + fStrip = 1; + } + + memcpy(src, buf, size); + + if (!fStrip) { + /* In loopback mode, Runt Packed Accept is always enabled internally; + * don't do any padding because guest may be looping back very short packets. + */ + if (!CSR_LOOP(dev)) + while (size < 60) + src[size++] = 0; + + uint32_t fcs = UINT32_MAX; + uint8_t *p = src; + + while (p != &src[size]) + CRC(fcs, *p++); + + /* FCS at the end of the packet */ + ((uint32_t *)&src[size])[0] = htonl(fcs); + size += 4; + } + + cbPacket = size; + + pcnetRmdLoad(dev, &rmd, PHYSADDR(dev, crda), 0); + /* if (!CSR_LAPPEN(dev)) */ + rmd.rmd1.stp = 1; + + int cbBuf = MIN(4096 - rmd.rmd1.bcnt, size); + uint32_t rbadr = PHYSADDR(dev, rmd.rmd0.rbadr); + + /* save the old value to check if it was changed as long as we didn't + * hold the critical section */ + iRxDesc = CSR_RCVRC(dev); + + /* We have to leave the critical section here or we risk deadlocking + * with EMT when the write is to an unallocated page or has an access + * handler associated with it. + * + * This shouldn't be a problem because: + * - any modification to the RX descriptor by the driver is + * forbidden as long as it is owned by the device + * - we don't cache any register state beyond this point + */ + + DMAPageWrite(rbadr, src, cbBuf); + + /* RX disabled in the meantime? If so, abort RX. */ + if (CSR_DRX(dev) || CSR_STOP(dev) || CSR_SPND(dev)) { + pcnetlog(3, "%s: RX disabled 1\n", dev->name); + return; + } + + /* Was the register modified in the meantime? If so, don't touch the + * register but still update the RX descriptor. */ + if (iRxDesc == CSR_RCVRC(dev)) { + if (iRxDesc-- < 2) + iRxDesc = CSR_RCVRL(dev); + CSR_RCVRC(dev) = iRxDesc; + } else + iRxDesc = CSR_RCVRC(dev); + + src += cbBuf; + size -= cbBuf; + + while (size > 0) { + /* Read the entire next descriptor as we're likely to need it. */ + next_crda = pcnetRdraAddr(dev, iRxDesc); + + /* Check next descriptor's own bit. If we don't own it, we have + * to quit and write error status into the last descriptor we own. + */ + if (!pcnetRmdLoad(dev, &next_rmd, PHYSADDR(dev, next_crda), 1)) + break; + + /* Write back current descriptor, clear the own bit. */ + pcnetRmdStorePassHost(dev, &rmd, PHYSADDR(dev, crda)); + + /* Switch to the next descriptor */ + crda = next_crda; + rmd = next_rmd; + + cbBuf = MIN(4096 - rmd.rmd1.bcnt, size); + uint32_t rbadr2 = PHYSADDR(dev, rmd.rmd0.rbadr); + + /* We have to leave the critical section here or we risk deadlocking + * with EMT when the write is to an unallocated page or has an access + * handler associated with it. See above for additional comments. */ + DMAPageWrite(rbadr2, src, cbBuf); + + /* RX disabled in the meantime? If so, abort RX. */ + if (CSR_DRX(dev) || CSR_STOP(dev) || CSR_SPND(dev)) { + pcnetlog(3, "%s: RX disabled 2\n", dev->name); + return; + } + + /* Was the register modified in the meantime? If so, don't touch the + * register but still update the RX descriptor. */ + if (iRxDesc == CSR_RCVRC(dev)) { + if (iRxDesc-- < 2) + iRxDesc = CSR_RCVRL(dev); + CSR_RCVRC(dev) = iRxDesc; + } else { + iRxDesc = CSR_RCVRC(dev); + } + + src += cbBuf; + size -= cbBuf; + } + + if (size == 0) { + rmd.rmd1.enp = 1; + rmd.rmd1.pam = !CSR_PROM(dev) && is_padr; + rmd.rmd1.lafm = !CSR_PROM(dev) && is_ladr; + rmd.rmd1.bam = !CSR_PROM(dev) && is_bcast; + rmd.rmd2.mcnt = cbPacket; + rmd.rmd2.zeros = 0; + } else { + pcnetlog(2, "%s: Overflow by %ubytes\n", dev->name, size); + rmd.rmd1.oflo = 1; + rmd.rmd1.buff = 1; + rmd.rmd1.err = 1; + } + + /* write back, clear the own bit */ + pcnetRmdStorePassHost(dev, &rmd, PHYSADDR(dev, crda)); + + dev->aCSR[0] |= 0x0400; + pcnetlog(2, "%s: RINT set, RCVRC=%d CRDA=%#010x\n", dev->name, + CSR_RCVRC(dev), PHYSADDR(dev, CSR_CRDA(dev))); + + /* guest driver is owner: force repoll of current and next RDTEs */ + CSR_CRST(dev) = 0; + } + } + + if (!CSR_LOOP(dev)) + pcnetPollRxTx(dev); + + pcnetUpdateIrq(dev); +} + + +/** + * Actually try transmit frames. + * + * @threads TX or EMT. + */ +static void +pcnetAsyncTransmit(nic_t *dev) +{ + /* + * Just cleared transmit demand if the transmitter is off. + */ + if (!CSR_TXON(dev)) { + dev->aCSR[0] &= ~0x0008; /* Clear TDMD */ + return; + } + + /* + * Iterate the transmit descriptors. + */ + int cMax = 32; + do { + TMD tmd; + if (!pcnetTdtePoll(dev, &tmd)) + break; + + pcnetlog(3, "%s: TMDLOAD %#010x\n", dev->name, PHYSADDR(dev, CSR_CXDA(dev))); + + int fLoopback = CSR_LOOP(dev); + + /* + * The typical case - a complete packet. + */ + if (tmd.tmd1.stp && tmd.tmd1.enp) { + const int cb = 4096 - tmd.tmd1.bcnt; + pcnetlog(1, "%s: pcnetAsyncTransmit: stp&enp: cb=%d xmtrc=%#x\n", dev->name, cb, CSR_XMTRC(dev)); + dev->xmit_pos = cb; + DMAPageRead(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf, cb); + + if (fLoopback) { + /* From the manual: ``A zero length buffer is acceptable as + * long as it is not the last buffer in a chain (STP = 0 and + * ENP = 1).'' That means that the first buffer might have a + * zero length if it is not the last one in the chain. */ + if (cb <= MAX_FRAME) { + if (HOST_IS_OWNER(CSR_CRST(dev))) + pcnetRdtePoll(dev); + + pcnetReceiveNoSync(dev, dev->abLoopBuf, dev->xmit_pos); + } else if (cb == 4096) { + /* The Windows NT4 pcnet driver sometimes marks the first + * unused descriptor as owned by us. Ignore that (by + * passing it back). Do not update the ring counter in this + * case (otherwise that driver becomes even more confused, + * which causes transmit to stall for about 10 seconds). + * This is just a workaround, not a final solution. */ + /* r=frank: IMHO this is the correct implementation. The + * manual says: ``If the OWN bit is set and the buffer + * length is 0, the OWN bit will be cleared. In the C-LANCE + * the buffer length of 0 is interpreted as a 4096-byte + * buffer.'' */ + /* r=michaln: Perhaps not quite right. The C-LANCE (Am79C90) + * datasheet explains that the old LANCE (Am7990) ignored + * the top four bits next to BCNT and a count of 0 was + * interpreted as 4096. In the C-LANCE, that is still the + * case if the top bits are all ones. If all 16 bits are + * zero, the C-LANCE interprets it as zero-length transmit + * buffer. It's not entirely clear if the later models + * (PCnet-ISA, PCnet-PCI) behave like the C-LANCE or not. + * It is possible that the actual behavior of the C-LANCE + * and later hardware is that the buffer lengths are *16-bit* + * two's complement numbers between 0 and 4096. AMD's drivers + * in fact generally treat the length as a 16-bit quantity. */ + pcnetlog(1, "%s: pcnetAsyncTransmit: illegal 4kb frame -> ignoring\n", dev->name); + pcnetTmdStorePassHost(dev, &tmd, PHYSADDR(dev, CSR_CXDA(dev))); + break; + } + } else { + pcnetlog(3, "%s: pcnetAsyncTransmit: transmit loopbuf stp and enp\n", dev->name); + network_tx(dev->abLoopBuf, dev->xmit_pos); + } + + /* Write back the TMD and pass it to the host (clear own bit). */ + pcnetTmdStorePassHost(dev, &tmd, PHYSADDR(dev, CSR_CXDA(dev))); + + /* advance the ring counter register */ + if (CSR_XMTRC(dev) < 2) { + CSR_XMTRC(dev) = CSR_XMTRL(dev); + } else { + CSR_XMTRC(dev)--; + } + } else if (tmd.tmd1.stp) { + /* + * Read TMDs until end-of-packet or tdte poll fails (underflow). + * + * We allocate a maximum sized buffer here since we do not wish to + * waste time finding out how much space we actually need even if + * we could reliably do that on SMP guests. + */ + int cb = 4096 - tmd.tmd1.bcnt; + dev->xmit_pos = pcnetCalcPacketLen(dev, cb); + DMAPageRead(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf, cb); + if (fLoopback) { + if (HOST_IS_OWNER(CSR_CRST(dev))) + pcnetRdtePoll(dev); + pcnetlog(3, "%s: pcnetAsyncTransmit: receive loopback stp\n", dev->name); + pcnetReceiveNoSync(dev, dev->abLoopBuf, dev->xmit_pos); + } else { + pcnetlog(3, "%s: pcnetAsyncTransmit: transmit loopbuf stp\n", dev->name); + network_tx(dev->abLoopBuf, dev->xmit_pos); + } + + for (;;) { + /* + * Advance the ring counter register and check the next tmd. + */ + const uint32_t GCPhysPrevTmd = PHYSADDR(dev, CSR_CXDA(dev)); + if (CSR_XMTRC(dev) < 2) + CSR_XMTRC(dev) = CSR_XMTRL(dev); + else + CSR_XMTRC(dev)--; + + TMD dummy; + if (!pcnetTdtePoll(dev, &dummy)) { + /* + * Underflow! + */ + tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1; + dev->aCSR[0] |= 0x0200; /* set TINT */ + if (!CSR_DXSUFLO(dev)) /* stop on xmit underflow */ + dev->aCSR[0] &= ~0x0010; /* clear TXON */ + pcnetTmdStorePassHost(dev, &tmd, GCPhysPrevTmd); + pcnetlog(3,"%s: pcnetAsyncTransmit: Underflow!!!\n", dev->name); + break; + } + + /* release & save the previous tmd, pass it to the host */ + pcnetTmdStorePassHost(dev, &tmd, GCPhysPrevTmd); + + /* + * The next tmd. + */ + pcnetTmdLoad(dev, &tmd, PHYSADDR(dev, CSR_CXDA(dev)), 0); + cb = 4096 - tmd.tmd1.bcnt; + if (dev->xmit_pos + cb <= MAX_FRAME) { /** @todo this used to be ... + cb < MAX_FRAME. */ + int off = dev->xmit_pos; + dev->xmit_pos = cb + off; + DMAPageRead(PHYSADDR(dev, tmd.tmd0.tbadr), dev->abLoopBuf + off, cb); + } + + /* + * Done already? + */ + if (tmd.tmd1.enp) { + if (fLoopback) { + pcnetlog(3, "%s: pcnetAsyncTransmit: receive loopback enp\n", dev->name); + pcnetReceiveNoSync(dev, dev->abLoopBuf, dev->xmit_pos); + } else { + pcnetlog(3, "%s: pcnetAsyncTransmit: transmit loopbuf enp\n", dev->name); + network_tx(dev->abLoopBuf, dev->xmit_pos); + } + + /* Write back the TMD, pass it to the host */ + pcnetTmdStorePassHost(dev, &tmd, PHYSADDR(dev, CSR_CXDA(dev))); + + /* advance the ring counter register */ + if (CSR_XMTRC(dev) < 2) + CSR_XMTRC(dev) = CSR_XMTRL(dev); + else + CSR_XMTRC(dev)--; + break; + } + } /* the loop */ + } + /* Update TDMD, TXSTRT and TINT. */ + dev->aCSR[0] &= ~0x0008; /* clear TDMD */ + dev->aCSR[4] |= 0x0008; /* set TXSTRT */ + if ( !CSR_TOKINTD(dev) /* Transmit OK Interrupt Disable, no infl. on errors. */ + || (CSR_LTINTEN(dev) && tmd.tmd1.ltint) + || tmd.tmd1.err) { + dev->aCSR[0] |= 0x0200; /* set TINT */ + pcnetUpdateIrq(dev); + } + if (--cMax == 0) + break; + } while (CSR_TXON(dev)); /* transfer on */ +} + + +/** + * Poll for changes in RX and TX descriptor rings. + */ +static void +pcnetPollRxTx(nic_t *dev) +{ + if (CSR_RXON(dev)) { + /* + * The second case is important for pcnetWaitReceiveAvail(): If CSR_CRST(dev) was + * true but pcnetCanReceive() returned false for some other reason we need to check + * _now_ if we have to wakeup pcnetWaitReceiveAvail(). + */ + if (HOST_IS_OWNER(CSR_CRST(dev))) + pcnetRdtePoll(dev); + } + + if (CSR_TDMD(dev) || (CSR_TXON(dev) && !CSR_DPOLL(dev))) + pcnetAsyncTransmit(dev); +} + + +static void +pcnetPollTimer(nic_t *dev) +{ + if (CSR_TDMD(dev)) + pcnetAsyncTransmit(dev); + + pcnetUpdateIrq(dev); + + if (!CSR_STOP(dev) && !CSR_SPND(dev) && !CSR_DPOLL(dev)) + pcnetPollRxTx(dev); +} + + +static void +pcnetHardReset(nic_t *dev) +{ + pcnetlog(2, "%s: pcnetHardReset\n", dev->name); + + dev->aBCR[BCR_MSRDA] = 0x0005; + dev->aBCR[BCR_MSWRA] = 0x0005; + dev->aBCR[BCR_MC ] = 0x0002; + dev->aBCR[BCR_LNKST] = 0x00c0; + dev->aBCR[BCR_LED1 ] = 0x0084; + dev->aBCR[BCR_LED2 ] = 0x0088; + dev->aBCR[BCR_LED3 ] = 0x0090; + + /* For ISA PnP cards, BCR8 reports IRQ/DMA (e.g. 0x0035 means IRQ 3, DMA 5). */ + if (dev->board == PCNET_ISA) + dev->aBCR[8] = (dev->dma_channel) | (dev->base_irq << 4); + + dev->aBCR[BCR_FDC ] = 0x0000; + dev->aBCR[BCR_BSBC ] = 0x9001; + dev->aBCR[BCR_EECAS] = 0x0002; + dev->aBCR[BCR_SWS ] = 0x0200; + dev->iLog2DescSize = 3; + dev->aBCR[BCR_PLAT ] = 0xff06; + + /* Reset the error counter. */ + dev->uCntBadRMD = 0; + + pcnetSoftReset(dev); +} + + +static void +pcnet_csr_writew(nic_t *dev, uint16_t rap, uint16_t val) +{ + uint16_t old_inea = CSR_INEA(dev); + + pcnetlog(1, "%s: pcnet_csr_writew: rap=%d val=%#06x\n", dev->name, rap, val); + switch (rap) { + case 0: + /* Clear any interrupt flags. */ + dev->aCSR[0] &= ~(val & 0x7f00); + dev->aCSR[0] = (dev->aCSR[0] & ~0x0040) | (val & 0x0048); + val = (val & 0x007f) | (dev->aCSR[0] & 0x7f00); + + /* If STOP, STRT and INIT are set, clear STRT and INIT */ + if ((val & 7) == 7) + val &= ~3; + + pcnetlog(2, "%s: CSR0 val = %04x, val2 = %04x\n", dev->name, val, dev->aCSR[0]); + + if (old_inea && !(val & 0x40)) { + pcnetlog(3, "%s: pcnet_csr_writew(): Disable IRQ\n", dev->name); + dev->iISR = 0; + dev->aCSR[0] &= ~0x0080; + pcnet_do_irq(dev, 0); + } + + if (!CSR_STOP(dev) && (val & 4)) { + pcnetlog(3, "%s: pcnet_csr_writew(): Stop\n", dev->name); + pcnetStop(dev); + } + + if (!CSR_INIT(dev) && (val & 1)) { + pcnetlog(3, "%s: pcnet_csr_writew(): Init\n", dev->name); + pcnetInit(dev); + } + + if (!CSR_STRT(dev) && (val & 2)) { + pcnetlog(3, "%s: pcnet_csr_writew(): Start\n", dev->name); + pcnetStart(dev); + } + + if (CSR_TDMD(dev)) { + pcnetlog(3, "%s: pcnet_csr_writew(): Transmit\n", dev->name); + pcnetAsyncTransmit(dev); + } + + return; + case 2: /* IADRH */ + if (dev->board == PCNET_ISA) + val &= 0x00ff; /* Upper 8 bits ignored on ISA chips. */ + case 1: /* IADRL */ + case 8: /* LADRF 0..15 */ + case 9: /* LADRF 16..31 */ + case 10: /* LADRF 32..47 */ + case 11: /* LADRF 48..63 */ + case 12: /* PADR 0..15 */ + case 13: /* PADR 16..31 */ + case 14: /* PADR 32..47 */ + case 18: /* CRBAL */ + case 19: /* CRBAU */ + case 20: /* CXBAL */ + case 21: /* CXBAU */ + case 22: /* NRBAL */ + case 23: /* NRBAU */ + case 26: /* NRDAL */ + case 27: /* NRDAU */ + case 28: /* CRDAL */ + case 29: /* CRDAU */ + case 32: /* NXDAL */ + case 33: /* NXDAU */ + case 34: /* CXDAL */ + case 35: /* CXDAU */ + case 36: /* NNRDL */ + case 37: /* NNRDU */ + case 38: /* NNXDL */ + case 39: /* NNXDU */ + case 40: /* CRBCL */ + case 41: /* CRBCU */ + case 42: /* CXBCL */ + case 43: /* CXBCU */ + case 44: /* NRBCL */ + case 45: /* NRBCU */ + case 46: /* POLL */ + case 47: /* POLLINT */ + case 72: /* RCVRC */ + case 74: /* XMTRC */ + case 112: /* MISSC */ + if (CSR_STOP(dev) || CSR_SPND(dev)) + break; + return; + case 3: /* Interrupt Mask and Deferral Control */ + break; + case 4: /* Test and Features Control */ + dev->aCSR[4] &= ~(val & 0x026a); + val &= ~0x026a; + val |= dev->aCSR[4] & 0x026a; + break; + case 5: /* Extended Control and Interrupt 1 */ + dev->aCSR[5] &= ~(val & 0x0a90); + val &= ~0x0a90; + val |= dev->aCSR[5] & 0x0a90; + break; + case 16: + pcnet_csr_writew(dev,1,val); + return; + case 17: + pcnet_csr_writew(dev,2,val); + return; + /* + * 24 and 25 are the Base Address of Receive Descriptor. + * We combine and mirror these in GCRDRA. + */ + case 24: /* BADRL */ + case 25: /* BADRU */ + if (!CSR_STOP(dev) && !CSR_SPND(dev)) { + pcnetlog(3, "%s: WRITE CSR%d, %#06x, ignoring!!\n", dev->name, rap, val); + return; + } + if (rap == 24) + dev->GCRDRA = (dev->GCRDRA & 0xffff0000) | (val & 0x0000ffff); + else + dev->GCRDRA = (dev->GCRDRA & 0x0000ffff) | ((val & 0x0000ffff) << 16); + pcnetlog(3, "%s: WRITE CSR%d, %#06x => GCRDRA=%08x (alt init)\n", dev->name, rap, val, dev->GCRDRA); + if (dev->GCRDRA & (dev->iLog2DescSize - 1)) + pcnetlog(1, "%s: Warning: Misaligned RDRA (GCRDRA=%#010x)\n", dev->name, dev->GCRDRA); + break; + /* + * 30 & 31 are the Base Address of Transmit Descriptor. + * We combine and mirrorthese in GCTDRA. + */ + case 30: /* BADXL */ + case 31: /* BADXU */ + if (!CSR_STOP(dev) && !CSR_SPND(dev)) { + pcnetlog(3, "%s: WRITE CSR%d, %#06x !!\n", dev->name, rap, val); + return; + } + if (rap == 30) + dev->GCTDRA = (dev->GCTDRA & 0xffff0000) | (val & 0x0000ffff); + else + dev->GCTDRA = (dev->GCTDRA & 0x0000ffff) | ((val & 0x0000ffff) << 16); + pcnetlog(3, "%s: WRITE CSR%d, %#06x => GCTDRA=%08x (alt init)\n", dev->name, rap, val, dev->GCTDRA); + if (dev->GCTDRA & (dev->iLog2DescSize - 1)) + pcnetlog(1, "%s: Warning: Misaligned TDRA (GCTDRA=%#010x)\n", dev->name, dev->GCTDRA); + break; + case 58: /* Software Style */ + pcnet_bcr_writew(dev,BCR_SWS,val); + break; + /* + * Registers 76 and 78 aren't stored correctly (see todos), but I'm don't dare + * try fix that right now. So, as a quick hack for 'alt init' I'll just correct them here. + */ + case 76: /* RCVRL */ /** @todo call pcnetUpdateRingHandlers */ + /** @todo receive ring length is stored in two's complement! */ + case 78: /* XMTRL */ /** @todo call pcnetUpdateRingHandlers */ + /** @todo transmit ring length is stored in two's complement! */ + if (!CSR_STOP(dev) && !CSR_SPND(dev)) { + pcnetlog(3, "%s: WRITE CSR%d, %#06x !!\n", dev->name, rap, val); + return; + } + pcnetlog(3, "%s: WRITE CSR%d, %#06x (hacked %#06x) (alt init)\n", dev->name, + rap, val, 1 + ~val); + val = 1 + ~val; + + /* + * HACK ALERT! Set the counter registers too. + */ + dev->aCSR[rap - 4] = val; + break; + default: + return; + } + + dev->aCSR[rap] = val; +} + + +/** + * Encode a 32-bit link speed into a custom 16-bit floating-point value + */ +static uint16_t +pcnetLinkSpd(uint32_t speed) +{ + unsigned exp = 0; + + while (speed & 0xFFFFE000) { + speed /= 10; + ++exp; + } + return (exp << 13) | speed; +} + + +static uint16_t +pcnet_csr_readw(nic_t *dev, uint16_t rap) +{ + uint16_t val; + + switch (rap) { + case 0: + pcnetUpdateIrq(dev); + val = dev->aCSR[0]; + val |= (val & 0x7800) ? 0x8000 : 0; + break; + case 16: + return pcnet_csr_readw(dev,1); + case 17: + return pcnet_csr_readw(dev,2); + case 58: + return pcnet_bcr_readw(dev,BCR_SWS); + case 68: /* Custom register to pass link speed to driver */ + return pcnetLinkSpd(dev->u32LinkSpeed); + case 88: + val = dev->aCSR[89]; + val <<= 16; + val |= dev->aCSR[88]; + break; + default: + val = dev->aCSR[rap]; + break; + } + pcnetlog(3, "%s: pcnet_csr_readw rap=%d val=0x%04x\n", dev->name, rap, val); + return val; +} + + +static void +pcnet_bcr_writew(nic_t *dev, uint16_t rap, uint16_t val) +{ + rap &= 0x7f; + pcnetlog(3, "%s: pcnet_bcr_writew rap=%d val=0x%04x\n", dev->name, rap, val); + switch (rap) { + case BCR_SWS: + if (!(CSR_STOP(dev) || CSR_SPND(dev))) + return; + val &= ~0x0300; + switch (val & 0x00ff) { + default: + case 0: + val |= 0x0200; /* 16 bit */ + dev->iLog2DescSize = 3; + dev->GCUpperPhys = (0xff00 & dev->aCSR[2]) << 16; + break; + case 1: + val |= 0x0100; /* 32 bit */ + dev->iLog2DescSize = 4; + dev->GCUpperPhys = 0; + break; + case 2: + case 3: + val |= 0x0300; /* 32 bit */ + dev->iLog2DescSize = 4; + dev->GCUpperPhys = 0; + break; + } + /* fall through */ + case BCR_LNKST: + case BCR_LED1: + case BCR_LED2: + case BCR_LED3: + case BCR_MC: + case BCR_FDC: + case BCR_BSBC: + case BCR_EECAS: + case BCR_PLAT: + dev->aBCR[rap] = val; + break; + default: + break; + } +} + + +static uint16_t +pcnet_bcr_readw(nic_t *dev, uint16_t rap) +{ + uint16_t val; + rap &= 0x7f; + switch (rap) { + case BCR_LNKST: + case BCR_LED1: + case BCR_LED2: + case BCR_LED3: + val = dev->aBCR[rap] & ~0x8000; + val |= (val & 0x017f & dev->u32Lnkst) ? 0x8000 : 0; + break; + default: + val = rap < BCR_MAX_RAP ? dev->aBCR[rap] : 0; + break; + } + + pcnetlog(3, "pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val); + return val; +} + + +static void +pcnet_word_write(nic_t *dev, uint32_t addr, uint16_t val) +{ + pcnetlog(3, "%s: pcnet_word_write: addr = %04x, val = %04x, DWIO not set = %04x\n", dev->name, addr & 0x0f, val, !BCR_DWIO(dev)); + + if (!BCR_DWIO(dev)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + pcnetPollTimer(dev); + pcnet_csr_writew(dev, dev->u32RAP, val); + pcnetUpdateIrq(dev); + break; + case 0x02: + dev->u32RAP = val & 0x7f; + break; + case 0x06: + pcnet_bcr_writew(dev, dev->u32RAP, val); + break; + } + } +} + + +static uint16_t +pcnet_word_read(nic_t *dev, uint32_t addr) +{ + uint16_t val = 0xffff; + + if (!BCR_DWIO(dev)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */ + /** Polling is then useless here and possibly expensive. */ + if (!CSR_DPOLL(dev)) + pcnetPollTimer(dev); + + val = pcnet_csr_readw(dev, dev->u32RAP); + if (dev->u32RAP == 0) + goto skip_update_irq; + break; + case 0x02: + val = dev->u32RAP; + goto skip_update_irq; + case 0x04: + pcnetSoftReset(dev); + val = 0; + break; + case 0x06: + val = pcnet_bcr_readw(dev, dev->u32RAP); + break; + } + } + + pcnetUpdateIrq(dev); + +skip_update_irq: + pcnetlog(3, "%s: pcnet_word_read: addr = %04x, val = %04x, DWIO not set = %04x\n", dev->name, addr & 0x0f, val, !BCR_DWIO(dev)); + + return(val); +} + + +static void +pcnet_dword_write(nic_t *dev, uint32_t addr, uint32_t val) +{ + if (BCR_DWIO(dev)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + pcnetPollTimer(dev); + pcnet_csr_writew(dev, dev->u32RAP, val & 0xffff); + pcnetUpdateIrq(dev); + break; + case 0x04: + dev->u32RAP = val & 0x7f; + break; + case 0x0c: + pcnet_bcr_writew(dev, dev->u32RAP, val & 0xffff); + break; + } + } else if ((addr & 0x0f) == 0) { + /* switch device to dword i/o mode */ + pcnet_bcr_writew(dev, BCR_BSBC, pcnet_bcr_readw(dev, BCR_BSBC) | 0x0080); + pcnetlog(3, "%s: device switched into dword i/o mode\n", dev->name); + }; +} + + +static uint32_t +pcnet_dword_read(nic_t *dev, uint32_t addr) +{ + uint32_t val = 0xffffffff; + + if (BCR_DWIO(dev)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + if (!CSR_DPOLL(dev)) + pcnetPollTimer(dev); + val = pcnet_csr_readw(dev, dev->u32RAP); + if (dev->u32RAP == 0) + goto skip_update_irq; + break; + case 0x04: + val = dev->u32RAP; + goto skip_update_irq; + case 0x08: + pcnetSoftReset(dev); + val = 0; + break; + case 0x0c: + val = pcnet_bcr_readw(dev, dev->u32RAP); + break; + } + } + + pcnetUpdateIrq(dev); + +skip_update_irq: + pcnetlog(3, "%s: Read Long mode, addr = %08x, val = %08x\n", dev->name, addr, val); + return(val); +} + + +static void +pcnet_aprom_writeb(nic_t *dev, uint32_t addr, uint32_t val) +{ + /* Check APROMWE bit to enable write access */ + if (pcnet_bcr_readw(dev, 2) & 0x80) + dev->aPROM[addr & 0x0f] = val & 0xff; +} + + +static uint32_t +pcnet_aprom_readb(nic_t *dev, uint32_t addr) +{ + uint32_t val = dev->aPROM[addr & 15]; + + return val; +} + + +static void +pcnet_write(nic_t *dev, uint32_t addr, uint32_t val, int len) +{ + uint16_t off = addr & 0x1f; + + pcnetlog(3, "%s: write addr %x, val %x, off %x, len %d\n", dev->name, addr, val, off, len); + + if (off < 0x10) { + if (!BCR_DWIO(dev) && len == 1) + pcnet_aprom_writeb(dev, addr, val); + else if (!BCR_DWIO(dev) && ((addr & 1) == 0) && len == 2) { + pcnet_aprom_writeb(dev, addr, val); + pcnet_aprom_writeb(dev, addr + 1, val >> 8); + } else if (BCR_DWIO(dev) && ((addr & 3) == 0) && len == 4) { + pcnet_aprom_writeb(dev, addr, val); + pcnet_aprom_writeb(dev, addr + 1, val >> 8); + pcnet_aprom_writeb(dev, addr + 2, val >> 16); + pcnet_aprom_writeb(dev, addr + 3, val >> 24); + } + } else { + if (len == 2) + pcnet_word_write(dev, addr, val); + else if (len == 4) + pcnet_dword_write(dev, addr, val); + } +} + + +static void +pcnet_writeb(uint16_t addr, uint8_t val, void *priv) +{ + pcnet_write((nic_t *)priv, addr, val, 1); +} + + +static void +pcnet_writew(uint16_t addr, uint16_t val, void *priv) +{ + pcnet_write((nic_t *)priv, addr, val, 2); +} + + +static void +pcnet_writel(uint16_t addr, uint32_t val, void *priv) +{ + pcnet_write((nic_t *)priv, addr, val, 4); +} + + +static uint32_t +pcnet_read(nic_t *dev, uint32_t addr, int len) +{ + uint32_t retval = 0xffffffff; + uint16_t off = addr & 0x1f; + + pcnetlog(3, "%s: read addr %x, off %x, len %d\n", dev->name, addr, off, len); + + if (off < 0x10) { + if (!BCR_DWIO(dev) && len == 1) + retval = pcnet_aprom_readb(dev, addr); + else if (!BCR_DWIO(dev) && ((addr & 1) == 0) && len == 2) + retval = pcnet_aprom_readb(dev, addr) | (pcnet_aprom_readb(dev, addr + 1) << 8); + else if (BCR_DWIO(dev) && ((addr & 3) == 0) && len == 4) { + retval = pcnet_aprom_readb(dev, addr) | (pcnet_aprom_readb(dev, addr + 1) << 8) | + (pcnet_aprom_readb(dev, addr + 2) << 16) | (pcnet_aprom_readb(dev, addr + 3) << 24); + } + } else { + if (len == 2) + retval = pcnet_word_read(dev, addr); + else if (len == 4) + retval = pcnet_dword_read(dev, addr); + } + + pcnetlog(3, "%s: value in read - %08x\n", dev->name, retval); + return(retval); +} + + +static uint8_t +pcnet_readb(uint16_t addr, void *priv) +{ + return(pcnet_read((nic_t *)priv, addr, 1)); +} + + +static uint16_t +pcnet_readw(uint16_t addr, void *priv) +{ + return(pcnet_read((nic_t *)priv, addr, 2)); +} + + +static uint32_t +pcnet_readl(uint16_t addr, void *priv) +{ + return(pcnet_read((nic_t *)priv, addr, 4)); +} + + +static void +pcnet_mmio_writeb(uint32_t addr, uint8_t val, void *priv) +{ + pcnet_write((nic_t *)priv, addr, val, 1); +} + + +static void +pcnet_mmio_writew(uint32_t addr, uint16_t val, void *priv) +{ + pcnet_write((nic_t *)priv, addr, val, 2); +} + + +static void +pcnet_mmio_writel(uint32_t addr, uint32_t val, void *priv) +{ + pcnet_write((nic_t *)priv, addr, val, 4); +} + + +static uint8_t +pcnet_mmio_readb(uint32_t addr, void *priv) +{ + return(pcnet_read((nic_t *)priv, addr, 1)); +} + + +static uint16_t +pcnet_mmio_readw(uint32_t addr, void *priv) +{ + return(pcnet_read((nic_t *)priv, addr, 2)); +} + + +static uint32_t +pcnet_mmio_readl(uint32_t addr, void *priv) +{ + return(pcnet_read((nic_t *)priv, addr, 4)); +} + + +static void +pcnet_mem_init(nic_t *dev, uint32_t addr) +{ + mem_mapping_add(&dev->mmio_mapping, addr, 32, + pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl, + pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +pcnet_mem_set_addr(nic_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->mmio_mapping, base, 32); +} + + +static void +pcnet_mem_disable(nic_t *dev) +{ + mem_mapping_disable(&dev->mmio_mapping); +} + + +static void +pcnet_ioremove(nic_t *dev, uint16_t addr, int len) +{ + if (dev->is_pci || dev->is_vlb) { + io_removehandler(addr, len, + pcnet_readb, pcnet_readw, pcnet_readl, + pcnet_writeb, pcnet_writew, pcnet_writel, dev); + } else { + io_removehandler(addr, len, + pcnet_readb, pcnet_readw, NULL, + pcnet_writeb, pcnet_writew, NULL, dev); + } +} + + +static void +pcnet_ioset(nic_t *dev, uint16_t addr, int len) +{ + pcnet_ioremove(dev, addr, len); + + if (dev->is_pci || dev->is_vlb) { + io_sethandler(addr, len, + pcnet_readb, pcnet_readw, pcnet_readl, + pcnet_writeb, pcnet_writew, pcnet_writel, dev); + } else { + io_sethandler(addr, len, + pcnet_readb, pcnet_readw, NULL, + pcnet_writeb, pcnet_writew, NULL, dev); + } +} + + +static void +pcnet_pci_write(int func, int addr, uint8_t val, void *p) +{ + nic_t *dev = (nic_t *)p; + uint8_t valxor; + + pcnetlog(4, "%s: Write value %02X to register %02X\n", dev->name, val, addr & 0xff); + + switch (addr) { + case 0x04: + valxor = (val & 0x57) ^ pcnet_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + pcnet_ioremove(dev, dev->PCIBase, 32); + if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) + pcnet_ioset(dev, dev->PCIBase, 32); + } + if (valxor & PCI_COMMAND_MEM) { + pcnet_mem_disable(dev); + if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) + pcnet_mem_set_addr(dev, dev->MMIOBase); + } + pcnet_pci_regs[addr] = val & 0x57; + break; + + case 0x05: + pcnet_pci_regs[addr] = val & 0x01; + break; + + case 0x0D: + pcnet_pci_regs[addr] = val; + break; + + case 0x10: case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + pcnet_ioremove(dev, dev->PCIBase, 32); + /* Then let's set the PCI regs. */ + pcnet_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + pcnet_pci_bar[0].addr &= 0xff00; + dev->PCIBase = pcnet_pci_bar[0].addr; + /* Log the new base. */ + pcnetlog(4, "%s: New I/O base is %04X\n" , dev->name, dev->PCIBase); + /* We're done, so get out of the here. */ + if (pcnet_pci_regs[4] & PCI_COMMAND_IO) { + if (dev->PCIBase != 0) + pcnet_ioset(dev, dev->PCIBase, 32); + } + return; + + case 0x15: case 0x16: case 0x17: + /* MMIO Base set. */ + /* First, remove the old I/O. */ + pcnet_mem_disable(dev); + /* Then let's set the PCI regs. */ + pcnet_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + pcnet_pci_bar[1].addr &= 0xffffc000; + dev->MMIOBase = pcnet_pci_bar[1].addr & 0xffffc000; + /* Log the new base. */ + pcnetlog(4, "%s: New MMIO base is %08X\n" , dev->name, dev->MMIOBase); + /* We're done, so get out of the here. */ + if (pcnet_pci_regs[4] & PCI_COMMAND_MEM) { + if (dev->MMIOBase != 0) + pcnet_mem_set_addr(dev, dev->MMIOBase); + } + return; + + case 0x3C: + dev->base_irq = val; + pcnet_pci_regs[addr] = val; + return; + } +} + + +static uint8_t +pcnet_pci_read(int func, int addr, void *p) +{ + nic_t *dev = (nic_t *)p; + + pcnetlog(4, "%s: Read to register %02X\n", dev->name, addr & 0xff); + + switch (addr) { + case 0x00: + return 0x22; + case 0x01: + return 0x10; + case 0x02: + return 0x00; + case 0x03: + return 0x20; + case 0x04: + return pcnet_pci_regs[0x04] & 0x57; /*Respond to IO and memory accesses*/ + case 0x05: + return pcnet_pci_regs[0x05] & 0x01; + case 0x06: + return 0x80; + case 0x07: + return 2; + case 0x08: + return 0x10; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*devubclass*/ + case 0x0B: + return 2; /*Class code*/ + case 0x0D: + return pcnet_pci_regs[addr]; + case 0x0E: + return 0; /*Header type */ + case 0x10: + return 1; /*I/O space*/ + case 0x11: + return pcnet_pci_bar[0].addr_regs[1]; + case 0x12: + return pcnet_pci_bar[0].addr_regs[2]; + case 0x13: + return pcnet_pci_bar[0].addr_regs[3]; + case 0x14: + return 0; /*Memory space*/ + case 0x15: + return pcnet_pci_bar[1].addr_regs[1]; + case 0x16: + return pcnet_pci_bar[1].addr_regs[2]; + case 0x17: + return pcnet_pci_bar[1].addr_regs[3]; + case 0x3C: + return dev->base_irq; + case 0x3D: + return PCI_INTA; + case 0x3E: + return 0x06; + case 0x3F: + return 0xff; + } + + return(0); +} + + +/** + * Check if the device/driver can receive data now. + * + * Worker for pcnetNetworkDown_WaitReceiveAvail(). This must be called before + * the pfnRecieve() method is called. + * + * @returns VBox status code. + * @param pThis The PCnet instance data. + */ +static void +pcnetCanReceive(nic_t *dev) +{ + if (!CSR_DRX(dev) && !CSR_STOP(dev) && !CSR_SPND(dev)) { + if (HOST_IS_OWNER(CSR_CRST(dev)) && dev->GCRDRA) + pcnetRdtePoll(dev); + + if (HOST_IS_OWNER(CSR_CRST(dev))) { + /** @todo Notify the guest _now_. Will potentially increase the interrupt load */ + if (dev->fSignalRxMiss) + dev->aCSR[0] |= 0x1000; /* Set MISS flag */ + } + } +} + + +static void * +pcnet_init(const device_t *info) +{ + uint32_t mac; + nic_t *dev; +#ifdef ENABLE_NIC_LOG + int i; +#endif + int c; + uint16_t checksum; + + /* Get the desired debug level. */ +#ifdef ENABLE_NIC_LOG + i = device_get_config_int("debug"); + if (i > 0) pcnet_do_log = i; +#endif + + dev = malloc(sizeof(nic_t)); + memset(dev, 0x00, sizeof(nic_t)); + dev->name = info->name; + dev->board = info->local; + + dev->is_pci = !!(info->flags & DEVICE_PCI); + dev->is_vlb = !!(info->flags & DEVICE_VLB); + + if (dev->is_pci) { + pcnet_mem_init(dev, 0x0fffff00); + pcnet_mem_disable(dev); + } + + dev->maclocal[0] = 0x00; /* 00:0C:87 (AMD OID) */ + dev->maclocal[1] = 0x0C; + dev->maclocal[2] = 0x87; + + /* See if we have a local MAC address configured. */ + mac = device_get_config_mac("mac", -1); + + /* Set up our BIA. */ + if (mac & 0xff000000) { + /* Generate new local MAC. */ + dev->maclocal[3] = random_generate(); + dev->maclocal[4] = random_generate(); + dev->maclocal[5] = random_generate(); + mac = (((int) dev->maclocal[3]) << 16); + mac |= (((int) dev->maclocal[4]) << 8); + mac |= ((int) dev->maclocal[5]); + device_set_config_mac("mac", mac); + } else { + dev->maclocal[3] = (mac>>16) & 0xff; + dev->maclocal[4] = (mac>>8) & 0xff; + dev->maclocal[5] = (mac & 0xff); + } + + memcpy(dev->aPROM, dev->maclocal, sizeof(dev->maclocal)); + + /* Reserved Location: must be 00h */ + dev->aPROM[6] = dev->aPROM[7] = 0x00; + + /* Reserved Location: must be 00h */ + dev->aPROM[8] = 0x00; + + /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */ + if (dev->is_pci) + dev->aPROM[9] = 0x11; + else if (dev->is_vlb) + dev->aPROM[9] = 0x10; + else + dev->aPROM[9] = 0x00; + + /* User programmable space, init with 0 */ + dev->aPROM[10] = dev->aPROM[11] = 0x00; + + /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh + and bytes 0Eh and 0Fh, must therefore be initialized with 0! */ + dev->aPROM[12] = dev->aPROM[13] = 0x00; + + /* Must be ASCII W (57h) if compatibility to AMD + driver software is desired */ + dev->aPROM[14] = dev->aPROM[15] = 0x57; + + for (c = 0, checksum = 0; c < 16; c++) + checksum += dev->aPROM[c]; + + *(uint16_t *)&dev->aPROM[12] = cpu_to_le16(checksum); + + /* + * Make this device known to the I/O system. + * PCI devices start with address spaces inactive. + */ + if (dev->is_pci) { + /* + * Configure the PCI space registers. + * + * We do this here, so the I/O routines are generic. + */ + + /* Enable our address space in PCI. */ + pcnet_pci_bar[0].addr_regs[0] = 1; + pcnet_pci_bar[1].addr_regs[0] = 0; + pcnet_pci_regs[0x04] = 3; + + /* Add device to the PCI bus, keep its slot number. */ + dev->card = pci_add_card(PCI_ADD_NORMAL, + pcnet_pci_read, pcnet_pci_write, dev); + } else { + dev->base_address = device_get_config_hex16("base"); + dev->base_irq = device_get_config_int("irq"); + if (dev->is_vlb) + dev->dma_channel = 0; + else + dev->dma_channel = device_get_config_int("dma"); + pcnet_ioset(dev, dev->base_address, 0x20); + } + + pcnetlog(2, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, dev->base_address, dev->base_irq, + dev->aPROM[0], dev->aPROM[1], dev->aPROM[2], + dev->aPROM[3], dev->aPROM[4], dev->aPROM[5]); + + pcnetlog(1, "%s: %s attached IO=0x%X IRQ=%d\n", dev->name, + dev->is_pci?"PCI":"ISA", dev->base_address, dev->base_irq); + + /* Reset the board. */ + pcnetHardReset(dev); + + /* Attach ourselves to the network module. */ + network_attach(dev, dev->aPROM, pcnetReceiveNoSync); + + return(dev); +} + + +static void +pcnet_close(void *priv) +{ + nic_t *dev = (nic_t *)priv; + + pcnetlog(1, "%s: closed\n", dev->name); + + free(dev); +} + + +static const device_config_t pcnet_pci_config[] = +{ + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + + +static const device_config_t pcnet_isa_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x300, + { + { + "0x300", 0x300 + }, + { + "0x320", 0x320 + }, + { + "0x340", 0x340 + }, + { + "0x360", 0x360 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 9", 9 + }, + { + "" + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 5, + { + { + "DMA 3", 3 + }, + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + +static const device_config_t pcnet_vlb_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x300, + { + { + "0x300", 0x300 + }, + { + "0x320", 0x320 + }, + { + "0x340", 0x340 + }, + { + "0x360", 0x360 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 9", 9 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + +const device_t pcnet_pci_device = { + "AMD PCnet-PCI", + DEVICE_PCI, + PCNET_PCI, + pcnet_init, pcnet_close, NULL, + NULL, NULL, NULL, + pcnet_pci_config +}; + +const device_t pcnet_isa_device = { + "AMD PCnet-ISA", + DEVICE_AT | DEVICE_ISA, + PCNET_ISA, + pcnet_init, pcnet_close, NULL, + NULL, NULL, NULL, + pcnet_isa_config +}; + +const device_t pcnet_vlb_device = { + "AMD PCnet-VL", + DEVICE_VLB, + PCNET_VLB, + pcnet_init, pcnet_close, NULL, + NULL, NULL, NULL, + pcnet_vlb_config +}; diff --git a/src/network/net_pcnet.h b/src/network/net_pcnet.h new file mode 100644 index 000000000..da4859368 --- /dev/null +++ b/src/network/net_pcnet.h @@ -0,0 +1,35 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the AMD PCnet LANCE NIC controller for both the ISA + * and PCI buses. + * + * Version: @(#)net_pcnet.c 1.0.0 2019/11/09 + * + * Authors: Miran Grca, + * TheCollector1995, + * Antony T Curtis + * + * Copyright 2004-2019 Antony T Curtis + * Copyright 2016-2019 Miran Grca. + */ +#ifndef NET_PCNET_H +# define NET_PCNET_H + + +enum { + PCNET_NONE = 0, + PCNET_ISA = 1, /* 16-bit ISA */ + PCNET_PCI = 2, /* 32-bit PCI */ + PCNET_VLB = 3 /* 32-bit VLB */ +}; + + +extern const device_t pcnet_isa_device; +extern const device_t pcnet_pci_device; +extern const device_t pcnet_vlb_device; + +#endif /*NET_PCNET_H*/ diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 3285702f4..8b8304854 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -8,11 +8,11 @@ * * Handle SLiRP library processing. * - * Version: @(#)net_slirp.c 1.0.3 2018/04/29 + * Version: @(#)net_slirp.c 1.0.9 2019/11/14 * * Author: Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -54,9 +54,9 @@ #include "slirp/slirp.h" #include "slirp/queue.h" #include "../86box.h" -#include "../config.h" #include "../device.h" #include "../plat.h" +// #include "../ui.h" #include "network.h" @@ -68,22 +68,22 @@ static event_t *poll_state; #ifdef ENABLE_SLIRP_LOG int slirp_do_log = ENABLE_SLIRP_LOG; -#endif static void -slirp_log(const char *format, ...) +slirp_log(const char *fmt, ...) { -#ifdef ENABLE_SLIRP_LOG va_list ap; if (slirp_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define slirp_log(fmt, ...) +#endif static void @@ -117,10 +117,14 @@ slirp_tic(void) /* Handle the receiving of frames. */ static void -poll_thread(UNUSED(void *arg)) +poll_thread(void *arg) { + uint8_t *mac = (uint8_t *)arg; struct queuepacket *qp; + uint32_t mac_cmp32[2]; + uint16_t mac_cmp16[2]; event_t *evt; + int data_valid = 0; slirp_log("SLiRP: polling started.\n"); thread_set_event(poll_state); @@ -142,18 +146,37 @@ poll_thread(UNUSED(void *arg)) if (slirpq == NULL) break; /* Wait for the next packet to arrive. */ - if (QueuePeek(slirpq) != 0) { + data_valid = 0; + + if (!network_get_wait() && (QueuePeek(slirpq) != 0)) { /* Grab a packet from the queue. */ + // ui_sb_update_icon(SB_NETWORK, 1); + qp = QueueDelete(slirpq); slirp_log("SLiRP: inQ:%d got a %dbyte packet @%08lx\n", QueuePeek(slirpq), qp->len, qp); - poll_card->rx(poll_card->priv, (uint8_t *)qp->data, qp->len); + /* Received MAC. */ + mac_cmp32[0] = *(uint32_t *)(((uint8_t *)qp->data)+6); + mac_cmp16[0] = *(uint16_t *)(((uint8_t *)qp->data)+10); + + /* Local MAC. */ + mac_cmp32[1] = *(uint32_t *)mac; + mac_cmp16[1] = *(uint16_t *)(mac+4); + if ((mac_cmp32[0] != mac_cmp32[1]) || + (mac_cmp16[0] != mac_cmp16[1])) { + + poll_card->rx(poll_card->priv, (uint8_t *)qp->data, qp->len); + data_valid = 1; + } /* Done with this one. */ free(qp); - } else { - /* If we did not get anything, wait a while. */ + } + + /* If we did not get anything, wait a while. */ + if (!data_valid) { + // ui_sb_update_icon(SB_NETWORK, 0); thread_wait_event(evt, 10); } @@ -195,6 +218,8 @@ net_slirp_init(void) int net_slirp_reset(const netcard_t *card, uint8_t *mac) { + // ui_sb_update_icon(SB_NETWORK, 0); + /* Save the callback info. */ poll_card = card; @@ -212,6 +237,8 @@ net_slirp_close(void) { queueADT sl; + // ui_sb_update_icon(SB_NETWORK, 0); + if (slirpq == NULL) return; slirp_log("SLiRP: closing.\n"); @@ -246,11 +273,15 @@ net_slirp_in(uint8_t *pkt, int pkt_len) { if (slirpq == NULL) return; + // ui_sb_update_icon(SB_NETWORK, 1); + network_busy(1); slirp_input((const uint8_t *)pkt, pkt_len); network_busy(0); + + // ui_sb_update_icon(SB_NETWORK, 0); } diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index 8bccbd78d..2148a2142 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -11,15 +11,15 @@ * - SMC/WD 8013EBT (ISA 16-bit); * - SMC/WD 8013EP/A (MCA). * - * Version: @(#)net_wd8003.c 1.0.0 2018/07/19 + * Version: @(#)net_wd8003.c 1.0.6 2019/09/21 * * Authors: Fred N. van Kempen, * TheCollector1995, * Miran Grca, * Peter Grehan, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. * Portions Copyright (C) 2002 MandrakeSoft S.A. * * This program is free software; you can redistribute it and/or modify @@ -49,18 +49,15 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../cpu/cpu.h" -#include "../config.h" -#include "../machine/machine.h" #include "../io.h" #include "../mem.h" #include "../rom.h" +#include "../machine/machine.h" #include "../mca.h" #include "../pci.h" #include "../pic.h" #include "../random.h" #include "../device.h" -#include "../ui.h" #include "network.h" #include "net_dp8390.h" #include "net_wd8003.h" @@ -85,311 +82,242 @@ #define WE_TYPE_SMC8216C 0x2b #define WE_TYPE_WD8013EBP 0x2c +#define WE_ICR_16BIT_SLOT 0x01 + +#define WE_MSR_ENABLE_RAM 0x40 +#define WE_MSR_SOFT_RESET 0x80 + +#define WE_IRR_ENABLE_IRQ 0x80 + +#define WE_ID_ETHERNET 0x01 +#define WE_ID_SOFT_CONFIG 0x20 +#define WE_ID_EXTRA_RAM 0x40 +#define WE_ID_BUS_MCA 0x80 + typedef struct { - dp8390_t dp8390; - mem_mapping_t ram_mapping; - uint32_t ram_addr, ram_size; - uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ + dp8390_t *dp8390; + mem_mapping_t ram_mapping; + uint32_t ram_addr, ram_size; uint8_t maclocal[6]; /* configured MAC (local) address */ + uint8_t bit16, pad; int board; const char *name; uint32_t base_address; - int base_irq; - - /* POS registers, MCA boards only */ - uint8_t pos_regs[8]; - - /* Memory for WD cards*/ - uint8_t reg1; - uint8_t reg5; - uint8_t if_chip; - uint8_t board_chip; + int irq; + + /* POS registers, MCA boards only */ + uint8_t pos_regs[8]; + + /* Memory for WD cards*/ + uint8_t msr, /* Memory Select Register (MSR) */ + icr, /* Interface Configuration Register (ICR) */ + irr, /* Interrupt Request Register (IRR) */ + laar, /* LA Address Register (read by Windows 98!) */ + if_chip, board_chip; } wd_t; -static void wd_rx(void *, uint8_t *, int); -static void wd_tx(wd_t *, uint32_t); #ifdef ENABLE_WD_LOG -int wd_do_log = ENABLE_WD_LOG; -#endif +int WE_do_log = ENABLE_WD_LOG; static void -wdlog(int lvl, const char *fmt, ...) +wdlog(const char *fmt, ...) { -#ifdef ENABLE_WD_LOG va_list ap; - if (wd_do_log >= lvl) { + if (wd_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define wdlog(fmt, ...) +#endif + + +static const int we_int_table[4] = {2, 3, 4, 7}; + static void -wd_interrupt(wd_t *dev, int set) +wd_interrupt(void *priv, int set) { - if (set) - picint(1<base_irq); - else - picintc(1<base_irq); + wd_t *dev = (wd_t *) priv; + + if (!(dev->irr & WE_IRR_ENABLE_IRQ)) + return; + + if (set) + picint(1 << dev->irq); + else + picintc(1 << dev->irq); } + /* reset - restore state to power-up, cancelling all i/o */ static void wd_reset(void *priv) { wd_t *dev = (wd_t *)priv; - wdlog(1, "%s: reset\n", dev->name); + wdlog("%s: reset\n", dev->name); - /* Initialize the MAC address area by doubling the physical address */ - dev->macaddr[0] = dev->dp8390.physaddr[0]; - dev->macaddr[1] = dev->dp8390.physaddr[1]; - dev->macaddr[2] = dev->dp8390.physaddr[2]; - dev->macaddr[3] = dev->dp8390.physaddr[3]; - dev->macaddr[4] = dev->dp8390.physaddr[4]; - dev->macaddr[5] = dev->dp8390.physaddr[5]; - - /* Zero out registers and memory */ - memset(&dev->dp8390.CR, 0x00, sizeof(dev->dp8390.CR) ); - memset(&dev->dp8390.ISR, 0x00, sizeof(dev->dp8390.ISR)); - memset(&dev->dp8390.IMR, 0x00, sizeof(dev->dp8390.IMR)); - memset(&dev->dp8390.DCR, 0x00, sizeof(dev->dp8390.DCR)); - memset(&dev->dp8390.TCR, 0x00, sizeof(dev->dp8390.TCR)); - memset(&dev->dp8390.TSR, 0x00, sizeof(dev->dp8390.TSR)); - memset(&dev->dp8390.RSR, 0x00, sizeof(dev->dp8390.RSR)); - dev->dp8390.tx_timer_active = 0; - dev->dp8390.local_dma = 0; - dev->dp8390.page_start = 0; - dev->dp8390.page_stop = 0; - dev->dp8390.bound_ptr = 0; - dev->dp8390.tx_page_start = 0; - dev->dp8390.num_coll = 0; - dev->dp8390.tx_bytes = 0; - dev->dp8390.fifo = 0; - dev->dp8390.remote_dma = 0; - dev->dp8390.remote_start = 0; - - dev->dp8390.remote_bytes = 0; - - dev->dp8390.tallycnt_0 = 0; - dev->dp8390.tallycnt_1 = 0; - dev->dp8390.tallycnt_2 = 0; - - dev->dp8390.curr_page = 0; - - dev->dp8390.rempkt_ptr = 0; - dev->dp8390.localpkt_ptr = 0; - dev->dp8390.address_cnt = 0; - - memset(&dev->dp8390.mem, 0x00, sizeof(dev->dp8390.mem)); - - /* Set power-up conditions */ - dev->dp8390.CR.stop = 1; - dev->dp8390.CR.rdma_cmd = 4; - dev->dp8390.ISR.reset = 1; - dev->dp8390.DCR.longaddr = 1; - - wd_interrupt(dev, 0); + dp8390_reset(dev->dp8390); } -static uint32_t -wd_chipmem_read(wd_t *dev, uint32_t addr, unsigned int len) + +static void +wd_soft_reset(void *priv) { - uint32_t retval = 0; + wd_t *dev = (wd_t *)priv; - if ((len == 2) && (addr & 0x1)) { - wdlog(3, "%s: unaligned chipmem word read\n", dev->name); - } - - /* ROM'd MAC address */ - if (dev->board == WD8003E) - { - if (addr <= 15) { - retval = dev->macaddr[addr % 16]; - if (len == 2) { - retval |= (dev->macaddr[(addr + 1) % 16] << 8); - } - return(retval); - } - } - - return(0xff); + dp8390_soft_reset(dev->dp8390); } + static uint32_t wd_ram_read(uint32_t addr, unsigned len, void *priv) { - wd_t *dev = (wd_t *)priv; - uint32_t ret; - - if ((addr & 0x3fff) >= 0x2000) - { - if (len == 2) - return 0xffff; - else if (len == 1) - return 0xff; - else - return 0xffffffff; - } - - ret = dev->dp8390.mem[addr & 0x1fff]; - if (len == 2 || len == 4) - ret |= dev->dp8390.mem[(addr+1) & 0x1fff] << 8; - if (len == 4) { - ret |= dev->dp8390.mem[(addr+2) & 0x1fff] << 16; - ret |= dev->dp8390.mem[(addr+3) & 0x1fff] << 24; - } - - return ret; + wd_t *dev = (wd_t *)priv; + uint32_t ret; + uint16_t ram_mask = dev->ram_size - 1; + + ret = dev->dp8390->mem[addr & ram_mask]; + + if (len == 2) + ret |= dev->dp8390->mem[(addr + 1) & ram_mask] << 8; + + return ret; } + static uint8_t wd_ram_readb(uint32_t addr, void *priv) { - wd_t *dev = (wd_t *)priv; - - return wd_ram_read(addr, 1, dev); + wd_t *dev = (wd_t *)priv; + + return wd_ram_read(addr, 1, dev); } + static uint16_t wd_ram_readw(uint32_t addr, void *priv) { - wd_t *dev = (wd_t *)priv; - - return wd_ram_read(addr, 2, dev); + wd_t *dev = (wd_t *)priv; + + return wd_ram_read(addr, 2, dev); } -static uint32_t -wd_ram_readl(uint32_t addr, void *priv) -{ - wd_t *dev = (wd_t *)priv; - - return wd_ram_read(addr, 4, dev); -} static void wd_ram_write(uint32_t addr, uint32_t val, unsigned len, void *priv) { - wd_t *dev = (wd_t *)priv; + wd_t *dev = (wd_t *)priv; + uint16_t ram_mask = dev->ram_size - 1; - if ((addr & 0x3fff) >= 0x2000) - return; + dev->dp8390->mem[addr & ram_mask] = val & 0xff; - dev->dp8390.mem[addr & 0x1fff] = val & 0xff; - if (len == 2 || len == 4) - dev->dp8390.mem[(addr+1) & 0x1fff] = val >> 8; - if (len == 4) { - dev->dp8390.mem[(addr+2) & 0x1fff] = val >> 16; - dev->dp8390.mem[(addr+3) & 0x1fff] = val >> 24; - } + if (len == 2) + dev->dp8390->mem[(addr + 1) & ram_mask] = val >> 8; } + static void wd_ram_writeb(uint32_t addr, uint8_t val, void *priv) { - wd_t *dev = (wd_t *)priv; + wd_t *dev = (wd_t *)priv; - wd_ram_write(addr, val, 1, dev); + wd_ram_write(addr, val, 1, dev); } + static void wd_ram_writew(uint32_t addr, uint16_t val, void *priv) { - wd_t *dev = (wd_t *)priv; + wd_t *dev = (wd_t *)priv; - wd_ram_write(addr, val, 2, dev); + wd_ram_write(addr, val, 2, dev); } -static void -wd_ram_writel(uint32_t addr, uint32_t val, void *priv) + +static int +wd_get_irq_index(wd_t *dev) { - wd_t *dev = (wd_t *)priv; + uint8_t i, irq = 255; - wd_ram_write(addr, val, 4, dev); + for (i = 0; i < 4; i++) { + if (we_int_table[i] == dev->irq) + irq = i; + } + if (irq != 255) + return ((irq & 0x03) << 5); + else + + return 0; } + static uint32_t wd_smc_read(wd_t *dev, uint32_t off) { uint32_t retval = 0; - uint32_t checksum = 0; - + uint32_t checksum = 0; + + if (dev->board == WD8003E) + off |= 0x08; + switch(off) { case 0x00: + if (dev->board_chip & WE_ID_BUS_MCA) + retval = (dev->msr & 0xc0) | ((dev->ram_addr >> 13) & 0x3f); + else + retval = dev->msr; break; case 0x01: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[0]; - if (dev->board == WD8013EPA) - retval = dev->reg1; - break; - - case 0x02: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[1]; - break; - - case 0x03: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[2]; + if (dev->board_chip & WE_ID_SOFT_CONFIG) + retval = dev->icr; + else + retval = dev->icr & WE_ICR_16BIT_SLOT; break; case 0x04: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[3]; + if (dev->board_chip & WE_ID_SOFT_CONFIG) + retval = (dev->irr & 0x9f) | wd_get_irq_index(dev); break; - + case 0x05: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[4]; - if (dev->board == WD8013EPA) - retval = dev->reg5; + if (dev->board_chip & WE_ID_SOFT_CONFIG) + retval = dev->laar; break; - case 0x06: - if (dev->board == WD8003E) - retval = dev->dp8390.physaddr[5]; - break; - case 0x07: - if (dev->board == WD8013EPA) - { - if (dev->if_chip != 0x35 && dev->if_chip != 0x3A) - { - retval = 0; - break; - } - + if (dev->board_chip & WE_ID_SOFT_CONFIG) retval = dev->if_chip; - } break; - + case 0x08: - retval = dev->dp8390.physaddr[0]; + retval = dev->dp8390->physaddr[0]; break; case 0x09: - retval = dev->dp8390.physaddr[1]; + retval = dev->dp8390->physaddr[1]; break; case 0x0a: - retval = dev->dp8390.physaddr[2]; + retval = dev->dp8390->physaddr[2]; break; case 0x0b: - retval = dev->dp8390.physaddr[3]; + retval = dev->dp8390->physaddr[3]; break; case 0x0c: - retval = dev->dp8390.physaddr[4]; + retval = dev->dp8390->physaddr[4]; break; case 0x0d: - retval = dev->dp8390.physaddr[5]; + retval = dev->dp8390->physaddr[5]; break; case 0x0e: @@ -397,952 +325,253 @@ wd_smc_read(wd_t *dev, uint32_t off) break; case 0x0f: - { /*This has to return the byte that adds up to 0xFF*/ - checksum = (dev->dp8390.physaddr[0] + dev->dp8390.physaddr[1] + dev->dp8390.physaddr[2] + - dev->dp8390.physaddr[3] + dev->dp8390.physaddr[4] + dev->dp8390.physaddr[5] + + checksum = (dev->dp8390->physaddr[0] + dev->dp8390->physaddr[1] + dev->dp8390->physaddr[2] + + dev->dp8390->physaddr[3] + dev->dp8390->physaddr[4] + dev->dp8390->physaddr[5] + dev->board_chip); retval = 0xff - (checksum & 0xff); - } - break; + break; } - wdlog(2, "%s: ASIC read addr=0x%02x, value=0x%04x\n", + wdlog("%s: ASIC read addr=0x%02x, value=0x%04x\n", dev->name, (unsigned)off, (unsigned) retval); - + return(retval); } + +static void +wd_set_ram(wd_t *dev) +{ + uint32_t a13; + + if ((dev->board_chip & 0xa0) == 0x20) { + a13 = dev->msr & 0x3f; + a13 <<= 13; + + dev->ram_addr = a13 | (1 << 19); + mem_mapping_set_addr(&dev->ram_mapping, dev->ram_addr, dev->ram_size); + wdlog("%s: RAM address set to %08X\n", dev->name, dev->ram_addr); + } + + if (dev->msr & WE_MSR_ENABLE_RAM) + mem_mapping_enable(&dev->ram_mapping); + else + mem_mapping_disable(&dev->ram_mapping); + wdlog("%s: RAM now %sabled\n", dev->name, (dev->msr & WE_MSR_ENABLE_RAM) ? "en" : "dis"); +} + + static void wd_smc_write(wd_t *dev, uint32_t off, uint32_t val) { - wdlog(2, "%s: ASIC write addr=0x%02x, value=0x%04x\n", - dev->name, (unsigned)off, (unsigned) val); + uint8_t old; + + wdlog("%s: ASIC write addr=0x%02x, value=0x%04x\n", + dev->name, (unsigned)off, (unsigned) val); + + if (off && (dev->board == WD8003E)) + return; switch(off) { + /* Bits 0-5: Bits 13-18 of memory address (writable?): + Windows 98 requires this to be preloaded with the initial + addresss to work correctly; + Bit 6: Enable memory if set; + Bit 7: Software reset if set. */ case 0x00: /* WD Control register */ - if (val & 0x80) - { - dev->dp8390.ISR.reset = 1; - return; + old = dev->msr; + + if (!(old & WE_MSR_SOFT_RESET) && (val & WE_MSR_SOFT_RESET)) { + wd_soft_reset(dev); + wdlog("WD80x3: Soft reset\n"); } - - mem_mapping_disable(&dev->ram_mapping); - - if (val & 0x40) - { - mem_mapping_enable(&dev->ram_mapping); + + if ((dev->board_chip & 0xa0) == 0x20) + dev->msr = val; + else + dev->msr = (dev->msr & 0x3f) | (val & 0xc0); + + if ((old &= 0x7f) != (val & 0x7f)) { + wd_set_ram(dev); + wdlog("WD80x3: Memory now %sabled (addr = %08X)\n", (val & WE_MSR_ENABLE_RAM) ? "en" : "dis", dev->ram_addr); } break; + /* Bit 1: 0 = 8-bit slot, 1 = 16-bit slot; + Bit 3: 0 = 8k RAM, 1 = 32k RAM (only on revision < 2). */ case 0x01: - dev->reg1 = val; + if (dev->bit16 & 2) + dev->icr = (dev->icr & WE_ICR_16BIT_SLOT) | (val & WE_ICR_16BIT_SLOT); + else + dev->icr = val; break; + /* Bit 5: Bit 0 of encoded IRQ; + Bit 6: Bit 1 of encoded IRQ; + Bit 7: Enable interrupts. */ case 0x04: + if (dev->board_chip & WE_ID_SOFT_CONFIG) + dev->irr = (dev->irr & 0xe0) | (val & 0x1f); break; - + + /* Bits 0-4: Bits 19-23 of memory address (writable?): + Windows 98 requires this to be preloaded with the initial + addresss to work correctly; + Bit 5: Enable software interrupt; + Bit 6: Enable 16-bit RAM for LAN if set; + Bit 7: Enable 16-bit RAM for host if set. */ case 0x05: - dev->reg5 = val; + if (dev->board_chip & WE_ID_SOFT_CONFIG) + dev->laar = val; break; - - case 0x06: - break; - + + /* Bits 0-4: Chip ID; + Bit 5: Software configuration is supported if present; + Bit 6: 0 = 16k RAM, 1 = 32k RAM. */ case 0x07: - dev->if_chip = val; - break; + if (dev->board_chip & WE_ID_SOFT_CONFIG) + dev->if_chip = val; + break; - default: /* this is invalid, but happens under win95 device detection */ - wdlog(3, "%s: ASIC write invalid address %04x, ignoring\n", - dev->name, (unsigned)off); + default: + /* This is invalid, but happens under win95 device detection: + maybe some clone cards implement writing for some other + registers? */ + wdlog("%s: ASIC write invalid address %04x, ignoring\n", + dev->name, (unsigned)off); break; } } -/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ static uint8_t -page0_read(wd_t *dev, uint32_t off) +wd_read(uint16_t addr, void *priv, int len) { + wd_t *dev = (wd_t *)priv; + uint8_t retval = 0; + int off = addr - dev->base_address; - switch(off) { - case 0x01: /* CLDA0 */ - retval = (dev->dp8390.local_dma & 0xff); - break; + wdlog("%s: read addr %x\n", dev->name, addr); - case 0x02: /* CLDA1 */ - retval = (dev->dp8390.local_dma >> 8); - break; - - case 0x03: /* BNRY */ - retval = dev->dp8390.bound_ptr; - break; - - case 0x04: /* TSR */ - retval = ((dev->dp8390.TSR.ow_coll << 7) | - (dev->dp8390.TSR.cd_hbeat << 6) | - (dev->dp8390.TSR.fifo_ur << 5) | - (dev->dp8390.TSR.no_carrier << 4) | - (dev->dp8390.TSR.aborted << 3) | - (dev->dp8390.TSR.collided << 2) | - (dev->dp8390.TSR.tx_ok)); - break; - - case 0x05: /* NCR */ - retval = dev->dp8390.num_coll; - break; - - case 0x06: /* FIFO */ - /* reading FIFO is only valid in loopback mode */ - wdlog(3, "%s: reading FIFO not supported yet\n", dev->name); - retval = dev->dp8390.fifo; - break; - - case 0x07: /* ISR */ - retval = ((dev->dp8390.ISR.reset << 7) | - (dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - break; - - case 0x08: /* CRDA0 */ - retval = (dev->dp8390.remote_dma & 0xff); - break; - - case 0x09: /* CRDA1 */ - retval = (dev->dp8390.remote_dma >> 8); - break; - - case 0x0a: /* reserved / RTL8029ID0 */ - wdlog(3, "%s: reserved Page0 read - 0x0a\n", dev->name); - retval = 0xff; - break; - - case 0x0b: /* reserved / RTL8029ID1 */ - wdlog(3, "%s: reserved Page0 read - 0x0b\n", dev->name); - retval = 0xff; - break; - - case 0x0c: /* RSR */ - retval = ((dev->dp8390.RSR.deferred << 7) | - (dev->dp8390.RSR.rx_disabled << 6) | - (dev->dp8390.RSR.rx_mbit << 5) | - (dev->dp8390.RSR.rx_missed << 4) | - (dev->dp8390.RSR.fifo_or << 3) | - (dev->dp8390.RSR.bad_falign << 2) | - (dev->dp8390.RSR.bad_crc << 1) | - (dev->dp8390.RSR.rx_ok)); - break; - - case 0x0d: /* CNTR0 */ - retval = dev->dp8390.tallycnt_0; - break; - - case 0x0e: /* CNTR1 */ - retval = dev->dp8390.tallycnt_1; - break; - - case 0x0f: /* CNTR2 */ - retval = dev->dp8390.tallycnt_2; - break; - - default: - wdlog(3, "%s: Page0 register 0x%02x out of range\n", - dev->name, off); - break; + if (off == 0x10) + retval = dp8390_read_cr(dev->dp8390); + else if ((off >= 0x00) && (off <= 0x0f)) + retval = wd_smc_read(dev, off); + else { + switch(dev->dp8390->CR.pgsel) { + case 0x00: + retval = dp8390_page0_read(dev->dp8390, off - 0x10, len); + break; + case 0x01: + retval = dp8390_page1_read(dev->dp8390, off - 0x10, len); + break; + case 0x02: + retval = dp8390_page2_read(dev->dp8390, off - 0x10, len); + break; + default: + wdlog("%s: unknown value of pgsel in read - %d\n", + dev->name, dev->dp8390->CR.pgsel); + break; + } } - wdlog(3, "%s: Page0 read from register 0x%02x, value=0x%02x\n", - dev->name, off, retval); - return(retval); } -static void -page0_write(wd_t *dev, uint32_t off, uint8_t val) -{ - uint8_t val2; - - wdlog(3, "%s: Page0 write to register 0x%02x, value=0x%02x\n", - dev->name, off, val); - - switch(off) { - case 0x01: /* PSTART */ - dev->dp8390.page_start = val; - break; - - case 0x02: /* PSTOP */ - dev->dp8390.page_stop = val; - break; - - case 0x03: /* BNRY */ - dev->dp8390.bound_ptr = val; - break; - - case 0x04: /* TPSR */ - dev->dp8390.tx_page_start = val; - break; - - case 0x05: /* TBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.tx_bytes &= 0xff00; - dev->dp8390.tx_bytes |= (val & 0xff); - break; - - case 0x06: /* TBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.tx_bytes &= 0x00ff; - dev->dp8390.tx_bytes |= ((val & 0xff) << 8); - break; - - case 0x07: /* ISR */ - val &= 0x7f; /* clear RST bit - status-only bit */ - /* All other values are cleared iff the ISR bit is 1 */ - dev->dp8390.ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); - dev->dp8390.ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); - dev->dp8390.ISR.rx_err &= !((int)((val & 0x04) == 0x04)); - dev->dp8390.ISR.tx_err &= !((int)((val & 0x08) == 0x08)); - dev->dp8390.ISR.overwrite &= !((int)((val & 0x10) == 0x10)); - dev->dp8390.ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); - dev->dp8390.ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); - val = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - val &= ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - if (val == 0x00) - wd_interrupt(dev, 0); - break; - - case 0x08: /* RSAR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_start &= 0xff00; - dev->dp8390.remote_start |= (val & 0xff); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x09: /* RSAR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_start &= 0x00ff; - dev->dp8390.remote_start |= ((val & 0xff) << 8); - dev->dp8390.remote_dma = dev->dp8390.remote_start; - break; - - case 0x0a: /* RBCR0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.remote_bytes &= 0xff00; - dev->dp8390.remote_bytes |= (val & 0xff); - break; - - case 0x0b: /* RBCR1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.remote_bytes &= 0x00ff; - dev->dp8390.remote_bytes |= ((val & 0xff) << 8); - break; - - case 0x0c: /* RCR */ - /* Check if the reserved bits are set */ - if (val & 0xc0) { - wdlog(3, "%s: RCR write, reserved bits set\n", - dev->name); - } - - /* Set all other bit-fields */ - dev->dp8390.RCR.errors_ok = ((val & 0x01) == 0x01); - dev->dp8390.RCR.runts_ok = ((val & 0x02) == 0x02); - dev->dp8390.RCR.broadcast = ((val & 0x04) == 0x04); - dev->dp8390.RCR.multicast = ((val & 0x08) == 0x08); - dev->dp8390.RCR.promisc = ((val & 0x10) == 0x10); - dev->dp8390.RCR.monitor = ((val & 0x20) == 0x20); - - /* Monitor bit is a little suspicious... */ - if (val & 0x20) wdlog(3, "%s: RCR write, monitor bit set!\n", - dev->name); - break; - - case 0x0d: /* TCR */ - /* Check reserved bits */ - if (val & 0xe0) wdlog(3, "%s: TCR write, reserved bits set\n", - dev->name); - - /* Test loop mode (not supported) */ - if (val & 0x06) { - dev->dp8390.TCR.loop_cntl = (val & 0x6) >> 1; - wdlog(3, "%s: TCR write, loop mode %d not supported\n", - dev->name, dev->dp8390.TCR.loop_cntl); - } - else { - dev->dp8390.TCR.loop_cntl = 0; - } - - /* Inhibit-CRC not supported. */ - if (val & 0x01) wdlog(3, - "%s: TCR write, inhibit-CRC not supported\n",dev->name); - - /* Auto-transmit disable very suspicious */ - if (val & 0x08) - { - wdlog(3, - "%s: TCR write, auto transmit disable not supported\n", - dev->name); - } - - /* Allow collision-offset to be set, although not used */ - dev->dp8390.TCR.coll_prio = ((val & 0x08) == 0x08); - break; - - case 0x0e: /* DCR */ - /* the loopback mode is not suppported yet */ - if (! (val & 0x08)) wdlog(3, - "%s: DCR write, loopback mode selected\n", dev->name); - - /* It is questionable to set longaddr and auto_rx, since - * they are not supported on the NE2000. Print a warning - * and continue. */ - if (val & 0x04) - wdlog(3, "%s: DCR write - LAS set ???\n", dev->name); - if (val & 0x10) - wdlog(3, "%s: DCR write - AR set ???\n", dev->name); - - /* Set other values. */ - dev->dp8390.DCR.wdsize = ((val & 0x01) == 0x01); - dev->dp8390.DCR.endian = ((val & 0x02) == 0x02); - dev->dp8390.DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ - dev->dp8390.DCR.loop = ((val & 0x08) == 0x08); - dev->dp8390.DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ - dev->dp8390.DCR.fifo_size = (val & 0x50) >> 5; - break; - - case 0x0f: /* IMR */ - /* Check for reserved bit */ - if (val & 0x80) - wdlog(3, "%s: IMR write, reserved bit set\n",dev->name); - - /* Set other values */ - dev->dp8390.IMR.rx_inte = ((val & 0x01) == 0x01); - dev->dp8390.IMR.tx_inte = ((val & 0x02) == 0x02); - dev->dp8390.IMR.rxerr_inte = ((val & 0x04) == 0x04); - dev->dp8390.IMR.txerr_inte = ((val & 0x08) == 0x08); - dev->dp8390.IMR.overw_inte = ((val & 0x10) == 0x10); - dev->dp8390.IMR.cofl_inte = ((val & 0x20) == 0x20); - dev->dp8390.IMR.rdma_inte = ((val & 0x40) == 0x40); - val2 = ((dev->dp8390.ISR.rdma_done << 6) | - (dev->dp8390.ISR.cnt_oflow << 5) | - (dev->dp8390.ISR.overwrite << 4) | - (dev->dp8390.ISR.tx_err << 3) | - (dev->dp8390.ISR.rx_err << 2) | - (dev->dp8390.ISR.pkt_tx << 1) | - (dev->dp8390.ISR.pkt_rx)); - if (((val & val2) & 0x7f) == 0) - wd_interrupt(dev, 0); - else - wd_interrupt(dev, 1); - break; - - default: - wdlog(3, "%s: Page0 write, bad register 0x%02x\n", - dev->name, off); - break; - } -} - -/* Handle reads/writes to the first page of the DS8390 register file. */ -static uint8_t -page1_read(wd_t *dev, uint32_t off) -{ - wdlog(3, "%s: Page1 read from register 0x%02x\n", - dev->name, off); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - return(dev->dp8390.physaddr[off - 1]); - - case 0x07: /* CURR */ - wdlog(3, "%s: returning current page: 0x%02x\n", - dev->name, (dev->dp8390.curr_page)); - return(dev->dp8390.curr_page); - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - return(dev->dp8390.mchash[off - 8]); - - default: - wdlog(3, "%s: Page1 read register 0x%02x out of range\n", - dev->name, off); - return(0); - } -} - - -static void -page1_write(wd_t *dev, uint32_t off, uint8_t val) -{ - wdlog(3, "%s: Page1 write to register 0x%02x, value=0x%04x\n", - dev->name, off, val); - - switch(off) { - case 0x01: /* PAR0-5 */ - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - dev->dp8390.physaddr[off - 1] = val; - if (off == 6) wdlog(3, - "%s: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], - dev->dp8390.physaddr[2], dev->dp8390.physaddr[3], - dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); - break; - - case 0x07: /* CURR */ - dev->dp8390.curr_page = val; - break; - - case 0x08: /* MAR0-7 */ - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - dev->dp8390.mchash[off - 8] = val; - break; - - default: - wdlog(3, "%s: Page1 write register 0x%02x out of range\n", - dev->name, off); - break; - } -} - -/* Handle reads/writes to the second page of the DS8390 register file. */ -static uint8_t -page2_read(wd_t *dev, uint32_t off) -{ - wdlog(3, "%s: Page2 read from register 0x%02x\n", - dev->name, off); - - switch(off) { - case 0x01: /* PSTART */ - return(dev->dp8390.page_start); - - case 0x02: /* PSTOP */ - return(dev->dp8390.page_stop); - - case 0x03: /* Remote Next-packet pointer */ - return(dev->dp8390.rempkt_ptr); - - case 0x04: /* TPSR */ - return(dev->dp8390.tx_page_start); - - case 0x05: /* Local Next-packet pointer */ - return(dev->dp8390.localpkt_ptr); - - case 0x06: /* Address counter (upper) */ - return(dev->dp8390.address_cnt >> 8); - - case 0x07: /* Address counter (lower) */ - return(dev->dp8390.address_cnt & 0xff); - - case 0x08: /* Reserved */ - case 0x09: - case 0x0a: - case 0x0b: - wdlog(3, "%s: reserved Page2 read - register 0x%02x\n", - dev->name, off); - return(0xff); - - case 0x0c: /* RCR */ - return ((dev->dp8390.RCR.monitor << 5) | - (dev->dp8390.RCR.promisc << 4) | - (dev->dp8390.RCR.multicast << 3) | - (dev->dp8390.RCR.broadcast << 2) | - (dev->dp8390.RCR.runts_ok << 1) | - (dev->dp8390.RCR.errors_ok)); - - case 0x0d: /* TCR */ - return ((dev->dp8390.TCR.coll_prio << 4) | - (dev->dp8390.TCR.ext_stoptx << 3) | - ((dev->dp8390.TCR.loop_cntl & 0x3) << 1) | - (dev->dp8390.TCR.crc_disable)); - - case 0x0e: /* DCR */ - return (((dev->dp8390.DCR.fifo_size & 0x3) << 5) | - (dev->dp8390.DCR.auto_rx << 4) | - (dev->dp8390.DCR.loop << 3) | - (dev->dp8390.DCR.longaddr << 2) | - (dev->dp8390.DCR.endian << 1) | - (dev->dp8390.DCR.wdsize)); - - case 0x0f: /* IMR */ - return ((dev->dp8390.IMR.rdma_inte << 6) | - (dev->dp8390.IMR.cofl_inte << 5) | - (dev->dp8390.IMR.overw_inte << 4) | - (dev->dp8390.IMR.txerr_inte << 3) | - (dev->dp8390.IMR.rxerr_inte << 2) | - (dev->dp8390.IMR.tx_inte << 1) | - (dev->dp8390.IMR.rx_inte)); - - default: - wdlog(3, "%s: Page2 register 0x%02x out of range\n", - dev->name, off); - break; - } - - return(0); -} - -#if 0 -static void -page2_write(wd_t *dev, uint32_t off, uint8_t val) -{ -/* Maybe all writes here should be BX_PANIC()'d, since they - affect internal operation, but let them through for now - and print a warning. */ - wdlog(3, "%s: Page2 write to register 0x%02x, value=0x%04x\n", - dev->name, off, val); - switch(off) { - case 0x01: /* CLDA0 */ - /* Clear out low byte and re-insert */ - dev->dp8390.local_dma &= 0xff00; - dev->dp8390.local_dma |= (val & 0xff); - break; - - case 0x02: /* CLDA1 */ - /* Clear out high byte and re-insert */ - dev->dp8390.local_dma &= 0x00ff; - dev->dp8390.local_dma |= ((val & 0xff) << 8); - break; - - case 0x03: /* Remote Next-pkt pointer */ - dev->dp8390.rempkt_ptr = val; - break; - - case 0x04: - wdlog(3, "page 2 write to reserved register 0x04\n"); - break; - - case 0x05: /* Local Next-packet pointer */ - dev->dp8390.localpkt_ptr = val; - break; - - case 0x06: /* Address counter (upper) */ - /* Clear out high byte and re-insert */ - dev->dp8390.address_cnt &= 0x00ff; - dev->dp8390.address_cnt |= ((val & 0xff) << 8); - break; - - case 0x07: /* Address counter (lower) */ - /* Clear out low byte and re-insert */ - dev->dp8390.address_cnt &= 0xff00; - dev->dp8390.address_cnt |= (val & 0xff); - break; - - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - wdlog(3, "%s: Page2 write to reserved register 0x%02x\n", - dev->name, off); - break; - - default: - wdlog(3, "%s: Page2 write, illegal register 0x%02x\n", - dev->name, off); - break; - } -} -#endif - -/* Routines for handling reads/writes to the Command Register. */ -static uint8_t -read_cr(wd_t *dev) -{ - uint32_t retval; - - retval = (((dev->dp8390.CR.pgsel & 0x03) << 6) | - ((dev->dp8390.CR.rdma_cmd & 0x07) << 3) | - (dev->dp8390.CR.tx_packet << 2) | - (dev->dp8390.CR.start << 1) | - (dev->dp8390.CR.stop)); - wdlog(3, "%s: read CR returns 0x%02x\n", dev->name, retval); - - return(retval); -} - -static void -write_cr(wd_t *dev, uint8_t val) -{ - wdlog(3, "%s: wrote 0x%02x to CR, CS=%08x, PC=%08x\n", dev->name, val, CS, cpu_state.pc); - - /* Validate remote-DMA */ - if ((val & 0x38) == 0x00) { - wdlog(3, "%s: CR write - invalid rDMA value 0\n", dev->name); - val |= 0x20; /* dma_cmd == 4 is a safe default */ - } - - /* Check for s/w reset */ - if (val & 0x01) { - dev->dp8390.ISR.reset = 1; - dev->dp8390.CR.stop = 1; - } else { - dev->dp8390.CR.stop = 0; - } - - dev->dp8390.CR.rdma_cmd = (val & 0x38) >> 3; - - /* If start command issued, the RST bit in the ISR */ - /* must be cleared */ - if ((val & 0x02) && !dev->dp8390.CR.start) - dev->dp8390.ISR.reset = 0; - - dev->dp8390.CR.start = ((val & 0x02) == 0x02); - dev->dp8390.CR.pgsel = (val & 0xc0) >> 6; - - /* Check for send-packet command */ - if (dev->dp8390.CR.rdma_cmd == 3) { - /* Set up DMA read from receive ring */ - dev->dp8390.remote_start = dev->dp8390.remote_dma = dev->dp8390.bound_ptr * 256; - dev->dp8390.remote_bytes = (uint16_t) wd_chipmem_read(dev, dev->dp8390.bound_ptr * 256 + 2, 2); - wdlog(2, "%s: sending buffer #x%x length %d\n", - dev->name, dev->dp8390.remote_start, dev->dp8390.remote_bytes); - } - - /* Check for start-tx */ - if ((val & 0x04) && dev->dp8390.TCR.loop_cntl) { - if (dev->dp8390.TCR.loop_cntl) { - wd_rx(dev, &dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], - dev->dp8390.tx_bytes); - } - } else if (val & 0x04) { - if (dev->dp8390.CR.stop) { - if (dev->dp8390.tx_bytes == 0) /* njh@bandsman.co.uk */ { - return; /* Solaris9 probe */ - } - wdlog(3, "%s: CR write - tx start, dev in reset\n", dev->name); - } - - if (dev->dp8390.tx_bytes == 0) - wdlog(3, "%s: CR write - tx start, tx bytes == 0\n", dev->name); - - /* Send the packet to the system driver */ - dev->dp8390.CR.tx_packet = 1; - - network_tx(dev->dp8390.mem, dev->dp8390.tx_bytes); - - wd_tx(dev, val); - } - - /* 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 (dev->dp8390.CR.rdma_cmd == 0x01 && dev->dp8390.CR.start && dev->dp8390.remote_bytes == 0) { - dev->dp8390.ISR.rdma_done = 1; - if (dev->dp8390.IMR.rdma_inte) { - wd_interrupt(dev, 1); - wd_interrupt(dev, 0); - } - } -} - static uint8_t wd_readb(uint16_t addr, void *priv) { - wd_t *dev = (wd_t *)priv; - - uint8_t retval = 0; + wd_t *dev = (wd_t *) priv; + + return(wd_read(addr, dev, 1)); +} + + +static uint16_t +wd_readw(uint16_t addr, void *priv) +{ + wd_t *dev = (wd_t *) priv; + + return(wd_read(addr, dev, 2)); +} + + +static void +wd_write(uint16_t addr, uint8_t val, void *priv, unsigned int len) +{ + wd_t *dev = (wd_t *)priv; int off = addr - dev->base_address; - wdlog(3, "%s: read addr %x\n", dev->name, addr); + wdlog("%s: write addr %x, value %x\n", dev->name, addr, val); - if (off == 0x10) - { - retval = read_cr(dev); - } - else if (off >= 0x00 && off <= 0x0f) - { - retval = wd_smc_read(dev, off); - } - else - { - switch(dev->dp8390.CR.pgsel) { + if (off == 0x10) + dp8390_write_cr(dev->dp8390, val); + else if ((off >= 0x00) && (off <= 0x0f)) + wd_smc_write(dev, off, val); + else { + switch(dev->dp8390->CR.pgsel) { case 0x00: - retval = page0_read(dev, off - 0x10); + dp8390_page0_write(dev->dp8390, off - 0x10, val, len); break; - case 0x01: - retval = page1_read(dev, off - 0x10); + dp8390_page1_write(dev->dp8390, off - 0x10, val, len); break; - - case 0x02: - retval = page2_read(dev, off - 0x10); - break; - default: - wdlog(3, "%s: unknown value of pgsel in read - %d\n", - dev->name, dev->dp8390.CR.pgsel); + wdlog("%s: unknown value of pgsel in write - %d\n", + dev->name, dev->dp8390->CR.pgsel); break; - } - } - - return(retval); + } + } } static void wd_writeb(uint16_t addr, uint8_t val, void *priv) { - wd_t *dev = (wd_t *)priv; - int off = addr - dev->base_address; - - wdlog(3, "%s: write addr %x, value %x\n", dev->name, addr, val); - - if (off == 0x10) - { - write_cr(dev, val); - } - else if (off >= 0x00 && off <= 0x0f) - { - wd_smc_write(dev, off, val); - } - else - { - switch(dev->dp8390.CR.pgsel) { - case 0x00: - page0_write(dev, off - 0x10, val); - break; - - case 0x01: - page1_write(dev, off - 0x10, val); - break; - - default: - wdlog(3, "%s: unknown value of pgsel in write - %d\n", - dev->name, dev->dp8390.CR.pgsel); - break; - } - } + wd_write(addr, val, priv, 1); } -static void wd_ioset(wd_t *dev, uint16_t addr); -static void wd_ioremove(wd_t *dev, uint16_t addr); static void -wd_ioset(wd_t *dev, uint16_t addr) +wd_writew(uint16_t addr, uint16_t val, void *priv) +{ + wd_write(addr, val & 0xff, priv, 2); +} + + +static void +wd_io_set(wd_t *dev, uint16_t addr) { + if (dev->bit16 & 1) { io_sethandler(addr, 0x20, - wd_readb, NULL, NULL, - wd_writeb, NULL, NULL, dev); + wd_readb, wd_readw, NULL, + wd_writeb, wd_writew, NULL, dev); + } else { + io_sethandler(addr, 0x20, + wd_readb, NULL, NULL, + wd_writeb, NULL, NULL, dev); + } } + static void -wd_ioremove(wd_t *dev, uint16_t addr) +wd_io_remove(wd_t *dev, uint16_t addr) { + if (dev->bit16 & 1) { + io_removehandler(addr, 0x20, + wd_readb, wd_readw, NULL, + wd_writeb, wd_writew, NULL, dev); + } else { io_removehandler(addr, 0x20, wd_readb, NULL, NULL, wd_writeb, NULL, NULL, dev); + } } -/* - * 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. - */ -static void -wd_rx(void *priv, uint8_t *buf, int io_len) -{ - static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; - wd_t *dev = (wd_t *)priv; - uint8_t pkthdr[4]; - uint8_t *startptr; - int pages, avail; - int idx, nextpage; - int endbytes; - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 1); - - if (io_len != 60) - wdlog(2, "%s: rx_frame with length %d\n", dev->name, io_len); - - if ((dev->dp8390.CR.stop != 0) || (dev->dp8390.page_start == 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 + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; - if (dev->dp8390.curr_page < dev->dp8390.bound_ptr) { - avail = dev->dp8390.bound_ptr - dev->dp8390.curr_page; - } else { - avail = (dev->dp8390.page_stop - dev->dp8390.page_start) - - (dev->dp8390.curr_page - dev->dp8390.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 NE2K_NEVER_FULL_RING - || (avail == pages) -#endif - ) { - wdlog(1, "%s: no space\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - if ((io_len < 40/*60*/) && !dev->dp8390.RCR.runts_ok) { - wdlog(1, "%s: rejected small packet, length %d\n", dev->name, io_len); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Some computers don't care... */ - if (io_len < 60) - io_len = 60; - - wdlog(2, "%s: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", - dev->name, - buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - io_len); - - /* Do address filtering if not in promiscuous mode. */ - if (! dev->dp8390.RCR.promisc) { - /* If this is a broadcast frame.. */ - if (! memcmp(buf, bcast_addr, 6)) { - /* Broadcast not enabled, we're done. */ - if (! dev->dp8390.RCR.broadcast) { - wdlog(2, "%s: RX BC disabled\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* If this is a multicast frame.. */ - else if (buf[0] & 0x01) { - /* Multicast not enabled, we're done. */ - if (! dev->dp8390.RCR.multicast) { -#if 1 - wdlog(2, "%s: RX MC disabled\n", dev->name); -#endif - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - - /* Are we listening to this multicast address? */ - idx = mcast_index(buf); - if (! (dev->dp8390.mchash[idx>>3] & (1<<(idx&0x7)))) { - wdlog(2, "%s: RX MC not listed\n", dev->name); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); - return; - } - } - - /* Unicast, must be for us.. */ - else if (memcmp(buf, dev->dp8390.physaddr, 6)) return; - } else { - wdlog(2, "%s: RX promiscuous receive\n", dev->name); - } - - nextpage = dev->dp8390.curr_page + pages; - if (nextpage >= dev->dp8390.page_stop) - nextpage -= (dev->dp8390.page_stop - dev->dp8390.page_start); - - /* Set up packet header. */ - pkthdr[0] = 0x01; /* RXOK - packet is OK */ - pkthdr[1] = nextpage; /* ptr to next packet */ - pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ - pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ - wdlog(2, "%s: RX pkthdr [%02x %02x %02x %02x]\n", - dev->name, pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); - - /* Copy into buffer, update curpage, and signal interrupt if config'd */ - startptr = dev->dp8390.mem + (dev->dp8390.curr_page * 256); - memcpy(startptr, pkthdr, sizeof(pkthdr)); - if ((nextpage > dev->dp8390.curr_page) || - ((dev->dp8390.curr_page + pages) == dev->dp8390.page_stop)) { - memcpy(startptr+sizeof(pkthdr), buf, io_len); - } else { - endbytes = (dev->dp8390.page_stop - dev->dp8390.curr_page) * 256; - memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); - startptr = dev->dp8390.mem + (dev->dp8390.page_start * 256); - memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); - } - dev->dp8390.curr_page = nextpage; - - dev->dp8390.RSR.rx_ok = 1; - dev->dp8390.RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; - dev->dp8390.ISR.pkt_rx = 1; - - if (dev->dp8390.IMR.rx_inte) - wd_interrupt(dev, 1); - - //FIXME: move to upper layer - ui_sb_update_icon(SB_NETWORK, 0); -} - -static void -wd_tx(wd_t *dev, uint32_t val) -{ - dev->dp8390.CR.tx_packet = 0; - dev->dp8390.TSR.tx_ok = 1; - dev->dp8390.ISR.pkt_tx = 1; - - /* Generate an interrupt if not masked */ - if (dev->dp8390.IMR.tx_inte) - wd_interrupt(dev, 1); - dev->dp8390.tx_timer_active = 0; -} static uint8_t wd_mca_read(int port, void *priv) @@ -1352,14 +581,15 @@ wd_mca_read(int port, void *priv) return(dev->pos_regs[port & 7]); } -#define MCA_61C8_IRQS { 3, 4, 10, 15 } + +#define MCA_6FC0_IRQS { 3, 4, 10, 15 } + static void wd_mca_write(int port, uint8_t val, void *priv) { wd_t *dev = (wd_t *)priv; - int8_t irq[4] = MCA_61C8_IRQS; - uint32_t ram_size = 0; + int8_t irq[4] = MCA_6FC0_IRQS; /* MCA does not write registers below 0x0100. */ if (port < 0x0102) return; @@ -1367,16 +597,6 @@ wd_mca_write(int port, uint8_t val, void *priv) /* Save the MCA register value. */ dev->pos_regs[port & 7] = val; - wd_ioremove(dev, dev->base_address); - - dev->base_address = 0x800 + (((dev->pos_regs[2] & 0xf0) >> 4) * 0x1000); - - dev->ram_addr = 0xC0000 + ((dev->pos_regs[3] & 0x0f) * 0x2000) + ((dev->pos_regs[3] & 0x80) ? 0xF00000 : 0); - - dev->base_irq = irq[(dev->pos_regs[5] & 0x0c) >> 2]; - - ram_size = (dev->pos_regs[3] & 0x10) ? 0x4000 : 0x2000; - /* * The PS/2 Model 80 BIOS always enables a card if it finds one, * even if no resources were assigned yet (because we only added @@ -1384,91 +604,60 @@ wd_mca_write(int port, uint8_t val, void *priv) * * So, remove current address, if any. */ + if (dev->base_address) + wd_io_remove(dev, dev->base_address); + + dev->base_address = (dev->pos_regs[2] & 0xfe) << 4; + dev->ram_addr = (dev->pos_regs[3] & 0xfc) << 12; + dev->irq = irq[dev->pos_regs[5] & 0x02]; /* Initialize the device if fully configured. */ - if (dev->pos_regs[2] & 0x01) { - /* Card enabled; register (new) I/O handler. */ - - wd_ioset(dev, dev->base_address); - - wd_reset(dev); - - mem_mapping_add(&dev->ram_mapping, dev->ram_addr, ram_size, - wd_ram_readb, wd_ram_readw, wd_ram_readl, - wd_ram_writeb, wd_ram_writew, wd_ram_writel, - NULL, MEM_MAPPING_EXTERNAL, dev); - - mem_mapping_disable(&dev->ram_mapping); - - wdlog(1, "%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, - dev->base_address, dev->base_irq, dev->ram_addr); - } + /* Register (new) I/O handler. */ + if (dev->pos_regs[2] & 0x01) + wd_io_set(dev, dev->base_address); + + mem_mapping_set_addr(&dev->ram_mapping, dev->ram_addr, dev->ram_size); + + mem_mapping_disable(&dev->ram_mapping); + if ((dev->msr & WE_MSR_ENABLE_RAM) && (dev->pos_regs[2] & 0x01)) + mem_mapping_enable(&dev->ram_mapping); + + wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, + dev->base_address, dev->irq, dev->ram_addr); } + +static uint8_t +wd_mca_feedb(void *priv) +{ + return 1; +} + + static void * wd_init(const device_t *info) { uint32_t mac; wd_t *dev; -#ifdef ENABLE_NIC_LOG - int i; -#endif /* Get the desired debug level. */ #ifdef ENABLE_NIC_LOG i = device_get_config_int("debug"); - if (i > 0) wd_do_log = i; + if (i > 0) WE_do_log = i; #endif dev = malloc(sizeof(wd_t)); memset(dev, 0x00, sizeof(wd_t)); dev->name = info->name; dev->board = info->local; - - switch(dev->board) { - case WD8003E: - dev->board_chip = WE_TYPE_WD8003E; - dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0xC0; - break; - - case WD8013EBT: - dev->board_chip = WE_TYPE_WD8013EBT; - dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0xC0; - break; - case WD8013EPA: - dev->board_chip = WE_TYPE_WD8013EP | 0x80; - dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ - dev->maclocal[1] = 0x00; - dev->maclocal[2] = 0xC0; - dev->pos_regs[0] = 0xC8; - dev->pos_regs[1] = 0x61; - break; - } - - if (dev->board != WD8013EPA) { - dev->base_address = device_get_config_hex16("base"); - dev->base_irq = device_get_config_int("irq"); - dev->ram_addr = device_get_config_hex20("ram_addr"); - } - else { - mca_add(wd_mca_read, wd_mca_write, dev); - } + dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xC0; /* See if we have a local MAC address configured. */ mac = device_get_config_mac("mac", -1); - /* - * Make this device known to the I/O system. - * PnP and PCI devices start with address spaces inactive. - */ - if (dev->board != WD8013EPA) - wd_ioset(dev, dev->base_address); - /* Set up our BIA. */ if (mac & 0xff000000) { /* Generate new local MAC. */ @@ -1484,32 +673,110 @@ wd_init(const device_t *info) dev->maclocal[4] = (mac>>8) & 0xff; dev->maclocal[5] = (mac & 0xff); } - memcpy(dev->dp8390.physaddr, dev->maclocal, sizeof(dev->maclocal)); - wdlog(0, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, dev->base_address, dev->base_irq, - dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], dev->dp8390.physaddr[2], - dev->dp8390.physaddr[3], dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); + if ((dev->board == WD8003ETA) || (dev->board == WD8003EA)) + mca_add(wd_mca_read, wd_mca_write, wd_mca_feedb, dev); + else { + dev->base_address = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->ram_addr = device_get_config_hex20("ram_addr"); + } + + dev->dp8390 = device_add(&dp8390_device); + dev->dp8390->priv = dev; + dev->dp8390->interrupt = wd_interrupt; + dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CLEAR_IRQ); + + switch(dev->board) { + /* Ethernet, ISA, no interface chip, RAM 8k */ + case WD8003E: + dev->board_chip = WE_TYPE_WD8003E; + dev->ram_size = 0x2000; + break; + + /* Ethernet, ISA, 5x3 interface chip, RAM 8k or 32k */ + case WD8003EB: + dev->board_chip = WE_TYPE_WD8003EB; + dev->if_chip = 1; + dev->ram_size = device_get_config_int("ram_size"); + if (dev->ram_size == 0x8000) + dev->board_chip |= WE_ID_EXTRA_RAM; + + /* Bit A19 is implicit 1. */ + dev->msr |= (dev->ram_addr >> 13) & 0x3f; + break; + + /* Ethernet, ISA, no interface chip, RAM 8k or 32k (8-bit slot) / 16k or 64k (16-bit slot) */ + case WD8013EBT: + dev->board_chip = WE_TYPE_WD8013EBT; + dev->ram_size = device_get_config_int("ram_size"); + if (dev->ram_size == 0x10000) + dev->board_chip |= WE_ID_EXTRA_RAM; + + dev->bit16 = 2; + if (AT) + dev->bit16 |= 1; + else { + dev->bit16 |= 0; + if (dev->irq == 9) + dev->irq = 2; + dev->ram_size >>= 1; /* Half the RAM when in 8-bit slot. */ + } + break; + + /* Ethernet, MCA, 5x3 interface chip, RAM 16k */ + case WD8003EA: + dev->board_chip = WE_ID_SOFT_CONFIG; + /* Ethernet, MCA, no interface chip, RAM 16k */ + case WD8003ETA: + dev->board_chip |= 0x05 | WE_ID_BUS_MCA; + dev->ram_size = 0x4000; + dev->pos_regs[0] = 0xC0; + dev->pos_regs[1] = 0x6F; + dev->bit16 = 3; + break; + } + + dev->irr |= WE_IRR_ENABLE_IRQ; + dev->icr |= (dev->bit16 & 0x01); + + dp8390_mem_alloc(dev->dp8390, 0x0000, dev->ram_size); + + if (dev->base_address) + wd_io_set(dev, dev->base_address); + + memcpy(dev->dp8390->physaddr, dev->maclocal, sizeof(dev->maclocal)); + + wdlog("%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, dev->base_address, dev->irq, + dev->dp8390->physaddr[0], dev->dp8390->physaddr[1], dev->dp8390->physaddr[2], + dev->dp8390->physaddr[3], dev->dp8390->physaddr[4], dev->dp8390->physaddr[5]); /* Reset the board. */ - if (dev->board != WD8013EPA) - wd_reset(dev); + wd_reset(dev); + + /* Map this system into the memory map. */ + if (dev->bit16 & 1) { + mem_mapping_add(&dev->ram_mapping, dev->ram_addr, dev->ram_size, + wd_ram_readb, wd_ram_readw, NULL, + wd_ram_writeb, wd_ram_writew, NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + } else { + mem_mapping_add(&dev->ram_mapping, dev->ram_addr, dev->ram_size, + wd_ram_readb, NULL, NULL, + wd_ram_writeb, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + } + + mem_mapping_disable(&dev->ram_mapping); /* Attach ourselves to the network module. */ - network_attach(dev, dev->dp8390.physaddr, wd_rx); - - /* Map this system into the memory map. */ - if (dev->board != WD8013EPA) - { - mem_mapping_add(&dev->ram_mapping, dev->ram_addr, 0x4000, - wd_ram_readb, NULL, NULL, - wd_ram_writeb, NULL, NULL, - NULL, MEM_MAPPING_EXTERNAL, dev); - mem_mapping_disable(&dev->ram_mapping); - - wdlog(1, "%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, - dev->base_address, dev->base_irq, dev->ram_addr); - } + network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx); + + if (!(dev->board_chip & WE_ID_BUS_MCA)) { + wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, + dev->base_address, dev->irq, dev->ram_addr); + } return(dev); } @@ -1520,16 +787,12 @@ wd_close(void *priv) { wd_t *dev = (wd_t *)priv; - /* Make sure the platform layer is shut down. */ - network_close(); - - wd_ioremove(dev, dev->base_address); - - wdlog(1, "%s: closed\n", dev->name); + wdlog("%s: closed\n", dev->name); free(dev); } + static const device_config_t wd8003_config[] = { { @@ -1572,9 +835,6 @@ static const device_config_t wd8003_config[] = } }, }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, { "ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000, { @@ -1601,25 +861,46 @@ static const device_config_t wd8003_config[] = } }, }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, { "", "", -1 } }; -static const device_config_t wd8013_config[] = +static const device_config_t wd8003eb_config[] = { { - "base", "Address", CONFIG_HEX16, "", 0x300, + "base", "Address", CONFIG_HEX16, "", 0x280, { + { + "0x200", 0x200 + }, + { + "0x220", 0x220 + }, { "0x240", 0x240 }, + { + "0x260", 0x260 + }, { "0x280", 0x280 }, + { + "0x2A0", 0x2A0 + }, + { + "0x2C0", 0x2C0 + }, { "0x300", 0x300 }, + { + "0x340", 0x340 + }, { "0x380", 0x380 }, @@ -1632,11 +913,130 @@ static const device_config_t wd8013_config[] = "irq", "IRQ", CONFIG_SELECTION, "", 3, { { - "IRQ 2", 2 + "IRQ 2/9", 9 }, { "IRQ 3", 3 }, + { + "IRQ 4", 4 + }, + { + "IRQ 7", 7 + }, + { + "" + } + }, + }, + { + "ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000, + { + { + "C000", 0xC0000 + }, + { + "C400", 0xC4000 + }, + { + "C800", 0xC8000 + }, + { + "CC00", 0xCC000 + }, + { + "D000", 0xD0000 + }, + { + "D400", 0xD4000 + }, + { + "D800", 0xD8000 + }, + { + "DC00", 0xDC000 + }, + { + "" + } + }, + }, + { + "ram_size", "RAM size", CONFIG_SELECTION, "", 8192, + { + { + "8 kB", 8192 + }, + { + "32 kB", 32768 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + +/* WD8013EBT configuration and defaults set according to this site: + http://www.stack.nl/~marcolz/network/wd80x3.html#WD8013EBT */ +static const device_config_t wd8013_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x280, + { + { + "0x200", 0x200 + }, + { + "0x220", 0x220 + }, + { + "0x240", 0x240 + }, + { + "0x260", 0x260 + }, + { + "0x280", 0x280 + }, + { + "0x2A0", 0x2A0 + }, + { + "0x2C0", 0x2C0 + }, + { + "0x300", 0x300 + }, + { + "0x340", 0x340 + }, + { + "0x380", 0x380 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 2/9", 9 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, { "IRQ 5", 5 }, @@ -1657,12 +1057,15 @@ static const device_config_t wd8013_config[] = } }, }, - { - "mac", "MAC Address", CONFIG_MAC, "", -1 - }, { "ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000, { + { + "C000", 0xC0000 + }, + { + "C400", 0xC4000 + }, { "C800", 0xC8000 }, @@ -1686,6 +1089,23 @@ static const device_config_t wd8013_config[] = } }, }, + { + "ram_size", "RAM size", CONFIG_SELECTION, "", 16384, + { + { + "16 kB", 16384 + }, + { + "64 kB", 65536 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, { "", "", -1 } @@ -1701,6 +1121,7 @@ static const device_config_t mca_mac_config[] = } }; + const device_t wd8003e_device = { "Western Digital WD8003E", DEVICE_ISA, @@ -1710,6 +1131,15 @@ const device_t wd8003e_device = { wd8003_config }; +const device_t wd8003eb_device = { + "Western Digital WD8003EB", + DEVICE_ISA, + WD8003EB, + wd_init, wd_close, NULL, + NULL, NULL, NULL, + wd8003eb_config +}; + const device_t wd8013ebt_device = { "Western Digital WD8013EBT", DEVICE_ISA, @@ -1719,11 +1149,20 @@ const device_t wd8013ebt_device = { wd8013_config }; -const device_t wd8013epa_device = { - "Western Digital WD8013EP/A", +const device_t wd8003eta_device = { + "Western Digital WD8003ET/A", DEVICE_MCA, - WD8013EPA, + WD8003ETA, wd_init, wd_close, NULL, NULL, NULL, NULL, mca_mac_config -}; \ No newline at end of file +}; + +const device_t wd8003ea_device = { + "Western Digital WD8003E/A", + DEVICE_MCA, + WD8003EA, + wd_init, wd_close, NULL, + NULL, NULL, NULL, + mca_mac_config +}; diff --git a/src/network/net_wd8003.h b/src/network/net_wd8003.h index 44a64120f..ecf1b09e6 100644 --- a/src/network/net_wd8003.h +++ b/src/network/net_wd8003.h @@ -11,7 +11,7 @@ * - SMC/WD 8013EBT (ISA 16-bit); * - SMC/WD 8013EP/A (MCA). * - * Version: @(#)net_wd8003.c 1.0.0 2018/07/19 + * Version: @(#)net_wd8003.c 1.0.1 2018/10/22 * * Authors: Fred N. van Kempen, * TheCollector1995, @@ -45,13 +45,17 @@ enum { WD_NONE = 0, - WD8003E = 1, /* 8-bit ISA WD8003E */ - WD8013EBT = 2, /* 16-bit ISA WD8013EBT */ - WD8013EPA = 3 /* MCA WD8013EP/A */ + WD8003E, /* WD8003E : 8-bit ISA, no interface chip */ + WD8003EB, /* WD8003EB : 8-bit ISA, 5x3 interface chip */ + WD8013EBT, /* WD8013EBT : 16-bit ISA, no interface chip */ + WD8003ETA, /* WD8003ET/A: 16-bit MCA, no interface chip */ + WD8003EA /* WD8003E/A : 16-bit MCA, 5x3 interface chip */ }; extern const device_t wd8003e_device; +extern const device_t wd8003eb_device; extern const device_t wd8013ebt_device; -extern const device_t wd8013epa_device; +extern const device_t wd8003eta_device; +extern const device_t wd8003ea_device; -#endif /*NET_WD8003_H*/ \ No newline at end of file +#endif /*NET_WD8003_H*/ diff --git a/src/network/network.c b/src/network/network.c index b3f673c47..475a3674e 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -12,11 +12,11 @@ * it should be malloc'ed and then linked to the NETCARD def. * Will be done later. * - * Version: @(#)network.c 1.0.6 2018/06/19 + * Version: @(#)network.c 1.0.13 2019/12/02 * * Author: Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -62,6 +62,7 @@ #include "network.h" #include "net_3c503.h" #include "net_ne2000.h" +#include "net_pcnet.h" #include "net_wd8003.h" @@ -70,22 +71,32 @@ static netcard_t net_cards[] = { NULL }, { "[ISA] 3Com EtherLink II (3C503)","3c503", &threec503_device, NULL }, + { "[ISA] AMD PCnet-ISA", "pcnetisa", &pcnet_isa_device, + NULL }, { "[ISA] Novell NE1000", "ne1k", &ne1000_device, NULL }, { "[ISA] Novell NE2000", "ne2k", &ne2000_device, NULL }, { "[ISA] Realtek RTL8019AS", "ne2kpnp", &rtl8019as_device, NULL }, - { "[ISA] Western Digital WD8003E","wd8003e", &wd8003e_device, + { "[ISA] Western Digital WD8003E", "wd8003e", &wd8003e_device, + NULL }, + { "[ISA] Western Digital WD8003EB", "wd8003eb", &wd8003eb_device, NULL }, { "[ISA] Western Digital WD8013EBT","wd8013ebt", &wd8013ebt_device, NULL }, - { "[MCA] Novell NE/2", "ne2", &ne2_device, + { "[MCA] NetWorth Ethernet/MC", "ethernextmc", ðernext_mc_device, NULL }, - { "[MCA] Western Digital WD8013EP/A","wd8013epa", &wd8013epa_device, + { "[MCA] Western Digital WD8003ET/A","wd8003eta", &wd8003eta_device, + NULL }, + { "[MCA] Western Digital WD8003E/A", "wd8003ea", &wd8003ea_device, + NULL }, + { "[PCI] AMD PCnet-PCI", "pcnetpci", &pcnet_pci_device, NULL }, { "[PCI] Realtek RTL8029AS", "ne2kpci", &rtl8029as_device, NULL }, + { "[VLB] AMD PCnet-VL", "pcnetvlb", &pcnet_vlb_device, + NULL }, { "", "", NULL, NULL } }; @@ -95,7 +106,8 @@ static netcard_t net_cards[] = { int network_type; int network_ndev; int network_card; -char network_host[512]; +static volatile int net_wait = 0; +char network_host[522]; netdev_t network_devs[32]; #ifdef ENABLE_NIC_LOG int nic_do_log = ENABLE_NIC_LOG; @@ -116,22 +128,22 @@ static struct { #ifdef ENABLE_NETWORK_LOG int network_do_log = ENABLE_NETWORK_LOG; -#endif static void -network_log(const char *format, ...) +network_log(const char *fmt, ...) { -#ifdef ENABLE_NETWORK_LOG va_list ap; if (network_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define network_log(fmt, ...) +#endif void @@ -216,6 +228,8 @@ network_attach(void *dev, uint8_t *mac, NETRXCB rx) net_cards[network_card].rx = rx; network_mac = mac; + network_set_wait(0); + /* Create the network events. */ poll_data.wake_poll_thread = thread_create_event(); poll_data.poll_complete = thread_create_event(); @@ -438,3 +452,24 @@ network_card_get_from_internal_name(char *s) return(-1); } + + +void +network_set_wait(int wait) +{ + network_wait(1); + net_wait = wait; + network_wait(0); +} + + +int +network_get_wait(void) +{ + int ret; + + network_wait(1); + ret = net_wait; + network_wait(0); + return ret; +} diff --git a/src/network/network.h b/src/network/network.h index bdd4beb54..feae064ee 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -8,11 +8,11 @@ * * Definitions for the network module. * - * Version: @(#)network.h 1.0.2 2018/03/15 + * Version: @(#)network.h 1.0.3 2019/11/14 * * Author: Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -124,6 +124,9 @@ extern char *network_card_get_internal_name(int); extern int network_card_get_from_internal_name(char *); extern const device_t *network_card_getdevice(int); +extern void network_set_wait(int wait); +extern int network_get_wait(void); + #ifdef __cplusplus } #endif diff --git a/src/network/slirp/ip.h b/src/network/slirp/ip.h index 5fa673963..f21178360 100644 --- a/src/network/slirp/ip.h +++ b/src/network/slirp/ip.h @@ -209,7 +209,7 @@ typedef u_int32_t caddr32_t; #endif #endif -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) typedef uintptr_t ipqp_32; typedef uintptr_t ipasfragp_32; #else @@ -230,7 +230,7 @@ typedef caddr32_t ipasfragp_32; #endif struct ipovly { -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) uintptr_t ih_next, ih_prev; /* for protocol sequence q's */ #else caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ @@ -258,7 +258,7 @@ struct ipovly { * size 28 bytes */ struct ipq { -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) uintptr_t next,prev; /* to other reass headers */ #else ipqp_32 next,prev; /* to other reass headers */ @@ -276,6 +276,10 @@ struct ipq { * * Note: ipf_next must be at same offset as ipq_next above */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + struct ipasfrag { #ifdef WORDS_BIGENDIAN u_char ip_v:4, @@ -298,7 +302,11 @@ struct ipasfrag { u_int16_t ip_sum; ipasfragp_32 ipf_next; /* next fragment */ ipasfragp_32 ipf_prev; /* previous fragment */ -}; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) //WAS 0 +#endif /* * Structure stored in mbuf in inpcb.ip_options diff --git a/src/network/slirp/slirp.c b/src/network/slirp/slirp.c index 7457f1340..5ade8ae30 100644 --- a/src/network/slirp/slirp.c +++ b/src/network/slirp/slirp.c @@ -389,172 +389,127 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) 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, (char *)&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, (char *)&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(); + /* Update time */ + updtime(); - /* 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. + /* + * 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; + } + } + + ret = 0; + + /* + * 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; + } + 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, (char *)&ret, 0, 0); + 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; + } + + /* + * Continue tcp_input + */ + tcp_input((struct SLIRPmbuf *)NULL, sizeof(struct ip), so); + } else + ret = sowrite(so); + } + } + + /* + * Now UDP sockets. + * Incoming packets are sent straight away, they're not buffered. + * Incoming UDP data isn't buffered either. */ - global_readfds = NULL; - global_writefds = NULL; - global_xfds = NULL; + 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 @@ -701,10 +656,3 @@ int slirp_redir(int is_udp, int host_port, } 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/network/slirp/tcp.h b/src/network/slirp/tcp.h index d9a8ccf72..5df25a8f0 100644 --- a/src/network/slirp/tcp.h +++ b/src/network/slirp/tcp.h @@ -33,7 +33,7 @@ #ifndef _TCP_H_ #define _TCP_H_ -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) typedef uintptr_t tcp_seq; #else typedef u_int32_t tcp_seq; diff --git a/src/network/slirp/tcp_var.h b/src/network/slirp/tcp_var.h index e6fbd3abb..a9606c276 100644 --- a/src/network/slirp/tcp_var.h +++ b/src/network/slirp/tcp_var.h @@ -36,7 +36,7 @@ #include "tcpip.h" #include "tcp_timer.h" -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) typedef uintptr_t tcpiphdrp_32; #else #if SIZEOF_CHAR_P == 4 @@ -178,7 +178,7 @@ struct tcpcb { * port numbers (which are no longer needed once we've located the * tcpcb) are overlayed with an mbuf pointer. */ -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) typedef uintptr_t mbufp_32; #else #if SIZEOF_CHAR_P == 4 diff --git a/src/nmi.h b/src/nmi.h index e5e7c891d..72c2f507f 100644 --- a/src/nmi.h +++ b/src/nmi.h @@ -7,4 +7,5 @@ extern int nmi_auto_clear; extern void nmi_init(void); + extern void nmi_write(uint16_t port, uint8_t val, void *p); diff --git a/src/nvr.c b/src/nvr.c index 2037b68e9..53376295f 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -1,4 +1,4 @@ -/* +/* * VARCem Virtual ARchaeological Computer EMulator. * An emulator of (mostly) x86-based PC systems and devices, * using the ISA,EISA,VLB,MCA and PCI system buses, roughly @@ -8,11 +8,13 @@ * * Implement a generic NVRAM/CMOS/RTC device. * - * Version: @(#)nvr.c 1.0.10 2018/06/08 + * Version: @(#)nvr.c 1.0.19 2019/11/19 * - * Author: Fred N. van Kempen, + * Authors: Fred N. van Kempen, , + * David HrdliÄka, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2018,2019 David HrdliÄka. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -53,13 +55,8 @@ #include #define HAVE_STDARG_H #include "86box.h" -#include "device.h" #include "machine/machine.h" -#include "machine/m_xt_t1000.h" #include "mem.h" -#include "pic.h" -#include "pit.h" -#include "rom.h" #include "timer.h" #include "plat.h" #include "nvr.h" @@ -75,22 +72,22 @@ static nvr_t *saved_nvr = NULL; #ifdef ENABLE_NVR_LOG int nvr_do_log = ENABLE_NVR_LOG; -#endif static void -nvr_log(const char *format, ...) +nvr_log(const char *fmt, ...) { -#ifdef ENABLE_NVR_LOG va_list ap; if (nvr_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define nvr_log(fmt, ...) +#endif /* Determine whether or not the year is leap. */ @@ -130,7 +127,6 @@ rtc_tick(void) if (++intclk.tm_mday == (nvr_get_days(intclk.tm_mon, intclk.tm_year) + 1)) { intclk.tm_mday = 1; - intclk.tm_mon++; if (++intclk.tm_mon == 13) { intclk.tm_mon = 1; intclk.tm_year++; @@ -160,7 +156,7 @@ onesec_timer(void *priv) nvr->onesec_cnt = 0; } - nvr->onesec_time += (int64_t)(10000 * TIMER_USEC); + timer_advance_u64(&nvr->onesec_time, (uint64_t)(10000ULL * TIMER_USEC)); } @@ -181,10 +177,13 @@ nvr_init(nvr_t *nvr) /* Initialize the internal clock as needed. */ memset(&intclk, 0x00, sizeof(intclk)); - if (enable_sync) { + if (time_sync & TIME_SYNC_ENABLED) { /* Get the current time of day, and convert to local time. */ (void)time(&now); - tm = localtime(&now); + if(time_sync & TIME_SYNC_UTC) + tm = gmtime(&now); + else + tm = localtime(&now); /* Set the internal clock. */ nvr_time_set(tm); @@ -195,7 +194,7 @@ nvr_init(nvr_t *nvr) } /* Set up our timer. */ - timer_add(onesec_timer, &nvr->onesec_time, TIMER_ALWAYS_ENABLED, nvr); + timer_add(&nvr->onesec_time, onesec_timer, nvr, 1); /* It does not need saving yet. */ nvr_dosave = 0; @@ -252,8 +251,7 @@ nvr_load(void) if (saved_nvr == NULL) return(0); /* Clear out any old data. */ - // memset(saved_nvr->regs, 0x00, sizeof(saved_nvr->regs)); - memset(saved_nvr->regs, 0xff, sizeof(saved_nvr->regs)); + memset(saved_nvr->regs, 0x00, sizeof(saved_nvr->regs)); /* Set the defaults. */ if (saved_nvr->reset != NULL) @@ -271,11 +269,6 @@ nvr_load(void) } } - if (romset == ROM_T1000) - t1000_nvr_load(); - else if (romset == ROM_T1200) - t1200_nvr_load(); - /* Get the local RTC running! */ if (saved_nvr->start != NULL) saved_nvr->start(saved_nvr); @@ -284,6 +277,13 @@ nvr_load(void) } +void +nvr_set_ven_save(void (*ven_save)(void)) +{ + saved_nvr->ven_save = ven_save; +} + + /* Save the current NVR to a file. */ int nvr_save(void) @@ -305,10 +305,8 @@ nvr_save(void) } } - if (romset == ROM_T1000) - t1000_nvr_save(); - else if (romset == ROM_T1200) - t1200_nvr_save(); + if (saved_nvr->ven_save) + saved_nvr->ven_save(); /* Device is clean again. */ nvr_dosave = 0; @@ -318,13 +316,9 @@ nvr_save(void) void -nvr_period_recalc(void) +nvr_close(void) { - /* Make sure we have been initialized. */ - if (saved_nvr == NULL) return; - - if (saved_nvr->size != 0) - saved_nvr->recalc(saved_nvr); + saved_nvr = NULL; } diff --git a/src/nvr.h b/src/nvr.h index 11321fd6a..f315b7a51 100644 --- a/src/nvr.h +++ b/src/nvr.h @@ -1,4 +1,4 @@ -/* +/* * VARCem Virtual ARchaeological Computer EMulator. * An emulator of (mostly) x86-based PC systems and devices, * using the ISA,EISA,VLB,MCA and PCI system buses, roughly @@ -8,11 +8,13 @@ * * Definitions for the generic NVRAM/CMOS driver. * - * Version: @(#)nvr.h 1.0.7 2018/06/08 + * Version: @(#)nvr.h 1.0.11 2019/03/16 * - * Author: Fred N. van Kempen, + * Author: Fred N. van Kempen, , + * David HrdliÄka, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2018,2019 David HrdliÄka. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -55,6 +57,11 @@ #define RTC_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f)) #define RTC_BCDINC(x,y) RTC_BCD(RTC_DCB(x) + y) +/* Time sync options */ +#define TIME_SYNC_DISABLED 0 +#define TIME_SYNC_ENABLED 1 +#define TIME_SYNC_UTC 2 + /* Define a generic RTC/NVRAM device. */ typedef struct _nvr_ { @@ -63,7 +70,7 @@ typedef struct _nvr_ { int8_t irq; uint8_t onesec_cnt; - int64_t onesec_time; + pc_timer_t onesec_time; void *data; /* local data */ @@ -71,7 +78,7 @@ typedef struct _nvr_ { void (*reset)(struct _nvr_ *); void (*start)(struct _nvr_ *); void (*tick)(struct _nvr_ *); - void (*recalc)(struct _nvr_ *); + void (*ven_save)(void); uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ } nvr_t; @@ -83,6 +90,7 @@ extern const device_t at_nvr_old_device; extern const device_t at_nvr_device; extern const device_t ps_nvr_device; extern const device_t amstrad_nvr_device; +extern const device_t ibmat_nvr_device; #endif @@ -92,13 +100,14 @@ extern void nvr_init(nvr_t *); extern wchar_t *nvr_path(wchar_t *str); extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode); extern int nvr_load(void); +extern void nvr_close(void); +extern void nvr_set_ven_save(void (*ven_save)(void)); extern int nvr_save(void); extern int nvr_is_leap(int year); extern int nvr_get_days(int month, int year); extern void nvr_time_get(struct tm *); extern void nvr_time_set(struct tm *); -extern void nvr_period_recalc(void); #endif /*EMU_NVR_H*/ diff --git a/src/nvr_at.c b/src/nvr_at.c index e6cd8cc71..967f14018 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -189,16 +189,16 @@ * including the later update (DS12887A) which implemented a * "century" register to be compatible with Y2K. * - * Version: @(#)nvr_at.c 1.0.9 2018/05/10 + * Version: @(#)nvr_at.c 1.0.16 2019/11/19 * * Authors: Fred N. van Kempen, * Miran Grca, * Mahod, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. * * 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 @@ -232,9 +232,9 @@ #include "mem.h" #include "nmi.h" #include "pic.h" +#include "timer.h" #include "pit.h" #include "rom.h" -#include "timer.h" #include "device.h" #include "nvr.h" @@ -286,12 +286,18 @@ typedef struct { int8_t stat; + uint8_t cent; + uint8_t def; - uint16_t addr; + uint8_t addr; - int64_t ecount, - rtctime; + int16_t count, state; + + uint64_t ecount, + rtc_time; + pc_timer_t update_timer, + rtc_timer; } local_t; @@ -404,6 +410,8 @@ timer_update(void *priv) local_t *local = (local_t *)nvr->data; struct tm tm; + local->ecount = 0LL; + if (! (nvr->regs[RTC_REGB] & REGB_SET)) { /* Get the current time from the internal clock. */ nvr_time_get(&tm); @@ -441,27 +449,33 @@ timer_update(void *priv) picint(1 << nvr->irq); } } - - local->ecount = 0; } -/* Re-calculate the timer values. */ static void -timer_recalc(nvr_t *nvr, int add) +timer_load_count(nvr_t *nvr) { - local_t *local = (local_t *)nvr->data; - int64_t c, nt; + int c = nvr->regs[RTC_REGA] & REGA_RS; + local_t *local = (local_t *) nvr->data; - c = 1ULL << ((nvr->regs[RTC_REGA] & REGA_RS) - 1); - nt = (int64_t)(RTCCONST * c * (1<rtctime = nt; + if ((nvr->regs[RTC_REGA] & 0x70) != 0x20) { + local->state = 0; return; - } else if (add == 1) - local->rtctime += nt; - else if (local->rtctime > nt) - local->rtctime = nt; + } + + local->state = 1; + + switch (c) { + case 0: + local->state = 0; + break; + case 1: case 2: + local->count = 1 << (c + 6); + break; + default: + local->count = 1 << (c - 1); + break; + } } @@ -471,13 +485,16 @@ timer_intr(void *priv) nvr_t *nvr = (nvr_t *)priv; local_t *local = (local_t *)nvr->data; - if (! (nvr->regs[RTC_REGA] & REGA_RS)) { - local->rtctime = 0x7fffffff; - return; - } + timer_advance_u64(&local->rtc_timer, RTCCONST); - /* Update our timer interval. */ - timer_recalc(nvr, 1); + if (local->state == 1) { + local->count--; + if (local->count == 0) + timer_load_count(nvr); + else + return; + } else + return; nvr->regs[RTC_REGC] |= REGC_PF; if (nvr->regs[RTC_REGB] & REGB_PIE) { @@ -504,7 +521,8 @@ timer_tick(nvr_t *nvr) rtc_tick(); /* Schedule the actual update. */ - local->ecount = (int64_t)((244.0 + 1984.0) * TIMER_USEC); + local->ecount = (244ULL + 1984ULL) * TIMER_USEC; + timer_set_delay_u64(&local->update_timer, local->ecount); } } @@ -518,17 +536,14 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) struct tm tm; uint8_t old; - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); if (addr & 1) { old = nvr->regs[local->addr]; switch(local->addr) { case RTC_REGA: nvr->regs[RTC_REGA] = val; - if (val & REGA_RS) - timer_recalc(nvr, 1); - else - local->rtctime = 0x7fffffff; + timer_load_count(nvr); break; case RTC_REGB: @@ -542,7 +557,7 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) case RTC_REGC: /* R/O */ case RTC_REGD: /* R/O */ - break; + break; default: /* non-RTC registers are just NVRAM */ if (nvr->regs[local->addr] != val) { @@ -554,7 +569,7 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) if ((local->addr < RTC_REGA) || ((local->cent != 0xff) && (local->addr == local->cent))) { if ((local->addr != 1) && (local->addr != 3) && (local->addr != 5)) { - if ((old != val) && !enable_sync) { + if ((old != val) && !(time_sync & TIME_SYNC_ENABLED)) { /* Update internal clock. */ time_get(nvr, &tm); nvr_time_set(&tm); @@ -565,7 +580,7 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) } else { local->addr = (val & (nvr->size - 1)); if (!(machines[machine].flags & MACHINE_MCA) && - (romset != ROM_IBMPS1_2133)) + !(machines[machine].flags & MACHINE_NONMI)) nmi_mask = (~val & 0x80); } } @@ -579,9 +594,9 @@ nvr_read(uint16_t addr, void *priv) local_t *local = (local_t *)nvr->data; uint8_t ret; - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); - if (addr & 1) switch(local->addr) { + if (addr & 1) switch(local->addr) { case RTC_REGA: ret = (nvr->regs[RTC_REGA] & 0x7f) | local->stat; break; @@ -600,9 +615,8 @@ nvr_read(uint16_t addr, void *priv) default: ret = nvr->regs[local->addr]; break; - } else { + } else ret = local->addr; - } return(ret); } @@ -614,7 +628,8 @@ nvr_reset(nvr_t *nvr) { local_t *local = (local_t *)nvr->data; - memset(nvr->regs, 0x00, RTC_REGS); + /* memset(nvr->regs, local->def, RTC_REGS); */ + memset(nvr->regs, local->def, nvr->size); nvr->regs[RTC_DOM] = 1; nvr->regs[RTC_MONTH] = 1; nvr->regs[RTC_YEAR] = RTC_BCD(80); @@ -627,10 +642,23 @@ nvr_reset(nvr_t *nvr) static void nvr_start(nvr_t *nvr) { + int i; + local_t *local = (local_t *) nvr->data; + struct tm tm; + int default_found = 0; + + for (i = 0; i < nvr->size; i++) { + if (nvr->regs[i] == local->def) + default_found++; + } + + if (default_found == nvr->size) + nvr->regs[0x0e] = 0xff; /* If load failed or it loaded an uninitialized NVR, + mark everything as bad. */ /* Initialize the internal and chip times. */ - if (enable_sync) { + if (time_sync & TIME_SYNC_ENABLED) { /* Use the internal clock's time. */ nvr_time_get(&tm); time_set(nvr, &tm); @@ -643,14 +671,24 @@ nvr_start(nvr_t *nvr) /* Start the RTC. */ nvr->regs[RTC_REGA] = (REGA_RS2|REGA_RS1); nvr->regs[RTC_REGB] = REGB_2412; - timer_recalc(nvr, 1); } static void -nvr_recalc(nvr_t *nvr) +nvr_at_speed_changed(void *priv) { - timer_recalc(nvr, 0); + nvr_t *nvr = (nvr_t *) priv; + local_t *local = (local_t *) nvr->data; + + timer_disable(&local->rtc_timer); + timer_set_delay_u64(&local->rtc_timer, RTCCONST); + + timer_disable(&local->update_timer); + if (local->ecount > 0ULL) + timer_set_delay_u64(&local->update_timer, local->ecount); + + timer_disable(&nvr->onesec_time); + timer_set_delay_u64(&nvr->onesec_time, (10000ULL * TIMER_USEC)); } @@ -663,11 +701,7 @@ nvr_at_init(const device_t *info) /* Allocate an NVR for this machine. */ nvr = (nvr_t *)malloc(sizeof(nvr_t)); if (nvr == NULL) return(NULL); - /* FIXME: See which is correct, this or 0xFF. */ - if (info->local == 0) - memset(nvr, 0xff, sizeof(nvr_t)); - else - memset(nvr, 0x00, sizeof(nvr_t)); + memset(nvr, 0x00, sizeof(nvr_t)); local = (local_t *)malloc(sizeof(local_t)); memset(local, 0x00, sizeof(local_t)); @@ -675,6 +709,7 @@ nvr_at_init(const device_t *info) /* This is machine specific. */ nvr->size = machines[machine].nvrmask + 1; + local->def = 0x00; switch(info->local) { case 0: /* standard AT, no century register */ nvr->irq = 8; @@ -694,21 +729,31 @@ nvr_at_init(const device_t *info) case 3: /* Amstrad PC's */ nvr->irq = 1; local->cent = RTC_CENTURY_AT; + local->def = 0xff; break; + + case 4: /* IBM AT */ + nvr->irq = 8; + local->cent = RTC_CENTURY_AT; + local->def = 0xff; + break; + } /* Set up any local handlers here. */ nvr->reset = nvr_reset; nvr->start = nvr_start; nvr->tick = timer_tick; - nvr->recalc = nvr_recalc; /* Initialize the generic NVR. */ nvr_init(nvr); /* Start the timers. */ - timer_add(timer_update, &local->ecount, &local->ecount, nvr); - timer_add(timer_intr, &local->rtctime, TIMER_ALWAYS_ENABLED, nvr); + timer_add(&local->update_timer, timer_update, nvr, 0); + + timer_add(&local->rtc_timer, timer_intr, nvr, 0); + timer_load_count(nvr); + timer_set_delay_u64(&local->rtc_timer, RTCCONST); /* Set up the I/O handler for this device. */ io_sethandler(0x0070, 2, @@ -721,7 +766,14 @@ nvr_at_init(const device_t *info) static void nvr_at_close(void *priv) { - nvr_t *nvr = (nvr_t *)priv; + nvr_t *nvr = (nvr_t *) priv; + local_t *local = (local_t *) nvr->data; + + nvr_close(); + + timer_disable(&local->rtc_timer); + timer_disable(&local->update_timer); + timer_disable(&nvr->onesec_time); if (nvr->fn != NULL) free(nvr->fn); @@ -738,7 +790,7 @@ const device_t at_nvr_old_device = { DEVICE_ISA | DEVICE_AT, 0, nvr_at_init, nvr_at_close, NULL, - NULL, NULL, + NULL, nvr_at_speed_changed, NULL }; @@ -747,7 +799,7 @@ const device_t at_nvr_device = { DEVICE_ISA | DEVICE_AT, 1, nvr_at_init, nvr_at_close, NULL, - NULL, NULL, + NULL, nvr_at_speed_changed, NULL }; @@ -756,7 +808,7 @@ const device_t ps_nvr_device = { DEVICE_PS2, 2, nvr_at_init, nvr_at_close, NULL, - NULL, NULL, + NULL, nvr_at_speed_changed, NULL }; @@ -765,6 +817,15 @@ const device_t amstrad_nvr_device = { MACHINE_ISA | MACHINE_AT, 3, nvr_at_init, nvr_at_close, NULL, - NULL, NULL, + NULL, nvr_at_speed_changed, + NULL +}; + +const device_t ibmat_nvr_device = { + "IBM AT NVRAM", + DEVICE_ISA | DEVICE_AT, + 4, + nvr_at_init, nvr_at_close, NULL, + NULL, nvr_at_speed_changed, NULL }; diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index 4431d7a4f..5c943a0eb 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -8,7 +8,7 @@ * * Handling of the PS/2 series CMOS devices. * - * Version: @(#)nvr_ps2.c 1.0.7 2018/04/26 + * Version: @(#)nvr_ps2.c 1.0.10 2018/10/02 * * Authors: Fred N. van Kempen, * Sarah Walker, @@ -40,11 +40,11 @@ #include #include #include "86box.h" -#include "cpu/cpu.h" #include "machine/machine.h" #include "device.h" #include "io.h" #include "mem.h" +#include "timer.h" #include "nvr.h" #include "nvr_ps2.h" #include "rom.h" @@ -54,6 +54,8 @@ typedef struct { int addr; uint8_t ram[8192]; + + wchar_t *fn; } ps2_nvr_t; @@ -105,26 +107,24 @@ ps2_nvr_write(uint16_t port, uint8_t val, void *priv) static void * ps2_nvr_init(const device_t *info) { + char temp[64]; ps2_nvr_t *nvr; FILE *f = NULL; + int c; nvr = (ps2_nvr_t *)malloc(sizeof(ps2_nvr_t)); memset(nvr, 0x00, sizeof(ps2_nvr_t)); - + + /* Set up the NVR file's name. */ + sprintf(temp, "%s_sec.nvr", machine_get_internal_name()); + c = strlen(temp); + nvr->fn = (wchar_t *)malloc((c + 1) * sizeof(wchar_t)); + mbstowcs(nvr->fn, temp, c + 1); + io_sethandler(0x0074, 3, ps2_nvr_read,NULL,NULL, ps2_nvr_write,NULL,NULL, nvr); - switch (romset) { - case ROM_IBMPS2_M70_TYPE3: - f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"rb"); - break; - case ROM_IBMPS2_M70_TYPE4: - f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"rb"); - break; - case ROM_IBMPS2_M80: - f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"rb"); - break; - } + f = nvr_fopen(nvr->fn, L"rb"); memset(nvr->ram, 0xff, 8192); if (f != NULL) { @@ -142,17 +142,7 @@ ps2_nvr_close(void *priv) ps2_nvr_t *nvr = (ps2_nvr_t *)priv; FILE *f = NULL; - switch (romset) { - case ROM_IBMPS2_M70_TYPE3: - f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"wb"); - break; - case ROM_IBMPS2_M70_TYPE4: - f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"wb"); - break; - case ROM_IBMPS2_M80: - f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"wb"); - break; - } + f = nvr_fopen(nvr->fn, L"wb"); if (f != NULL) { (void)fwrite(nvr->ram, 8192, 1, f); diff --git a/src/pc.c b/src/pc.c index 88fa42579..9f0bcc926 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,15 +8,15 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.73 2018/06/02 + * Version: @(#)pc.c 1.0.93 2019/12/05 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -29,24 +29,35 @@ #define HAVE_STDARG_H #include "86box.h" #include "config.h" +#include "mem.h" +#ifdef USE_NEW_DYNAREC +#ifdef USE_DYNAREC +#include "cpu_new/cpu.h" +# include "cpu_new/codegen.h" +#endif +#include "cpu_new/x86_ops.h" +#else #include "cpu/cpu.h" #ifdef USE_DYNAREC # include "cpu/codegen.h" #endif #include "cpu/x86_ops.h" +#endif #include "io.h" -#include "mem.h" #include "rom.h" #include "dma.h" #include "pci.h" #include "pic.h" +#include "timer.h" +#include "device.h" #include "pit.h" #include "random.h" #include "timer.h" -#include "device.h" #include "nvr.h" #include "machine/machine.h" #include "bugger.h" +#include "isamem.h" +#include "isartc.h" #include "lpt.h" #include "serial.h" #include "keyboard.h" @@ -58,11 +69,11 @@ #include "disk/hdc.h" #include "disk/hdc_ide.h" #include "scsi/scsi.h" +#include "scsi/scsi_device.h" #include "cdrom/cdrom.h" #include "disk/zip.h" #include "scsi/scsi_disk.h" #include "cdrom/cdrom_image.h" -#include "cdrom/cdrom_null.h" #include "network/network.h" #include "sound/sound.h" #include "sound/midi.h" @@ -106,8 +117,9 @@ int vid_cga_contrast = 0, /* (C) video */ enable_overscan = 0, /* (C) video */ force_43 = 0; /* (C) video */ int serial_enabled[SERIAL_MAX] = {0,0}, /* (C) enable serial ports */ - lpt_enabled = 0, /* (C) enable LPT ports */ - bugger_enabled = 0; /* (C) enable ISAbugger */ + bugger_enabled = 0, /* (C) enable ISAbugger */ + isamem_type[ISAMEM_MAX] = { 0,0,0,0 }, /* (C) enable ISA mem cards */ + isartc_type = 0; /* (C) enable ISA RTC card */ int gfxcard = 0; /* (C) graphics/video card */ int sound_is_float = 1, /* (C) sound uses FP values */ GAMEBLASTER = 0, /* (C) sound option */ @@ -119,7 +131,10 @@ int cpu_manufacturer = 0, /* (C) cpu manufacturer */ cpu_use_dynarec = 0, /* (C) cpu uses/needs Dyna */ cpu = 3, /* (C) cpu type */ enable_external_fpu = 0; /* (C) enable external FPU */ -int enable_sync = 0; /* (C) enable time sync */ +int time_sync = 0; /* (C) enable time sync */ +#ifdef USE_DISCORD +int enable_discord = 0; /* (C) enable Discord integration */ +#endif /* Statistics. */ extern int @@ -132,11 +147,8 @@ int fps, framecount; /* emulator % */ int CPUID; int output; int atfullspeed; -int cpuspeed2; int clockrate; -int gfx_present[GFX_MAX]; /* should not be here */ - wchar_t exe_path[1024]; /* path (dir) of executable */ wchar_t usr_path[1024]; /* path (dir) of user data */ wchar_t cfg_path[1024]; /* full path of config file */ @@ -144,7 +156,6 @@ FILE *stdlog = NULL; /* file to log output to */ int scrnsz_x = SCREEN_RES_X, /* current screen size, X */ scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */ int config_changed; /* config has changed */ -int romset; /* current machine ID */ int title_update; int64_t main_time; @@ -254,11 +265,17 @@ fatal(const char *fmt, ...) config_save(); dumppic(); +#ifdef ENABLE_808X_LOG dumpregs(1); +#endif /* Make sure the message does not have a trailing newline. */ if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; + /* Cleanly terminate all of the emulator's components so as + to avoid things like threads getting stuck. */ + do_stop(); + ui_msgbox(MBX_ERROR|MBX_FATAL|MBX_ANSI, temp); fflush(stdlog); @@ -269,22 +286,22 @@ fatal(const char *fmt, ...) #ifdef ENABLE_PC_LOG int pc_do_log = ENABLE_PC_LOG; -#endif static void -pc_log(const char *format, ...) +pc_log(const char *fmt, ...) { -#ifdef ENABLE_PC_LOG va_list ap; if (pc_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define pc_log(fmt, ...) +#endif /* @@ -419,8 +436,8 @@ usage: /* If the specified path does not yet exist, create it. */ - if (! plat_dir_check(path)) - plat_dir_create(path); + if (! plat_dir_check(usr_path)) + plat_dir_create(usr_path); } /* Make sure we have a trailing backslash. */ @@ -457,9 +474,6 @@ usage: wcscpy(usr_path, cfg); else wcscat(usr_path, cfg); - - /* Make sure we have a trailing backslash. */ - plat_path_slash(usr_path); } /* At this point, we can safely create the full path name. */ @@ -489,7 +503,6 @@ usage: mouse_init(); cdrom_global_init(); zip_global_init(); - scsi_disk_global_init(); /* Load the configuration file. */ config_load(); @@ -499,85 +512,38 @@ usage: } -void -pc_full_speed(void) -{ - cpuspeed2 = cpuspeed; - - if (! atfullspeed) { - pc_log("Set fullspeed - %i %i %i\n", is386, AT, cpuspeed2); - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) - setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - else - setpitclock(14318184.0); - } - atfullspeed = 1; - - nvr_period_recalc(); -} - - void pc_speed_changed(void) { if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) - setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + pit_set_clock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); else - setpitclock(14318184.0); - - nvr_period_recalc(); + pit_set_clock(14318184.0); } -#if 0 -/* Re-load system configuration and restart. */ -/* FIXME: this has to be reviewed! */ void -pc_reload(wchar_t *fn) +pc_full_speed(void) { - int i; - - config_write(cfg_path); - - for (i=0; i=0; c--) { - if (gfx_present[c]) { + if (! video_card_available(gfxcard)) { + c = 0; + while (video_get_internal_name(c) != NULL) { + gfxcard = -1; + if (video_card_available(c)) { + ui_msgbox(MBX_INFO, (wchar_t *)IDS_2064); gfxcard = c; config_save(); - - /* This can loop if all cards now bad.. */ - goto again2; + break; } + c++; + } + if (gfxcard == -1) { + fatal("No available video cards\n"); + exit(-1); + return(0); } } - // cpuspeed2 = (AT) ? 2 : 1; - cpuspeed2 = (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) ? 2 : 1; atfullspeed = 0; random_init(); @@ -647,27 +603,16 @@ again2: keyboard_init(); joystick_init(); - video_init(); - device_init(); - timer_reset(); + video_init(); fdd_init(); sound_init(); - hdc_init(hdc_name); + hdc_init(); - cdrom_hard_reset(); - - zip_hard_reset(); - - scsi_disk_hard_reset(); - - scsi_card_init(); - - pc_full_speed(); - shadowbios = 0; + video_reset_close(); return(1); } @@ -715,9 +660,15 @@ pc_send_cae(void) void pc_reset_hard_close(void) { + ui_sb_set_ready(0); + + /* Turn off timer processing to avoid potential segmentation faults. */ + timer_close(); + suppress_overscan = 0; nvr_save(); + nvr_close(); mouse_close(); @@ -725,11 +676,19 @@ pc_reset_hard_close(void) device_close_all(); + scsi_device_close_all(); + midi_close(); cdrom_close(); + zip_close(); + + scsi_disk_close(); + closeal(); + + video_reset_close(); } @@ -750,24 +709,29 @@ pc_reset_hard_init(void) /* Reset the general machine support modules. */ io_init(); - timer_reset(); + + /* Turn on and (re)initialize timer processing. */ + timer_init(); device_init(); sound_reset(); - /* This is needed to initialize the serial timer. */ - serial_init(); - - cdrom_hard_reset(); - - zip_hard_reset(); - - scsi_disk_hard_reset(); - /* Initialize the actual machine and its basic modules. */ machine_init(); + /* Reset and reconfigure the serial ports. */ + serial_standalone_init(); + + /* Reset and reconfigure the Sound Card layer. */ + sound_card_reset(); + + /* Reset any ISA memory cards. */ + isamem_reset(); + + /* Reset any ISA RTC cards. */ + isartc_reset(); + fdd_reset(); /* @@ -781,28 +745,24 @@ pc_reset_hard_init(void) /* Reset some basic devices. */ speaker_init(); - serial_reset(); lpt_devices_init(); shadowbios = 0; /* - * This has to be after the serial initialization so that - * serial_init() doesn't break the serial mouse by resetting - * the RCR callback to NULL. + * Reset the mouse, this will attach it to any port needed. */ mouse_reset(); - /* Reset the video card. */ - video_reset(gfxcard); - /* Reset the Hard Disk Controller module. */ hdc_reset(); - /* Reset and reconfigure the SCSI layer. */ scsi_card_init(); - /* Reset and reconfigure the Sound Card layer. */ - sound_card_reset(); + cdrom_hard_reset(); + + zip_hard_reset(); + + scsi_disk_hard_reset(); /* Reset and reconfigure the Network Card layer. */ network_reset(); @@ -810,13 +770,14 @@ pc_reset_hard_init(void) if (joystick_type != 7) gameport_update_joystick_type(); - if (config_changed) { - ui_sb_update_panes(); + ui_sb_update_panes(); + if (config_changed) { config_save(); config_changed = 0; - } + } else + ui_sb_set_ready(1); /* Needs the status bar... */ if (bugger_enabled) @@ -828,10 +789,8 @@ pc_reset_hard_init(void) pic_reset(); cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) - setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - else - setpitclock(14318184.0); + atfullspeed = 0; + pc_full_speed(); } @@ -883,12 +842,18 @@ pc_close(thread_t *ptr) plat_delay_ms(200); } +#ifdef USE_NEW_DYNAREC + codegen_close(); +#endif + nvr_save(); config_save(); plat_mouse_capture(0); + timer_close(); + lpt_devices_close(); for (i=0; i + * Fred N. van Kempen, + * Sarah Walker, + * + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2008-2020 Sarah Walker. + */ #include #include #include @@ -14,749 +34,743 @@ #include "pci.h" #include "piix.h" #include "keyboard.h" -#if 0 -#include "scsi/scsi.h" -#include "cdrom/cdrom.h" -#include "disk/hdc.h" -#include "disk/hdc_ide.h" -#include "disk/zip.h" -#endif -static uint64_t pci_irq_hold[16]; +typedef struct { + uint8_t id, type; + uint8_t irq_routing[4]; -typedef struct -{ - uint8_t id, type; - uint8_t irq_routing[4]; - void (*write) (int func, int addr, uint8_t val, void *priv); - uint8_t (*read) (int func, int addr, void *priv); - void * priv; + void *priv; + void (*write)(int func, int addr, uint8_t val, void *priv); + uint8_t (*read)(int func, int addr, void *priv); } pci_card_t; -static pci_card_t pci_cards[32]; -static uint8_t last_pci_card = 0; - -static uint8_t pci_card_to_slot_mapping[32]; - -static uint8_t elcr[2] = { 0, 0 }; - -static uint8_t pci_irqs[4]; - -typedef struct -{ - uint8_t enabled; - uint8_t irq_line; +typedef struct { + uint8_t enabled; + uint8_t irq_line; } pci_mirq_t; -static pci_mirq_t pci_mirqs[2]; -static int pci_index, pci_func, pci_card, pci_bus, pci_enable, pci_key; -int pci_burst_time, pci_nonburst_time; +int pci_burst_time, + pci_nonburst_time; + +static pci_card_t pci_cards[32]; +static uint8_t last_pci_card = 0; +static uint8_t pci_card_to_slot_mapping[32]; +static uint8_t elcr[2] = { 0, 0 }; +static uint8_t pci_irqs[4], pci_irq_level[4]; +static uint64_t pci_irq_hold[16]; +static pci_mirq_t pci_mirqs[3]; +static int pci_type, + pci_index, + pci_func, + pci_card, + pci_bus, + pci_enable, + pci_key; +static int trc_reg = 0, elcr_enabled = 1; -static int trc_reg = 0; #ifdef ENABLE_PCI_LOG int pci_do_log = ENABLE_PCI_LOG; + + +static void +pci_log(const char *fmt, ...) +{ + va_list ap; + + if (pci_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pci_log(fmt, ...) #endif static void -pcilog(const char *fmt, ...) +pci_cf8_write(uint16_t port, uint32_t val, void *priv) { -#ifdef ENABLE_PCI_LOG - va_list ap; - - if (pci_do_log) - { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif + pci_index = val & 0xff; + pci_func = (val >> 8) & 7; + pci_card = (val >> 11) & 31; + pci_bus = (val >> 16) & 0xff; + pci_enable = (val >> 31) & 1; } -static void pci_cf8_write(uint16_t port, uint32_t val, void *p) +static uint32_t +pci_cf8_read(uint16_t port, void *priv) { - pci_index = val & 0xff; - pci_func = (val >> 8) & 7; - pci_card = (val >> 11) & 31; - pci_bus = (val >> 16) & 0xff; - pci_enable = (val >> 31) & 1; + return pci_index | (pci_func << 8) | + (pci_card << 11) | (pci_bus << 16) | (pci_enable << 31); } -static uint32_t pci_cf8_read(uint16_t port, void *p) -{ - return pci_index | (pci_func << 8) | (pci_card << 11) | (pci_bus << 16) | (pci_enable << 31); -} -static void pci_write(uint16_t port, uint8_t val, void *priv) +static void +pci_write(uint16_t port, uint8_t val, void *priv) { - uint8_t slot = 0; + uint8_t slot = 0; - switch (port) - { - case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: - if (!pci_enable) - return; - - if (!pci_bus) - { + switch (port) { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (! pci_enable) + return; + + if (! pci_bus) { slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xFF) - { - if (pci_cards[slot].write) - { - /* pcilog("Reading PCI card on slot %02X (pci_cards[%i])...\n", pci_card, slot); */ + if (slot != 0xff) { + if (pci_cards[slot].write) { + pci_log("Writing to PCI card on slot %02X (pci_cards[%i]) (%02X:%02X)...\n", pci_card, slot, pci_func, pci_index); pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); } } } - - break; - } + + break; + } } -static uint8_t pci_read(uint16_t port, void *priv) + +static uint8_t +pci_read(uint16_t port, void *priv) { - uint8_t slot = 0; + uint8_t slot = 0; - switch (port) - { - case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: - if (!pci_enable) - return 0xff; + switch (port) { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (! pci_enable) + return 0xff; - if (!pci_bus) - { + if (! pci_bus) { slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xFF) - { + if (slot != 0xff) { if (pci_cards[slot].read) - { return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); - } } } - return 0xff; - } - return 0xff; + return 0xff; + } + + return 0xff; } -static void elcr_write(uint16_t port, uint8_t val, void *priv) + +static void +elcr_write(uint16_t port, uint8_t val, void *priv) { - /* pcilog("ELCR%i: WRITE %02X\n", port & 1, val); */ - if (port & 1) - { - val &= 0xDE; - } + pci_log("ELCR%i: WRITE %02X\n", port & 1, val); + + if (port & 1) + val &= 0xde; + else + val &= 0xf8; + + elcr[port & 1] = val; + + pci_log("ELCR %i: %c %c %c %c %c %c %c %c\n", + port & 1, + (val & 1) ? 'L' : 'E', + (val & 2) ? 'L' : 'E', + (val & 4) ? 'L' : 'E', + (val & 8) ? 'L' : 'E', + (val & 0x10) ? 'L' : 'E', + (val & 0x20) ? 'L' : 'E', + (val & 0x40) ? 'L' : 'E', + (val & 0x80) ? 'L' : 'E'); +} + + +static uint8_t +elcr_read(uint16_t port, void *priv) +{ + pci_log("ELCR%i: READ %02X\n", port & 1, elcr[port & 1]); + + return elcr[port & 1]; +} + + +static void +elcr_reset(void) +{ + pic_reset(); + + elcr[0] = 0x00; + elcr[1] = 0x00; +} + + +static void pci_type2_write(uint16_t port, uint8_t val, void *priv); +static uint8_t pci_type2_read(uint16_t port, void *priv); + + +static void +pci_type2_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t slot = 0; + + if (port == 0xcf8) { + pci_func = (val >> 1) & 7; + + if (!pci_key && (val & 0xf0)) + io_sethandler(0xc000, 0x1000, + pci_type2_read, NULL, NULL, + pci_type2_write, NULL, NULL, priv); else - { - val &= 0xF8; + io_removehandler(0xc000, 0x1000, + pci_type2_read, NULL, NULL, + pci_type2_write, NULL, NULL, priv); + + pci_key = val & 0xf0; + } else if (port == 0xcfa) { + pci_bus = val; + } else { + pci_card = (port >> 8) & 0xf; + pci_index = port & 0xff; + + if (! pci_bus) { + slot = pci_card_to_slot_mapping[pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].write) { + pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); + } + } } - elcr[port & 1] = val; - - pcilog("ELCR %i: %c %c %c %c %c %c %c %c\n", port & 1, (val & 1) ? 'L' : 'E', (val & 2) ? 'L' : 'E', (val & 4) ? 'L' : 'E', (val & 8) ? 'L' : 'E', (val & 0x10) ? 'L' : 'E', (val & 0x20) ? 'L' : 'E', (val & 0x40) ? 'L' : 'E', (val & 0x80) ? 'L' : 'E'); + } } -static uint8_t elcr_read(uint16_t port, void *priv) + +static uint8_t +pci_type2_read(uint16_t port, void *priv) { - /* pcilog("ELCR%i: READ %02X\n", port & 1, elcr[port & 1]); */ - return elcr[port & 1]; -} + uint8_t slot = 0; -static void elcr_reset(void) -{ - pic_reset(); - /* elcr[0] = elcr[1] = 0; */ - elcr[0] = 0x98; - elcr[1] = 0x00; -} + if (port == 0xcf8) + return pci_key | (pci_func << 1); -static void pci_type2_write(uint16_t port, uint8_t val, void *priv); -static uint8_t pci_type2_read(uint16_t port, void *priv); + if (port == 0xcfa) + return pci_bus; -static void pci_type2_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t slot = 0; + pci_card = (port >> 8) & 0xf; + pci_index = port & 0xff; - if (port == 0xcf8) - { - pci_func = (val >> 1) & 7; - if (!pci_key && (val & 0xf0)) - io_sethandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); - else - io_removehandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); - pci_key = val & 0xf0; - } - else if (port == 0xcfa) - { - pci_bus = val; - } - else - { - pci_card = (port >> 8) & 0xf; - pci_index = port & 0xff; - - if (!pci_bus) - { - slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xFF) - { - if (pci_cards[slot].write) - { - pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); - } - } + if (! pci_bus) { + slot = pci_card_to_slot_mapping[pci_card]; + if (slot != 0xff) { + if (pci_cards[slot].read) { + return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); } - } + } + } + + return 0xff; } -static uint8_t pci_type2_read(uint16_t port, void *priv) + +void +pci_set_irq_routing(int pci_int, int irq) { - uint8_t slot = 0; - - if (port == 0xcf8) - { - return pci_key | (pci_func << 1); - } - else if (port == 0xcfa) - { - return pci_bus; - } - else - { - pci_card = (port >> 8) & 0xf; - pci_index = port & 0xff; - - if (!pci_bus) - { - slot = pci_card_to_slot_mapping[pci_card]; - if (slot != 0xFF) - { - if (pci_cards[slot].read) - { - return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); - } - } - } - } - return 0xff; + pci_irqs[pci_int - 1] = irq; } -void pci_set_irq_routing(int pci_int, int irq) + +void +pci_set_irq_level(int pci_int, int level) { - pci_irqs[pci_int - 1] = irq; + pci_irq_level[pci_int - 1] = !!level; } -void pci_enable_mirq(int mirq) + +void +pci_enable_mirq(int mirq) { - pci_mirqs[mirq].enabled = 1; + pci_mirqs[mirq].enabled = 1; } -void pci_set_mirq_routing(int mirq, int irq) + +void +pci_set_mirq_routing(int mirq, int irq) { - pci_mirqs[mirq].irq_line = irq; + pci_mirqs[mirq].irq_line = irq; } -int pci_irq_is_level(int irq) -{ - int real_irq = irq & 7; +int +pci_irq_is_level(int irq) +{ + int real_irq = irq & 7; + + if (elcr_enabled) { if ((irq <= 2) || (irq == 8) || (irq == 13)) - { return 0; - } if (irq > 7) - { return !!(elcr[1] & (1 << real_irq)); - } + + return !!(elcr[0] & (1 << real_irq)); + } else { + if (irq < 8) + return (pic.icw1 & 8) ? 1 : 0; else - { - return !!(elcr[0] & (1 << real_irq)); - } + return (pic2.icw1 & 8) ? 1 : 0; + } } -uint8_t pci_use_mirq(uint8_t mirq) + +uint8_t +pci_use_mirq(uint8_t mirq) { - if (!PCI || !pci_mirqs[0].enabled) - { - return 0; - } + if (!PCI || !pci_mirqs[mirq].enabled) + return 0; - if (pci_mirqs[mirq].irq_line & 0x80) - { - return 0; - } + if (pci_mirqs[mirq].irq_line & 0x80) + return 0; - return 1; + return 1; } -#define pci_mirq_log pcilog -void pci_set_mirq(uint8_t mirq) +void +pci_set_mirq(uint8_t mirq, int level) { - uint8_t irq_line = 0; - uint8_t level = 0; + uint8_t irq_line = 0; - if (!pci_mirqs[mirq].enabled) - { - pci_mirq_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq); - return; - } + if (! pci_mirqs[mirq].enabled) { + pci_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq); + return; + } - if (pci_mirqs[mirq].irq_line > 0x0F) - { - pci_mirq_log("pci_set_mirq(%02X): IRQ line is disabled\n", mirq); - return; - } - else - { - irq_line = pci_mirqs[mirq].irq_line; - pci_mirq_log("pci_set_mirq(%02X): Using IRQ %i\n", mirq, irq_line); - } + if (pci_mirqs[mirq].irq_line > 0x0f) { + pci_log("pci_set_mirq(%02X): IRQ line is disabled\n", mirq); + return; + } - if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1 << (0x1E + mirq)))) - { - /* IRQ already held, do nothing. */ - pci_mirq_log("pci_set_mirq(%02X): MIRQ is already holding the IRQ\n", mirq); - return; - } - else - { - pci_mirq_log("pci_set_mirq(%02X): MIRQ not yet holding the IRQ\n", mirq); - } + irq_line = pci_mirqs[mirq].irq_line; + pci_log("pci_set_mirq(%02X): Using IRQ %i\n", mirq, irq_line); - level = pci_irq_is_level(irq_line); + if (level && (pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) { + /* IRQ already held, do nothing. */ + pci_log("pci_set_mirq(%02X): MIRQ is already holding the IRQ\n", mirq); + return; + } + pci_log("pci_set_mirq(%02X): MIRQ not yet holding the IRQ\n", mirq); - if (!level || !pci_irq_hold[irq_line]) - { - pci_mirq_log("pci_set_mirq(%02X): Issuing %s-triggered IRQ (%sheld)\n", mirq, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); + if (!level || !pci_irq_hold[irq_line]) { + pci_log("pci_set_mirq(%02X): Issuing %s-triggered IRQ (%sheld)\n", mirq, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); - /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ + /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ + if (level) picintlevel(1 << irq_line); - } - else if (level && pci_irq_hold[irq_line]) - { - pci_mirq_log("pci_set_mirq(%02X): IRQ line already being held\n", mirq); - } - - /* If the IRQ is level-triggered, mark that this MIRQ is holding it. */ - if (level) - { - pci_mirq_log("pci_set_mirq(%02X): Marking that this card is holding the IRQ\n", mirq); - pci_irq_hold[irq_line] |= (1 << (0x1E + mirq)); - } else - { - pci_mirq_log("pci_set_mirq(%02X): Edge-triggered interrupt, not marking\n", mirq); - } + picint(1 << irq_line); + } else if (level && pci_irq_hold[irq_line]) { + pci_log("pci_set_mirq(%02X): IRQ line already being held\n", mirq); + } + + /* If the IRQ is level-triggered, mark that this MIRQ is holding it. */ + if (level) { + pci_log("pci_set_mirq(%02X): Marking that this card is holding the IRQ\n", mirq); + pci_irq_hold[irq_line] |= (1ULL << (0x1E + mirq)); + } + + pci_log("pci_set_mirq(%02X): Edge-triggered interrupt, not marking\n", mirq); } -void pci_set_irq(uint8_t card, uint8_t pci_int) + +void +pci_set_irq(uint8_t card, uint8_t pci_int) { - uint8_t slot = 0; - uint8_t irq_routing = 0; - uint8_t pci_int_index = pci_int - PCI_INTA; - uint8_t irq_line = 0; - uint8_t level = 0; + uint8_t slot = 0; + uint8_t irq_routing = 0; + uint8_t pci_int_index = pci_int - PCI_INTA; + uint8_t irq_line = 0; + uint8_t level = 0; - if (!last_pci_card) - { - pcilog("pci_set_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); - return; - } - else - { - pcilog("pci_set_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); - } + if (! last_pci_card) { + pci_log("pci_set_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); + return; + } + pci_log("pci_set_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); - slot = pci_card_to_slot_mapping[card]; + slot = pci_card_to_slot_mapping[card]; + if (slot == 0xff) { + pci_log("pci_set_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); + return; + } + pci_log("pci_set_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); - if (slot == 0xFF) - { - pcilog("pci_set_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); - return; - } - else - { - pcilog("pci_set_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); - } + if (! pci_cards[slot].irq_routing[pci_int_index]) { + pci_log("pci_set_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); + return; + } - if (!pci_cards[slot].irq_routing[pci_int_index]) - { - pcilog("pci_set_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); - return; - } - else - { - irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; - pcilog("pci_set_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); - } + if (pci_type & PCI_NO_IRQ_STEERING) + irq_line = pci_cards[slot].read(0, 0x3c, pci_cards[slot].priv); + else { + irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; + pci_log("pci_set_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); - if (pci_irqs[irq_routing] > 0x0F) - { - pcilog("pci_set_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); - return; - } - else - { - irq_line = pci_irqs[irq_routing]; - pcilog("pci_set_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - } + irq_line = pci_irqs[irq_routing]; + level = pci_irq_level[irq_routing]; + } - if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1 << card))) - { - /* IRQ already held, do nothing. */ - pcilog("pci_set_irq(%02X, %02X): Card is already holding the IRQ\n", card, pci_int); - return; - } - else - { - pcilog("pci_set_irq(%02X, %02X): Card not yet holding the IRQ\n", card, pci_int); - } + if (irq_line > 0x0f) { + pci_log("pci_set_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); + return; + } else + pci_log("pci_set_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - level = pci_irq_is_level(irq_line); + if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1ULL << card))) { + /* IRQ already held, do nothing. */ + pci_log("pci_set_irq(%02X, %02X): Card is already holding the IRQ\n", card, pci_int); + return; + } + pci_log("pci_set_irq(%02X, %02X): Card not yet holding the IRQ\n", card, pci_int); - if (!level || !pci_irq_hold[irq_line]) - { - pcilog("pci_set_irq(%02X, %02X): Issuing %s-triggered IRQ (%sheld)\n", card, pci_int, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); + if (!level || !pci_irq_hold[irq_line]) { + pci_log("pci_set_irq(%02X, %02X): Issuing %s-triggered IRQ (%sheld)\n", card, pci_int, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); - /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ + /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ + if (level) picintlevel(1 << irq_line); - } - else if (level && pci_irq_hold[irq_line]) - { - pcilog("pci_set_irq(%02X, %02X): IRQ line already being held\n", card, pci_int); - } - - /* If the IRQ is level-triggered, mark that this card is holding it. */ - if (pci_irq_is_level(irq_line)) - { - pcilog("pci_set_irq(%02X, %02X): Marking that this card is holding the IRQ\n", card, pci_int); - pci_irq_hold[irq_line] |= (1 << card); - } else - { - pcilog("pci_set_irq(%02X, %02X): Edge-triggered interrupt, not marking\n", card, pci_int); - } + picint(1 << irq_line); + } else if (level && pci_irq_hold[irq_line]) { + pci_log("pci_set_irq(%02X, %02X): IRQ line already being held\n", card, pci_int); + } + + /* If the IRQ is level-triggered, mark that this card is holding it. */ + if (level) { + pci_log("pci_set_irq(%02X, %02X): Marking that this card is holding the IRQ\n", card, pci_int); + pci_irq_hold[irq_line] |= (1ULL << card); + } else { + pci_log("pci_set_irq(%02X, %02X): Edge-triggered interrupt, not marking\n", card, pci_int); + } } -void pci_clear_mirq(uint8_t mirq) + +void +pci_clear_mirq(uint8_t mirq, int level) { - uint8_t irq_line = 0; - uint8_t level = 0; + uint8_t irq_line = 0; - mirq = 0; + if (mirq > 1) { + pci_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq); + return; + } - if (mirq > 1) - { - pci_mirq_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq); - return; - } - - if (!pci_mirqs[mirq].enabled) - { - pci_mirq_log("pci_clear_mirq(%02X): MIRQ0 disabled\n", mirq); - return; - } - - if (pci_mirqs[mirq].irq_line > 0x0F) - { - pci_mirq_log("pci_clear_mirq(%02X): IRQ line is disabled\n", mirq); - return; - } - else - { - irq_line = pci_mirqs[mirq].irq_line; - pci_mirq_log("pci_clear_mirq(%02X): Using IRQ %i\n", mirq, irq_line); - } - - if (pci_irq_is_level(irq_line) && !(pci_irq_hold[irq_line] & (1 << (0x1E + mirq)))) - { - /* IRQ not held, do nothing. */ - pci_mirq_log("pci_clear_mirq(%02X): MIRQ is not holding the IRQ\n", mirq); - return; - } - - level = pci_irq_is_level(irq_line); - - if (level) - { - pci_mirq_log("pci_clear_mirq(%02X): Releasing this MIRQ's hold on the IRQ\n", mirq); - pci_irq_hold[irq_line] &= ~(1 << (0x1E + mirq)); - - if (!pci_irq_hold[irq_line]) - { - pci_mirq_log("pci_clear_mirq(%02X): IRQ no longer held by any card, clearing it\n", mirq); - picintc(1 << irq_line); - } - else - { - pci_mirq_log("pci_clear_mirq(%02X): IRQ is still being held\n", mirq); - } - } - else - { - pci_mirq_log("pci_clear_mirq(%02X): Clearing edge-triggered interrupt\n", mirq); - picintc(1 << irq_line); + if (! pci_mirqs[mirq].enabled) { + pci_log("pci_clear_mirq(%02X): MIRQ0 disabled\n", mirq); + return; + } + + if (pci_mirqs[mirq].irq_line > 0x0f) { + pci_log("pci_clear_mirq(%02X): IRQ line is disabled\n", mirq); + return; + } + + irq_line = pci_mirqs[mirq].irq_line; + pci_log("pci_clear_mirq(%02X): Using IRQ %i\n", mirq, irq_line); + + if (level && !(pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) { + /* IRQ not held, do nothing. */ + pci_log("pci_clear_mirq(%02X): MIRQ is not holding the IRQ\n", mirq); + return; + } + + if (level) { + pci_log("pci_clear_mirq(%02X): Releasing this MIRQ's hold on the IRQ\n", mirq); + pci_irq_hold[irq_line] &= ~(1 << (0x1E + mirq)); + + if (! pci_irq_hold[irq_line]) { + pci_log("pci_clear_mirq(%02X): IRQ no longer held by any card, clearing it\n", mirq); + picintc(1 << irq_line); + } else { + pci_log("pci_clear_mirq(%02X): IRQ is still being held\n", mirq); } + } else { + pci_log("pci_clear_mirq(%02X): Clearing edge-triggered interrupt\n", mirq); + picintc(1 << irq_line); + } } -void pci_clear_irq(uint8_t card, uint8_t pci_int) + +void +pci_clear_irq(uint8_t card, uint8_t pci_int) { - uint8_t slot = 0; - uint8_t irq_routing = 0; - uint8_t pci_int_index = pci_int - PCI_INTA; - uint8_t irq_line = 0; - uint8_t level = 0; + uint8_t slot = 0; + uint8_t irq_routing = 0; + uint8_t pci_int_index = pci_int - PCI_INTA; + uint8_t irq_line = 0; + uint8_t level = 0; - if (!last_pci_card) - { - pcilog("pci_clear_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); - return; - } - else - { - pcilog("pci_clear_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); - } + if (! last_pci_card) { + pci_log("pci_clear_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); + return; + } + pci_log("pci_clear_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); - slot = pci_card_to_slot_mapping[card]; + slot = pci_card_to_slot_mapping[card]; + if (slot == 0xff) { + pci_log("pci_clear_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); + return; + } + pci_log("pci_clear_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); - if (slot == 0xFF) - { - pcilog("pci_clear_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); - return; - } - else - { - pcilog("pci_clear_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); - } + if (! pci_cards[slot].irq_routing[pci_int_index]) { + pci_log("pci_clear_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); + return; + } - if (!pci_cards[slot].irq_routing[pci_int_index]) - { - pcilog("pci_clear_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); - return; - } - else - { - irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; - pcilog("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); - } + if (pci_type & PCI_NO_IRQ_STEERING) + irq_line = pci_cards[slot].read(0, 0x3c, pci_cards[slot].priv); + else { + irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; + pci_log("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); - if (pci_irqs[irq_routing] > 0x0F) - { - pcilog("pci_clear_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); - return; - } - else - { - irq_line = pci_irqs[irq_routing]; - pcilog("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - } + irq_line = pci_irqs[irq_routing]; + level = pci_irq_level[irq_routing]; + } - if (pci_irq_is_level(irq_line) && !(pci_irq_hold[irq_line] & (1 << card))) - { - /* IRQ not held, do nothing. */ - pcilog("pci_clear_irq(%02X, %02X): Card is not holding the IRQ\n", card, pci_int); - return; - } + if (irq_line > 0x0f) { + pci_log("pci_clear_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); + return; + } - level = pci_irq_is_level(irq_line); + pci_log("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - if (level) - { - pcilog("pci_clear_irq(%02X, %02X): Releasing this card's hold on the IRQ\n", card, pci_int); - pci_irq_hold[irq_line] &= ~(1 << card); + if (level && !(pci_irq_hold[irq_line] & (1ULL << card))) { + /* IRQ not held, do nothing. */ + pci_log("pci_clear_irq(%02X, %02X): Card is not holding the IRQ\n", card, pci_int); + return; + } - if (!pci_irq_hold[irq_line]) - { - pcilog("pci_clear_irq(%02X, %02X): IRQ no longer held by any card, clearing it\n", card, pci_int); - picintc(1 << irq_line); - } - else - { - pcilog("pci_clear_irq(%02X, %02X): IRQ is still being held\n", card, pci_int); - } - } - else - { - pcilog("pci_clear_irq(%02X, %02X): Clearing edge-triggered interrupt\n", card, pci_int); - picintc(1 << irq_line); + if (level) { + pci_log("pci_clear_irq(%02X, %02X): Releasing this card's hold on the IRQ\n", card, pci_int); + pci_irq_hold[irq_line] &= ~(1 << card); + + if (! pci_irq_hold[irq_line]) { + pci_log("pci_clear_irq(%02X, %02X): IRQ no longer held by any card, clearing it\n", card, pci_int); + picintc(1 << irq_line); + } else { + pci_log("pci_clear_irq(%02X, %02X): IRQ is still being held\n", card, pci_int); } + } else { + pci_log("pci_clear_irq(%02X, %02X): Clearing edge-triggered interrupt\n", card, pci_int); + picintc(1 << irq_line); + } } -void pci_reset(void) + +void +pci_elcr_set_enabled(int enabled) { - int i = 0; + elcr_enabled = enabled; +} - for (i = 0; i < 16; i++) - { - if (pci_irq_hold[i]) - { - pci_irq_hold[i] = 0; - picintc(1 << i); - } +void +pci_reset(void) +{ + int i; + + for (i = 0; i < 16; i++) { + if (pci_irq_hold[i]) { + pci_irq_hold[i] = 0; + + picintc(1 << i); } + } - elcr_reset(); + elcr_reset(); } -static void pci_slots_clear(void) + +static void +pci_slots_clear(void) { - uint8_t i = 0; - uint8_t j = 0; + uint8_t i, j; - last_pci_card = 0; + last_pci_card = 0; - for (i = 0; i < 32; i++) - { - pci_cards[i].id = 0xFF; - pci_cards[i].type = 0xFF; + for (i = 0; i < 32; i++) { + pci_cards[i].id = 0xFF; + pci_cards[i].type = 0xFF; - for (j = 0; j < 4; j++) - { - pci_cards[i].irq_routing[j] = 0; - } + for (j = 0; j < 4; j++) + pci_cards[i].irq_routing[j] = 0; - pci_cards[i].read = NULL; - pci_cards[i].write = NULL; - pci_cards[i].priv = NULL; + pci_cards[i].read = NULL; + pci_cards[i].write = NULL; + pci_cards[i].priv = NULL; - pci_card_to_slot_mapping[i] = 0xFF; - } + pci_card_to_slot_mapping[i] = 0xFF; + } } -static uint8_t trc_read(uint16_t port, void *priv) + +static uint8_t +trc_read(uint16_t port, void *priv) { - return trc_reg & 0xfb; + return trc_reg & 0xfb; } -static void trc_reset(uint8_t val) + +static void +trc_reset(uint8_t val) { - if (val & 2) - { - device_reset_all_pci(); + if (val & 2) { + device_reset_all_pci(); - port_92_reset(); + cpu_alt_reset = 0; - pci_reset(); - } - resetx86(); -} + mem_a20_alt = 0; + mem_a20_recalc(); -static void trc_write(uint16_t port, uint8_t val, void *priv) -{ - /* pcilog("TRC Write: %02X\n", val); */ - if (!(trc_reg & 4) && (val & 4)) - { - trc_reset(val); - } - trc_reg = val & 0xfd; -} - -void trc_init(void) -{ - trc_reg = 0; - - io_sethandler(0x0cf9, 0x0001, trc_read, NULL, NULL, trc_write, NULL, NULL, NULL); -} - -void pci_init(int type) -{ - int c; - - PCI = 1; - - pci_slots_clear(); + flushmmucache(); pci_reset(); + keyboard_at_reset(); + } - trc_init(); - - io_sethandler(0x04d0, 0x0002, elcr_read, NULL, NULL, elcr_write, NULL, NULL, NULL); - - if (type == PCI_CONFIG_TYPE_1) - { - io_sethandler(0x0cf8, 0x0001, NULL, NULL, pci_cf8_read, NULL, NULL, pci_cf8_write, NULL); - io_sethandler(0x0cfc, 0x0004, pci_read, NULL, NULL, pci_write, NULL, NULL, NULL); - } - else - { - io_sethandler(0x0cf8, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); - io_sethandler(0x0cfa, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); - } - - for (c = 0; c < 4; c++) - { - pci_irqs[c] = PCI_IRQ_DISABLED; - } - - for (c = 0; c < 2; c++) - { - pci_mirqs[c].enabled = 0; - pci_mirqs[c].irq_line = PCI_IRQ_DISABLED; - } + resetx86(); } -void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd) + +static void +trc_write(uint16_t port, uint8_t val, void *priv) { - pci_cards[last_pci_card].id = card; - pci_cards[last_pci_card].type = type; - pci_cards[last_pci_card].irq_routing[0] = inta; - pci_cards[last_pci_card].irq_routing[1] = intb; - pci_cards[last_pci_card].irq_routing[2] = intc; - pci_cards[last_pci_card].irq_routing[3] = intd; - pci_cards[last_pci_card].read = NULL; - pci_cards[last_pci_card].write = NULL; - pci_cards[last_pci_card].priv = NULL; - pci_card_to_slot_mapping[card] = last_pci_card; - pcilog("pci_register_slot(): pci_cards[%i].id = %02X\n", last_pci_card, card); - last_pci_card++; + pci_log("TRC Write: %02X\n", val); + + if (!(trc_reg & 4) && (val & 4)) + trc_reset(val); + + trc_reg = val & 0xfd; + + if (val & 2) + trc_reg &= 0xfb; } -uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) + +void +trc_init(void) { - uint8_t i = 0; + trc_reg = 0; - if (add_type < PCI_ADD_NORMAL) - { - pcilog("pci_add_card(): Adding PCI CARD at specific slot %02X [SPECIFIC]\n", add_type); - } + io_sethandler(0x0cf9, 0x0001, + trc_read, NULL, NULL, trc_write, NULL, NULL, NULL); +} - if (!PCI) - { - pcilog("pci_add_card(): Adding PCI CARD failed (non-PCI machine) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); - return 0xFF; - } - if (!last_pci_card) - { - pcilog("pci_add_card(): Adding PCI CARD failed (no PCI slots) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); - return 0xFF; - } +void +pci_init(int type) +{ + int c; - for (i = 0; i < last_pci_card; i++) - { - if (!pci_cards[i].read && !pci_cards[i].write) - { - if (((pci_cards[i].type == PCI_CARD_NORMAL) && (add_type >= PCI_ADD_NORMAL)) || - ((pci_cards[i].type == PCI_CARD_ONBOARD) && (add_type == PCI_ADD_VIDEO)) || - ((pci_cards[i].id == add_type) && (add_type < PCI_ADD_NORMAL))) - { - pci_cards[i].read = read; - pci_cards[i].write = write; - pci_cards[i].priv = priv; - pcilog("pci_add_card(): Adding PCI CARD to pci_cards[%i] (slot %02X) [%s]\n", i, pci_cards[i].id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); - return pci_cards[i].id; - } + PCI = 1; + + pci_slots_clear(); + + pci_reset(); + + trc_init(); + + pci_type = type; + + if (!(type & PCI_NO_IRQ_STEERING)) { + io_sethandler(0x04d0, 0x0002, + elcr_read,NULL,NULL, elcr_write,NULL,NULL, NULL); + } + + if ((type & PCI_CONFIG_TYPE_MASK) == PCI_CONFIG_TYPE_1) { + io_sethandler(0x0cf8, 1, + NULL,NULL,pci_cf8_read, NULL,NULL,pci_cf8_write, NULL); + io_sethandler(0x0cfc, 4, + pci_read,NULL,NULL, pci_write,NULL,NULL, NULL); + } else { + io_sethandler(0x0cf8, 1, + pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); + io_sethandler(0x0cfa, 1, + pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); + } + + for (c = 0; c < 4; c++) { + pci_irqs[c] = PCI_IRQ_DISABLED; + pci_irq_level[c] = (type & PCI_NO_IRQ_STEERING) ? 0 : 1; + } + + for (c = 0; c < 3; c++) { + pci_mirqs[c].enabled = 0; + pci_mirqs[c].irq_line = PCI_IRQ_DISABLED; + } + + elcr_enabled = 1; +} + + +void +pci_register_slot(int card, int type, int inta, int intb, int intc, int intd) +{ + pci_card_t *dev = &pci_cards[last_pci_card]; + + dev->id = card; + dev->type = type; + dev->irq_routing[0] = inta; + dev->irq_routing[1] = intb; + dev->irq_routing[2] = intc; + dev->irq_routing[3] = intd; + dev->read = NULL; + dev->write = NULL; + dev->priv = NULL; + pci_card_to_slot_mapping[card] = last_pci_card; + + pci_log("pci_register_slot(): pci_cards[%i].id = %02X\n", last_pci_card, card); + + last_pci_card++; +} + + +uint8_t +pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) +{ + pci_card_t *dev; + uint8_t i; + + if (add_type < PCI_ADD_NORMAL) + pci_log("pci_add_card(): Adding PCI CARD at specific slot %02X [SPECIFIC]\n", add_type); + + if (! PCI) { + pci_log("pci_add_card(): Adding PCI CARD failed (non-PCI machine) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : "SPECIFIC"))); + return 0xff; + } + + if (! last_pci_card) { + pci_log("pci_add_card(): Adding PCI CARD failed (no PCI slots) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : "SPECIFIC"))); + return 0xff; + } + + for (i = 0; i < last_pci_card; i++) { + dev = &pci_cards[i]; + + if (!dev->read && !dev->write) { + if (((dev->type == PCI_CARD_NORMAL) && (add_type >= PCI_ADD_NORMAL)) || + ((dev->type == PCI_CARD_ONBOARD) && (add_type == PCI_ADD_VIDEO)) || + ((dev->type == PCI_CARD_SCSI) && (add_type == PCI_ADD_SCSI)) || + ((dev->id == add_type) && (add_type < PCI_ADD_NORMAL))) { + dev->read = read; + dev->write = write; + dev->priv = priv; + pci_log("pci_add_card(): Adding PCI CARD to pci_cards[%i] (slot %02X) [%s]\n", i, dev->id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : "SPECIFIC"))); + return dev->id; } } + } - pcilog("pci_add_card(): Adding PCI CARD failed (unable to find a suitable PCI slot) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); - return 0xFF; + pci_log("pci_add_card(): Adding PCI CARD failed (unable to find a suitable PCI slot) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : "SPECIFIC"))); + + return 0xff; } diff --git a/src/pci.h b/src/pci.h index 8f6d0e619..18a93d9fb 100644 --- a/src/pci.h +++ b/src/pci.h @@ -1,31 +1,39 @@ -void pci_set_irq_routing(int pci_int, int irq); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the PCI handler module. + * + * Version: @(#)pci.h 1.0.2 2020/01/11 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * Sarah Walker, + * + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2008-2020 Sarah Walker. + */ +#ifndef EMU_PCI_H +# define EMU_PCI_H -void pci_enable_mirq(int mirq); -void pci_set_mirq_routing(int mirq, int irq); - -uint8_t pci_use_mirq(uint8_t mirq); - -int pci_irq_is_level(int irq); - -void pci_set_mirq(uint8_t mirq); -void pci_set_irq(uint8_t card, uint8_t pci_int); -void pci_clear_mirq(uint8_t mirq); -void pci_clear_irq(uint8_t card, uint8_t pci_int); - -void pci_reset(void); -void pci_init(int type); -void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd); -void pci_close(void); -uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); #define PCI_REG_COMMAND 0x04 #define PCI_COMMAND_IO 0x01 #define PCI_COMMAND_MEM 0x02 +#define PCI_NO_IRQ_STEERING 0x8000 + #define PCI_CONFIG_TYPE_1 1 #define PCI_CONFIG_TYPE_2 2 +#define PCI_CONFIG_TYPE_MASK 0x7fff + #define PCI_INTA 1 #define PCI_INTB 2 #define PCI_INTC 3 @@ -33,25 +41,56 @@ uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void #define PCI_MIRQ0 0 #define PCI_MIRQ1 1 +#define PCI_MIRQ2 2 #define PCI_IRQ_DISABLED -1 -enum -{ - PCI_CARD_NORMAL = 0, - PCI_CARD_ONBOARD, - PCI_CARD_SPECIAL +enum { + PCI_CARD_NORMAL = 0, + PCI_CARD_ONBOARD, + PCI_CARD_SCSI, + PCI_CARD_SPECIAL }; #define PCI_ADD_NORMAL 0x80 #define PCI_ADD_VIDEO 0x81 - -extern int pci_burst_time, pci_nonburst_time; +#define PCI_ADD_SCSI 0x82 typedef union { uint32_t addr; uint8_t addr_regs[4]; } bar_t; + +extern int pci_burst_time, + pci_nonburst_time; + + +extern void pci_set_irq_routing(int pci_int, int irq); +extern void pci_set_irq_level(int pci_int, int level); + +extern void pci_enable_mirq(int mirq); +extern void pci_set_mirq_routing(int mirq, int irq); + +extern uint8_t pci_use_mirq(uint8_t mirq); + +extern int pci_irq_is_level(int irq); + +extern void pci_set_mirq(uint8_t mirq, int level); +extern void pci_set_irq(uint8_t card, uint8_t pci_int); +extern void pci_clear_mirq(uint8_t mirq, int level); +extern void pci_clear_irq(uint8_t card, uint8_t pci_int); + +extern void pci_reset(void); +extern void pci_init(int type); +extern void pci_register_slot(int card, int type, + int inta, int intb, int intc, int intd); +extern void pci_close(void); +extern uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); + extern void trc_init(void); +extern void pci_elcr_set_enabled(int enabled); + + +#endif /*EMU_PCI_H*/ diff --git a/src/pic.c b/src/pic.c index fb107da8b..60297734c 100644 --- a/src/pic.c +++ b/src/pic.c @@ -8,7 +8,7 @@ * * Implementation of the Intel PIC chip emulation. * - * Version: @(#)pic.c 1.0.0 2018/04/29 + * Version: @(#)pic.c 1.0.5 2019/09/20 * * Author: Miran Grca, * @@ -26,6 +26,7 @@ #include "io.h" #include "pci.h" #include "pic.h" +#include "timer.h" #include "pit.h" @@ -39,22 +40,22 @@ uint16_t pic_current; #ifdef ENABLE_PIC_LOG int pic_do_log = ENABLE_PIC_LOG; -#endif static void -pic_log(const char *format, ...) +pic_log(const char *fmt, ...) { -#ifdef ENABLE_PIC_LOG va_list ap; if (pic_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define pic_log(fmt, ...) +#endif void @@ -62,7 +63,7 @@ pic_updatepending() { uint16_t temp_pending = 0; if (AT) { - if ((pic2.pend&~pic2.mask)&~pic2.mask2) + if ((pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; else pic.pend &= ~pic.icw3; @@ -125,6 +126,7 @@ picint_is_level(uint16_t irq) } +/* Should this really EOI *ALL* IRQ's at once? */ static void pic_autoeoi() { @@ -136,15 +138,10 @@ pic_autoeoi() pic_update_mask(&pic.mask2, pic.ins); if (AT) { - if (((1 << c) == pic.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + if (((1 << c) == pic.icw3) && (pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; } - if ((pic_current & (1 << c)) && picint_is_level(c)) { - if (((1 << c) != pic.icw3) || !AT) - pic.pend |= 1 << c; - } - pic_updatepending(); return; } @@ -156,7 +153,11 @@ void pic_write(uint16_t addr, uint8_t val, void *priv) { int c; + + addr &= ~0x06; + if (addr&1) { + pic_log("%04X:%04X: write: %02X\n", CS, cpu_state.pc, val); switch (pic.icw) { case 0: /*OCW1*/ pic.mask=val; @@ -164,27 +165,36 @@ pic_write(uint16_t addr, uint8_t val, void *priv) break; case 1: /*ICW2*/ pic.vector=val&0xF8; + pic_log("ICW%i ->", pic.icw + 1); if (pic.icw1 & 2) pic.icw=3; else pic.icw=2; + pic_log("ICW%i\n", pic.icw + 1); break; case 2: /*ICW3*/ pic.icw3 = val; pic_log("PIC1 ICW3 now %02X\n", val); + pic_log("ICW%i ->", pic.icw + 1); if (pic.icw1 & 1) pic.icw=3; else pic.icw=0; + pic_log("ICW%i\n", pic.icw + 1); break; case 3: /*ICW4*/ + pic_log("ICW%i ->", pic.icw + 1); pic.icw4 = val; pic.icw=0; + pic_log("ICW%i\n", pic.icw + 1); break; } } else { if (val & 16) { /*ICW1*/ pic.mask = 0; - pic.mask2=0; - pic.icw=1; - pic.icw1=val; + pic.mask2 = 0; + pic_log("ICW%i ->", pic.icw + 1); + pic.icw = 1; + pic.icw1 = val; + pic_log("ICW%i\n", pic.icw + 1); pic.ins = 0; + pic.pend = 0; /* Pending IRQ's are cleared. */ pic_updatepending(); } else if (!(val & 8)) { /*OCW2*/ @@ -196,11 +206,6 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic.pend |= pic.icw3; } - if ((pic_current & (1 << (val & 7))) && picint_is_level(val & 7)) { - if ((((1 << (val & 7)) != pic.icw3) || !AT)) - pic.pend |= 1 << (val & 7); - } - pic_updatepending(); } else { for (c = 0; c < 8; c++) { @@ -209,17 +214,12 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic_update_mask(&pic.mask2, pic.ins); if (AT) { - if (((1 << c) == pic.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + if (((1 << c) == pic.icw3) && (pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; } - if ((pic_current & (1 << c)) && picint_is_level(c)) { - if ((((1 << c) != pic.icw3) || !AT)) - pic.pend |= 1 << c; - } - - if (c==1 && keywaiting) - intclear&=~1; + if ((c == 1) && keywaiting) + intclear &= ~1; pic_updatepending(); return; } @@ -236,13 +236,19 @@ pic_write(uint16_t addr, uint8_t val, void *priv) uint8_t pic_read(uint16_t addr, void *priv) { + addr &= ~0x06; + if (addr & 1) { pic_log("Read PIC mask %02X\n", pic.mask); + pic_log("%04X:%04X: Read PIC mask %02X\n", CS, cpu_state.pc, pic.mask); return pic.mask; } if (pic.read) { pic_log("Read PIC ins %02X\n", pic.ins); - return pic.ins | (pic2.ins ? 4 : 0); + if (AT) + return pic.ins | (pic2.ins ? 4 : 0); + else + return pic.ins; } return pic.pend; } @@ -255,6 +261,13 @@ pic_init() } +void +pic_init_pcjr() +{ + io_sethandler(0x0020, 0x0008, pic_read, NULL, NULL, pic_write, NULL, NULL, NULL); +} + + static void pic2_autoeoi() { @@ -265,11 +278,6 @@ pic2_autoeoi() pic2.ins &= ~(1 << c); pic_update_mask(&pic2.mask2, pic2.ins); - if (pic_current & (0x100 << c) && picint_is_level(c + 8)) { - pic2.pend |= (1 << c); - pic.pend |= (1 << pic2.icw3); - } - pic_updatepending(); return; } @@ -307,33 +315,24 @@ pic2_write(uint16_t addr, uint8_t val, void *priv) } else { if (val & 16) { /*ICW1*/ pic2.mask = 0; - pic2.mask2=0; - pic2.icw=1; + pic2.mask2 = 0; + pic2.icw = 1; pic2.icw1 = val; pic2.ins = 0; + pic2.pend = 0; /* Pending IRQ's are cleared. */ + pic.pend &= ~4; pic_updatepending(); } else if (!(val & 8)) { /*OCW2*/ if ((val & 0xE0) == 0x60) { pic2.ins &= ~(1 << (val & 7)); pic_update_mask(&pic2.mask2, pic2.ins); - if (pic_current & (0x100 << (val & 7)) && picint_is_level((val & 7) + 8)) { - pic2.pend |= (1 << (val & 7)); - pic.pend |= (1 << pic2.icw3); - } - pic_updatepending(); } else { for (c = 0; c < 8; c++) { if (pic2.ins&(1<pend & ~target_pic->mask; + int ret = -1; int pic_int = c & 7; int pic_int_num = 1 << pic_int; - if (pending & pic_int_num) { - target_pic->pend &= ~pic_int_num; + int in_service = 0; + + in_service = (target_pic->ins & (pic_int_num - 1)); /* Is anything of higher priority already in service? */ + in_service |= (target_pic->ins & pic_int_num); /* Is the current IRQ already in service? */ + if (AT) { + /* AT-specific stuff. */ + if (c >= 8) + in_service |= (pic.ins & 0x03); /* IRQ 8 to 15, are IRQ's with higher priorities than the + cascade IRQ already in service? */ + /* For IRQ 0 to 7, the cascade IRQ's in service bit indicates that one or + more IRQ's between 8 and 15 are already in service. */ + } + + if ((pending & pic_int_num) && !in_service) { + if (!((pic_current & (1 << c)) && picint_is_level(c))) + target_pic->pend &= ~pic_int_num; + else if (!picint_is_level(c)) + target_pic->pend &= ~pic_int_num; target_pic->ins |= pic_int_num; pic_update_mask(&target_pic->mask2, target_pic->ins); - if (c >= 8) { + if (AT && (c >= 8)) { + if (!((target_pic->pend & ~target_pic->mask) & ~target_pic->mask2)) + pic.pend &= ~(1 << pic2.icw3); pic.ins |= (1 << pic2.icw3); /*Cascade IRQ*/ pic_update_mask(&pic.mask2, pic.ins); } @@ -495,35 +513,36 @@ pic_process_interrupt(PIC* target_pic, int c) pic_updatepending(); if (target_pic->icw4 & 0x02) - (c >= 8) ? pic2_autoeoi() : pic_autoeoi(); + (AT && (c >= 8)) ? pic2_autoeoi() : pic_autoeoi(); - if (!c) - pit_set_gate(&pit2, 0, 0); + if (!c && (pit2 != NULL)) + pit_ctr_set_gate(&pit2->counters[0], 0); - return pic_int + target_pic->vector; - } else - return 0xFF; + ret = pic_int + target_pic->vector; + } + + return ret; } -uint8_t +int picinterrupt() { int c, d; - uint8_t ret; + int ret; for (c = 0; c <= 7; c++) { if (AT && ((1 << c) == pic.icw3)) { for (d = 8; d <= 15; d++) { ret = pic_process_interrupt(&pic2, d); - if (ret != 0xFF) return ret; + if (ret != -1) return ret; } } else { ret = pic_process_interrupt(&pic, c); - if (ret != 0xFF) return ret; + if (ret != -1) return ret; } } - return 0xFF; + return -1; } diff --git a/src/pic.h b/src/pic.h index b300c11a9..c164a0aa9 100644 --- a/src/pic.h +++ b/src/pic.h @@ -15,13 +15,14 @@ extern int pic_intpending; extern void pic_init(void); +extern void pic_init_pcjr(void); extern void pic2_init(void); extern void pic_reset(void); extern void picint(uint16_t num); extern void picintlevel(uint16_t num); extern void picintc(uint16_t num); -extern uint8_t picinterrupt(void); +extern int picinterrupt(void); extern void picclear(int num); extern void dumppic(void); diff --git a/src/piix.h b/src/piix.h index 1cfc22c8a..6de1d65b3 100644 --- a/src/piix.h +++ b/src/piix.h @@ -19,8 +19,3 @@ extern const device_t piix_device; extern const device_t piix_pb640_device; extern const device_t piix3_device; - -extern int piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv); -extern int piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv); - -extern void piix_bus_master_set_irq(int channel, void *priv); diff --git a/src/pit.c b/src/pit.c index 3ba096154..3fe4fb1dd 100644 --- a/src/pit.c +++ b/src/pit.c @@ -1,652 +1,982 @@ -/*IBM AT - - Write B0 - Write aa55 - Expects aa55 back*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel 8253/8254 Programmable Interval + * Timer. + * + * Version: @(#)pit.c 1.0.0 2019/12/02 + * + * Author: Miran Grca, + * Copyright 2019 Miran Grca. + */ #include +#include +#include #include #include +#include #include #include +#define HAVE_STDARG_H #include "86box.h" #include "cpu/cpu.h" +#include "device.h" +#include "timer.h" #include "dma.h" #include "io.h" #include "nmi.h" #include "pic.h" +#include "timer.h" #include "pit.h" #include "ppi.h" -#include "device.h" -#include "timer.h" #include "machine/machine.h" #include "sound/sound.h" #include "sound/snd_speaker.h" #include "video/video.h" -/*B0 to 40, two writes to 43, then two reads - value does not change!*/ -/*B4 to 40, two writes to 43, then two reads - value _does_ change!*/ -int64_t displine; +pit_t *pit, *pit2; +double cpuclock, PITCONSTD, + SYSCLK, + isa_timing, bus_timing; -PIT pit, - pit2; -float cpuclock; -float isa_timing, bus_timing; +uint64_t PITCONST, ISACONST, + CGACONST, + MDACONST, HERCCONST, + VGACONST1, VGACONST2, + RTCCONST; -double PITCONST; -float CGACONST; -float MDACONST; -float VGACONST1, - VGACONST2; -float RTCCONST; +int io_delay = 5; -int64_t firsttime=1; -void setrtcconst(float clock) + +int64_t firsttime = 1; + + +#define PIT_PS2 16 +#define PIT_EXT_IO 32 + + +enum { + PIT_8253 = 0, + PIT_8254 +}; + + +#ifdef ENABLE_PIT_LOG +int pit_do_log = ENABLE_PIT_LOG; + + +static void +pit_log(const char *fmt, ...) { - RTCCONST=clock/32768.0; - TIMER_USEC = (int64_t)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); + va_list ap; + + if (pit_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } } +#else +#define pit_log(fmt, ...) +#endif -void setpitclock(float clock) + +static void +ctr_set_out(ctr_t *ctr, int out) { - cpuclock=clock; - PITCONST=clock/(1193181.0 + (2.0 / 3.0)); - CGACONST=(clock/(19687503.0/11.0)); - MDACONST=(clock/2032125.0); - VGACONST1=(clock/25175000.0); - VGACONST2=(clock/28322000.0); - isa_timing = clock/8000000.0; - bus_timing = clock/(double)cpu_busspeed; - video_update_timing(); - - xt_cpu_multi = (int64_t)((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - /* RTCCONST=clock/32768.0; - TIMER_USEC = (int64_t)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); */ - device_speed_changed(); -} + if (ctr == NULL) + return; -void pit_reset(PIT *pit) -{ - void (*old_set_out_funcs[3])(int new_out, int old_out); - PIT_nr old_pit_nr[3]; - - memcpy(old_set_out_funcs, pit->set_out_funcs, 3 * sizeof(void *)); - memcpy(old_pit_nr, pit->pit_nr, 3 * sizeof(PIT_nr)); - memset(pit, 0, sizeof(PIT)); - memcpy(pit->set_out_funcs, old_set_out_funcs, 3 * sizeof(void *)); - memcpy(pit->pit_nr, old_pit_nr, 3 * sizeof(PIT_nr)); - - pit->l[0] = 0xFFFF; pit->c[0] = 0xFFFF*PITCONST; - pit->l[1] = 0xFFFF; pit->c[1] = 0xFFFF*PITCONST; - pit->l[2] = 0xFFFF; pit->c[2] = 0xFFFF*PITCONST; - pit->m[0] = pit->m[1] = pit->m[2] = 0; - pit->ctrls[0] = pit->ctrls[1] = pit->ctrls[2] = 0; - pit->thit[0]=1; - pit->gate[0] = pit->gate[1] = 1; - pit->gate[2] = 0; - pit->using_timer[0] = pit->using_timer[1] = pit->using_timer[2] = 1; -} - -void clearpit() -{ - pit.c[0]=(pit.l[0]<<2); -} - -float pit_timer0_freq() -{ - if (pit.l[0]) - return (1193181.0 + (2.0 / 3.0))/(float)pit.l[0]; - else - return (1193181.0 + (2.0 / 3.0))/(float)0x10000; -} - -static void pit_set_out(PIT *pit, int t, int out) -{ - pit->set_out_funcs[t](out, pit->out[t]); - pit->out[t] = out; -} - -static void pit_load(PIT *pit, int t) -{ - int l = pit->l[t] ? pit->l[t] : 0x10000; - timer_clock(); - pit->newcount[t] = 0; - pit->disabled[t] = 0; - switch (pit->m[t]) - { - case 0: /*Interrupt on terminal count*/ - pit->count[t] = l; - pit->c[t] = (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 0); - pit->thit[t] = 0; - pit->enabled[t] = pit->gate[t]; - break; - case 1: /*Hardware retriggerable one-shot*/ - pit->enabled[t] = 1; - break; - case 2: /*Rate generator*/ - if (pit->initial[t]) - { - pit->count[t] = l - 1; - pit->c[t] = (int64_t)(((((int64_t) l) - 1LL) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 1); - pit->thit[t] = 0; - } - pit->enabled[t] = pit->gate[t]; - break; - case 3: /*Square wave mode*/ - if (pit->initial[t]) - { - pit->count[t] = l; - pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 1); - pit->thit[t] = 0; - } - pit->enabled[t] = pit->gate[t]; - break; - case 4: /*Software triggered stobe*/ - if (!pit->thit[t] && !pit->initial[t]) - pit->newcount[t] = 1; - else - { - pit->count[t] = l; - pit->c[t] = (int64_t)((l << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 0); - pit->thit[t] = 0; - } - pit->enabled[t] = pit->gate[t]; - break; - case 5: /*Hardware triggered stobe*/ - pit->enabled[t] = 1; - break; - } - pit->initial[t] = 0; - pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; - timer_update_outstanding(); -} - -void pit_set_gate_no_timer(PIT *pit, int t, int gate) -{ - int64_t l = pit->l[t] ? pit->l[t] : 0x10000; - - if (pit->disabled[t]) - { - pit->gate[t] = gate; - return; - } - - switch (pit->m[t]) - { - case 0: /*Interrupt on terminal count*/ - case 4: /*Software triggered stobe*/ - pit->enabled[t] = gate; - break; - case 1: /*Hardware retriggerable one-shot*/ - case 5: /*Hardware triggered stobe*/ - if (gate && !pit->gate[t]) - { - pit->count[t] = l; - pit->c[t] = (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 0); - pit->thit[t] = 0; - pit->enabled[t] = 1; - } - break; - case 2: /*Rate generator*/ - if (gate && !pit->gate[t]) - { - pit->count[t] = l - 1; - pit->c[t] = (int64_t)(((((int64_t) l) - 1LL) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 1); - pit->thit[t] = 0; - } - pit->enabled[t] = gate; - break; - case 3: /*Square wave mode*/ - if (gate && !pit->gate[t]) - { - pit->count[t] = l; - pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 1); - pit->thit[t] = 0; - } - pit->enabled[t] = gate; - break; - } - pit->gate[t] = gate; - pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; -} - -void pit_set_gate(PIT *pit, int t, int gate) -{ - if (pit->disabled[t]) - { - pit->gate[t] = gate; - return; - } - - timer_process(); - - pit_set_gate_no_timer(pit, t, gate); - - timer_update_outstanding(); -} - -static void pit_over(PIT *pit, int t) -{ - int64_t l = pit->l[t] ? pit->l[t] : 0x10000; - if (pit->disabled[t]) - { - pit->count[t] += 0xffff; - pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); - return; - } - - switch (pit->m[t]) - { - case 0: /*Interrupt on terminal count*/ - case 1: /*Hardware retriggerable one-shot*/ - if (!pit->thit[t]) - pit_set_out(pit, t, 1); - pit->thit[t] = 1; - pit->count[t] += 0xffff; - pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); - break; - case 2: /*Rate generator*/ - pit->count[t] += l; - pit->c[t] += (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 0); - pit_set_out(pit, t, 1); - break; - case 3: /*Square wave mode*/ - if (pit->out[t]) - { - pit_set_out(pit, t, 0); - pit->count[t] += (l >> 1); - pit->c[t] += (int64_t)(((((int64_t) l) >> 1) << TIMER_SHIFT) * PITCONST); - } - else - { - pit_set_out(pit, t, 1); - pit->count[t] += ((l + 1) >> 1); - pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST); - } - break; - case 4: /*Software triggered strove*/ - if (!pit->thit[t]) - { - pit_set_out(pit, t, 0); - pit_set_out(pit, t, 1); - } - if (pit->newcount[t]) - { - pit->newcount[t] = 0; - pit->count[t] += l; - pit->c[t] += (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); - } - else - { - pit->thit[t] = 1; - pit->count[t] += 0xffff; - pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); - } - break; - case 5: /*Hardware triggered strove*/ - if (!pit->thit[t]) - { - pit_set_out(pit, t, 0); - pit_set_out(pit, t, 1); - } - pit->thit[t] = 1; - pit->count[t] += 0xffff; - pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); - break; - } - pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; -} - -int pit_get_timer_0() -{ - int read = (int)((int64_t)((pit.c[0] + ((1LL << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT); - 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(); - if (pit->using_timer[t] && !(pit->m[t] == 3 && !pit->gate[t])) - { - int read = (int)((int64_t)((pit->c[t] + ((1LL << 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]; -} - -void pit_write(uint16_t addr, uint8_t val, void *p) -{ - PIT *pit = (PIT *)p; - int t; - - switch (addr&3) - { - case 3: /*CTRL*/ - if ((val&0xC0)==0xC0) - { - if (!(val&0x20)) - { - if (val & 2) - pit->rl[0] = pit_read_timer(pit, 0); - if (val & 4) - pit->rl[1] = pit_read_timer(pit, 1); - if (val & 8) - pit->rl[2] = pit_read_timer(pit, 2); - } - if (!(val & 0x10)) - { - if (val & 2) - { - 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) | (pit->out[1] ? 0x80 : 0); - pit->do_read_status[1] = 1; - } - if (val & 8) - { - pit->read_status[2] = (pit->ctrls[2] & 0x3f) | (pit->out[2] ? 0x80 : 0); - pit->do_read_status[2] = 1; - } - } - return; - } - t = val >> 6; - pit->ctrl=val; - if ((val>>7)==3) - { - return; - } - if (!(pit->ctrl&0x30)) - { - pit->rl[t] = pit_read_timer(pit, t); - pit->ctrl |= 0x30; - pit->rereadlatch[t] = 0; - pit->rm[t] = 3; - pit->latched[t] = 1; - } - else - { - pit->ctrls[t] = val; - pit->rm[t]=pit->wm[t]=(pit->ctrl>>4)&3; - pit->m[t]=(val>>1)&7; - if (pit->m[t]>5) - pit->m[t]&=3; - if (!(pit->rm[t])) - { - pit->rm[t]=3; - pit->rl[t] = pit_read_timer(pit, t); - } - pit->rereadlatch[t]=1; - pit->initial[t] = 1; - if (!pit->m[t]) - pit_set_out(pit, t, 0); - else - pit_set_out(pit, t, 1); - pit->disabled[t] = 1; - } - pit->wp=0; - pit->thit[t]=0; - break; - case 0: case 1: case 2: /*Timers*/ - t=addr&3; - switch (pit->wm[t]) - { - case 1: - pit->l[t]=val; - pit_load(pit, t); - break; - case 2: - pit->l[t]=(val<<8); - pit_load(pit, t); - break; - case 0: - pit->l[t]&=0xFF; - pit->l[t]|=(val<<8); - pit_load(pit, t); - pit->wm[t]=3; - break; - case 3: - pit->l[t]&=0xFF00; - pit->l[t]|=val; - pit->wm[t]=0; - break; - } - speakval=(((float)pit->l[2]/(float)pit->l[0])*0x4000)-0x2000; - if (speakval>0x2000) speakval=0x2000; - break; - } -} - -uint8_t pit_read(uint16_t addr, void *p) -{ - PIT *pit = (PIT *)p; - int64_t t; - uint8_t temp = 0xff; - switch (addr&3) - { - case 0: case 1: case 2: /*Timers*/ - t = addr & 3; - if (pit->do_read_status[t]) - { - pit->do_read_status[t] = 0; - temp = pit->read_status[t]; - break; - } - if (pit->rereadlatch[addr & 3] && !pit->latched[addr & 3]) - { - pit->rereadlatch[addr & 3] = 0; - pit->rl[t] = pit_read_timer(pit, t); - } - switch (pit->rm[addr & 3]) - { - case 0: - temp = pit->rl[addr & 3] >> 8; - pit->rm[addr & 3] = 3; - pit->latched[addr & 3] = 0; - pit->rereadlatch[addr & 3] = 1; - break; - case 1: - temp = (pit->rl[addr & 3]) & 0xFF; - pit->latched[addr & 3] = 0; - pit->rereadlatch[addr & 3] = 1; - break; - case 2: - temp = (pit->rl[addr & 3]) >> 8; - pit->latched[addr & 3] = 0; - pit->rereadlatch[addr & 3] = 1; - break; - case 3: - temp = (pit->rl[addr & 3]) & 0xFF; - if (pit->m[addr & 3] & 0x80) - pit->m[addr & 3] &= 7; - else - pit->rm[addr & 3] = 0; - break; - } - break; - case 3: /*Control*/ - temp = pit->ctrl; - break; - } - return temp; -} - -void pit_timer_over(void *p) -{ - PIT_nr *pit_nr = (PIT_nr *)p; - PIT *pit = pit_nr->pit; - int64_t timer = pit_nr->nr; - - pit_over(pit, timer); -} - -void pit_clock(PIT *pit, int t) -{ - if (pit->thit[t] || !pit->enabled[t]) - return; - - if (pit->using_timer[t]) - return; - - pit->count[t] -= (pit->m[t] == 3) ? 2 : 1; - if (!pit->count[t]) - pit_over(pit, t); -} - -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] = (int64_t)((((int64_t) pit->count[t]) << TIMER_SHIFT) * PITCONST); - pit->using_timer[t] = using_timer; - pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; - timer_update_outstanding(); -} - -void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)) -{ - pit->set_out_funcs[t] = func; -} - -void pit_null_timer(int new_out, int old_out) -{ -} - -void pit_irq0_timer(int new_out, int old_out) -{ - if (new_out && !old_out) - picint(1); - if (!new_out) - picintc(1); -} - -void pit_irq0_timer_pcjr(int new_out, int old_out) -{ - if (new_out && !old_out) - { - picint(1); - pit_clock(&pit, 1); - } - if (!new_out) - picintc(1); -} - -void pit_irq0_ps2(int new_out, int old_out) -{ - if (new_out && !old_out) - { - picint(1); - pit_set_gate_no_timer(&pit2, 0, 1); - } - if (!new_out) - picintc(1); - if (!new_out && old_out) - pit_clock(&pit2, 0); -} - -void pit_refresh_timer_xt(int new_out, int old_out) -{ - if (new_out && !old_out) - dma_channel_read(0); -} - -void pit_refresh_timer_at(int new_out, int old_out) -{ - if (new_out && !old_out) - ppi.pb ^= 0x10; -} - -void pit_speaker_timer(int new_out, int old_out) -{ - int64_t l; - - speaker_update(); - - l = pit.l[2] ? pit.l[2] : 0x10000; - if (l < 25) - speakon = 0; - else - speakon = new_out; - ppispeakon = new_out; + if (ctr->out_func != NULL) + ctr->out_func(out, ctr->out); + ctr->out = out; } -void pit_nmi_ps2(int new_out, int old_out) +static void +ctr_load_count(ctr_t *ctr) { - nmi = new_out; - if (nmi) - nmi_auto_clear = 1; + int l = ctr->l ? ctr->l : 0x10000; + + ctr->count = l; + pit_log("ctr->count = %i\n", l); + ctr->null_count = 0; + ctr->newcount = !!(l & 1); } -void pit_init() + +static void +ctr_tick(ctr_t *ctr) { - pit_reset(&pit); - - io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit); - pit.gate[0] = pit.gate[1] = 1; - pit.gate[2] = 0; - pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; - - pit.pit_nr[0].nr = 0; - pit.pit_nr[1].nr = 1; - 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]); - - pit_set_out_func(&pit, 0, pit_irq0_timer); - pit_set_out_func(&pit, 1, pit_null_timer); - pit_set_out_func(&pit, 2, pit_speaker_timer); + switch(ctr->m & 0x07) { + case 0: + /*Interrupt on terminal count*/ + switch (ctr->state) { + case 1: + ctr_load_count(ctr); + ctr->state = 2; + break; + case 2: + if (ctr->gate && (ctr->count >= 1)) { + ctr->count--; + if (ctr->count < 1) { + ctr->state = 3; + ctr_set_out(ctr, 1); + } + } + break; + case 3: + ctr->count = (ctr->count - 1) & 0xffff; + break; + } + break; + case 1: + /*Hardware retriggerable one-shot*/ + switch (ctr->state) { + case 1: + ctr_load_count(ctr); + ctr->state = 2; + ctr_set_out(ctr, 0); + break; + case 2: + if (ctr->count >= 1) { + ctr->count--; + if (ctr->count < 1) { + ctr->state = 3; + ctr_set_out(ctr, 1); + } + } + break; + case 3: + ctr->count = (ctr->count - 1) & 0xffff; + break; + } + break; + case 2: case 6: + /*Rate generator*/ + switch (ctr->state) { + case 1: case 3: + ctr_load_count(ctr); + if (ctr->state == 3) + ctr_set_out(ctr, 1); + ctr->state = 2; + break; + case 2: + if (ctr->gate == 0) + break; + else if (ctr->count >= 2) { + ctr->count--; + if (ctr->count < 2) { + ctr->state = 3; + ctr_set_out(ctr, 0); + } + } + break; + } + break; + case 3: case 7: + /*Square wave mode*/ + switch (ctr->state) { + case 1: + ctr_load_count(ctr); + ctr->state = 2; + break; + case 2: + if (ctr->gate == 0) + break; + else if (ctr->count >= 0) { + ctr->count -= (ctr->newcount ? 1 : 2); + if (ctr->count < 0) { + ctr_load_count(ctr); + ctr->state = 3; + ctr_set_out(ctr, 0); + } else if (ctr->newcount) + ctr->newcount = 0; + } + break; + case 3: + if (ctr->gate == 0) + break; + else if (ctr->count >= 0) { + ctr->count -= (ctr->newcount ? 3 : 2); + if (ctr->count < 0) { + ctr_load_count(ctr); + ctr->state = 2; + ctr_set_out(ctr, 1); + } else if (ctr->newcount) + ctr->newcount = 0; + } + break; + } + break; + case 4: case 5: + /*Software triggered strobe*/ + /*Hardware triggered strobe*/ + if ((ctr->gate != 0) || (ctr->m != 4)) { + switch(ctr->state) { + case 0: + ctr->count--; + break; + case 1: + ctr_load_count(ctr); + ctr->state = 2; + break; + case 2: + if (ctr->count >= 1) { + ctr->count--; + if (ctr->count < 1) { + ctr->state = 3; + ctr_set_out(ctr, 0); + } + } + break; + case 3: + ctr->state = 0; + ctr_set_out(ctr, 1); + break; + } + } + break; + default: + break; + } } -void pit_ps2_init() + +static void +ctr_clock(ctr_t *ctr) { - pit_reset(&pit2); + /* FIXME: Is this even needed? */ + if ((ctr->state == 3) && (ctr->m != 2) && (ctr->m != 3)) + return; - io_sethandler(0x0044, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); - io_sethandler(0x0047, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); + if (ctr->using_timer) + return; - pit2.gate[0] = 0; - pit2.using_timer[0] = 0; - pit2.disabled[0] = 1; - - 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]); - - pit_set_out_func(&pit, 0, pit_irq0_ps2); - pit_set_out_func(&pit2, 0, pit_nmi_ps2); + ctr_tick(ctr); +} + + +static void +ctr_set_state_1(ctr_t *ctr) +{ + switch (ctr->m) { + case 0: case 4: + /*Interrupt on terminal count*/ + ctr->state = 1; + break; + case 2: case 3: + /*Rate generator*/ + /*Square wave mode*/ + if (ctr->state == 0) + ctr->state = 1; + break; + } +} + + +static void +ctr_load(ctr_t *ctr) +{ + if (ctr->l == 1) { + /* Count of 1 is illegal in modes 2 and 3. What happens here was + determined experimentally. */ + if (ctr->m == 2) + ctr->l = 2; + else if (ctr->m == 3) + ctr->l = 0; + } + + if (ctr->using_timer) + ctr->latch = 1; + else + ctr_set_state_1(ctr); + + if (ctr->load_func != NULL) + ctr->load_func(ctr->m, ctr->l ? ctr->l : 0x10000); + + pit_log("Counter loaded, state = %i, gate = %i\n", ctr->state, ctr->gate); +} + + +static void +ctr_latch_status(ctr_t *ctr) +{ + ctr->read_status = (ctr->ctrl & 0x3f) | (ctr->out ? 0x80 : 0) | (ctr->null_count ? 0x40 : 0); + ctr->do_read_status = 1; +} + + +static void +ctr_latch_count(ctr_t *ctr) +{ + int count = (ctr->latch || (ctr->state == 1)) ? ctr->l : ctr->count; + + switch (ctr->rm & 0x03) { + case 0x00: + /* This should never happen. */ + break; + case 0x01: + /* Latch bits 0-7 only. */ + ctr->rl = ((count << 8) & 0xff00) | (count & 0xff); + ctr->latched = 1; + break; + case 0x02: + /* Latch bit 8-15 only. */ + ctr->rl = (count & 0xff00) | ((count >> 8) & 0xff); + ctr->latched = 1; + break; + case 0x03: + /* Latch all 16 bits. */ + ctr->rl = count; + ctr->latched = 2; + break; + } + + pit_log("latched counter = %04X\n", ctr->rl & 0xffff); +} + + +uint16_t +pit_ctr_get_count(ctr_t *ctr) +{ + return (uint16_t) ctr->l; +} + + +void +pit_ctr_set_load_func(ctr_t *ctr, void (*func)(uint8_t new_m, int new_count)) +{ + if (ctr == NULL) + return; + + ctr->load_func = func; +} + + +void +pit_ctr_set_out_func(ctr_t *ctr, void (*func)(int new_out, int old_out)) +{ + if (ctr == NULL) + return; + + ctr->out_func = func; +} + + +void +pit_ctr_set_gate(ctr_t *ctr, int gate) +{ + int old = ctr->gate; + + ctr->gate = gate; + + switch (ctr->m & 0x07) { + case 1: case 2: case 3: case 5: case 6: case 7: + if (!old && gate) { + /* Here we handle the rising edges. */ + switch (ctr->m) { + case 1: + ctr->state = 1; + break; + case 2: case 6: + ctr->state = 3; + break; + case 3: case 5: case 7: + ctr_set_out(ctr, 1); + ctr->state = 1; + break; + } + } else if (old && !gate) { + /* Here we handle the lowering edges. */ + switch (ctr->m) { + case 2: case 3: case 6: case 7: + ctr_set_out(ctr, 1); + break; + } + } + break; + } +} + + +void +pit_ctr_set_using_timer(ctr_t *ctr, int using_timer) +{ + timer_process(); + + ctr->using_timer = using_timer; +} + + +static void +pit_timer_over(void *p) +{ + pit_t *dev = (pit_t *) p; + int i; + ctr_t *ctr; + int old; + + old = dev->clock; + dev->clock ^= 1; + + for (i = 0; i < 3; i++) { + ctr = &dev->counters[i]; + + if (ctr->using_timer && ctr->latch) { + if (old && !dev->clock) { + ctr_set_state_1(ctr); + ctr->latch = 0; + } + } else if (ctr->using_timer && !ctr->latch) { + if (ctr->state == 1) { + if (!old && dev->clock) + ctr->s1_det = 1; /* Rising edge. */ + else if (old && !dev->clock) { + ctr->s1_det++; /* Falling edge. */ + if (ctr->s1_det != 2) + ctr->s1_det = 0; + } + + if (ctr->s1_det == 2) { + ctr->s1_det = 0; + ctr_tick(ctr); + } + } else if (old && !dev->clock) + ctr_tick(ctr); + } + } + + timer_advance_u64(&dev->callback_timer, PITCONST >> 1ULL); +} + + +static void +pit_write(uint16_t addr, uint8_t val, void *priv) +{ + pit_t *dev = (pit_t *)priv; + int t = (addr & 3); + ctr_t *ctr; + + pit_log("[%04X:%08X] pit_write(%04X, %02X, %08X)\n", CS, cpu_state.pc, addr, val, priv); + + switch (addr & 3) { + case 3: /* control */ + t = val >> 6; + + if (t == 3) { + if (!(dev->flags & PIT_8254)) + break; + + /* This is 8254-only. */ + if (!(val & 0x20)) { + if (val & 2) + ctr_latch_count(&dev->counters[0]); + if (val & 4) + ctr_latch_count(&dev->counters[1]); + if (val & 8) + ctr_latch_count(&dev->counters[2]); + pit_log("PIT %i: Initiated readback command\n", t); + } + if (!(val & 0x10)) { + if (val & 2) + ctr_latch_status(&dev->counters[0]); + if (val & 4) + ctr_latch_status(&dev->counters[1]); + if (val & 8) + ctr_latch_status(&dev->counters[2]); + } + } else { + dev->ctrl = val; + ctr = &dev->counters[t]; + + if (!(dev->ctrl & 0x30)) { + ctr_latch_count(ctr); + pit_log("PIT %i: Initiated latched read, %i bytes latched\n", + t, ctr->latched); + } else { + ctr->ctrl = val; + ctr->rm = ctr->wm = (ctr->ctrl >> 4) & 3; + ctr->m = (val >> 1) & 7; + if (ctr->m > 5) + ctr->m &= 3; + ctr->null_count = 1; + ctr_set_out(ctr, !!ctr->m); + ctr->state = 0; + pit_log("PIT %i: M = %i, RM/WM = %i, State = %i, Out = %i\n", t, ctr->m, ctr->rm, ctr->state, ctr->out); + } + } + break; + + case 0: + case 1: + case 2: /* the actual timers */ + ctr = &dev->counters[t]; + + switch (ctr->wm) { + case 0: + /* This should never happen. */ + break; + case 1: + ctr->l = val; + if (ctr->m == 0) + ctr_set_out(ctr, 0); + ctr_load(ctr); + break; + case 2: + ctr->l = (val << 8); + if (ctr->m == 0) + ctr_set_out(ctr, 0); + ctr_load(ctr); + break; + case 3: case 0x83: + if (ctr->wm & 0x80) { + ctr->l = (ctr->l & 0x00ff) | (val << 8); + pit_log("PIT %i: Written high byte %02X, latch now %04X\n", t, val, ctr->l); + ctr_load(ctr); + } else { + ctr->l = (ctr->l & 0xff00) | val; + pit_log("PIT %i: Written low byte %02X, latch now %04X\n", t, val, ctr->l); + if (ctr->m == 0) { + ctr->state = 0; + ctr_set_out(ctr, 0); + } + } + + if (ctr->wm & 0x80) + ctr->wm &= ~0x80; + else + ctr->wm |= 0x80; + break; + } + break; + } +} + + +static uint8_t +pit_read(uint16_t addr, void *priv) +{ + pit_t *dev = (pit_t *)priv; + uint8_t ret = 0xff; + int count, t = (addr & 3); + ctr_t *ctr; + + switch (addr & 3) { + case 3: /* Control. */ + /* This is 8254-only, 8253 returns 0x00. */ + ret = (dev->flags & PIT_8254) ? dev->ctrl : 0x00; + break; + + case 0: + case 1: + case 2: /* The actual timers. */ + ctr = &dev->counters[t]; + + if (ctr->do_read_status) { + ctr->do_read_status = 0; + ret = ctr->read_status; + break; + } + + count = (ctr->state == 1) ? ctr->l : ctr->count; + + if (ctr->latched) { + ret = (ctr->rl) >> ((ctr->rm & 0x80) ? 8 : 0); + + if (ctr->rm & 0x80) + ctr->rm &= ~0x80; + else + ctr->rm |= 0x80; + + ctr->latched--; + } else switch (ctr->rm) { + case 0: case 0x80: + ret = 0x00; + break; + + case 1: + ret = count & 0xff; + break; + + case 2: + ret = count >> 8; + break; + + case 3: case 0x83: + if (ctr->wm & 0x80) + ret = ~(ctr->l & 0xff); + else + ret = count >> ((ctr->rm & 0x80) ? 8 : 0); + + if (ctr->rm & 0x80) + ctr->rm &= ~0x80; + else + ctr->rm |= 0x80; + break; + } + break; + } + + pit_log("[%04X:%08X] pit_read(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret); + + return ret; +} + + +/* FIXME: Should be moved to machine.c (default for most machine). */ +void +pit_irq0_timer(int new_out, int old_out) +{ + if (new_out && !old_out) + picint(1); + + if (!new_out) + picintc(1); +} + + +void +pit_irq0_timer_pcjr(int new_out, int old_out) +{ + if (new_out && !old_out) { + picint(1); + ctr_clock(&pit->counters[1]); + } + + if (!new_out) + picintc(1); +} + + +void +pit_irq0_timer_ps2(int new_out, int old_out) +{ + ctr_t *ctr = &pit2->counters[0]; + + if (new_out && !old_out) { + picint(1); + pit_ctr_set_gate(ctr, 1); + } + + if (!new_out) + picintc(1); + + if (!new_out && old_out) + ctr_clock(ctr); +} + + +void +pit_refresh_timer_xt(int new_out, int old_out) +{ + if (new_out && !old_out) + dma_channel_read(0); +} + + +void +pit_refresh_timer_at(int new_out, int old_out) +{ + if (new_out && !old_out) + ppi.pb ^= 0x10; +} + + +void +pit_speaker_timer(int new_out, int old_out) +{ + int l; + + speaker_update(); + + l = pit->counters[2].l ? pit->counters[2].l : 0x10000; + if (l < 25) + speakon = 0; + else + speakon = new_out; + + ppispeakon = new_out; +} + + +void +pit_nmi_timer_ps2(int new_out, int old_out) +{ + nmi = new_out; + + if (nmi) + nmi_auto_clear = 1; +} + + +static void +ctr_reset(ctr_t *ctr) +{ + ctr->ctrl = 0; + ctr->m = 0; + ctr->gate = 0; + ctr->l = 0xffff; + ctr->using_timer = 1; + ctr->state = 0; + ctr->null_count = 1; + + ctr->latch = 0; + + ctr->s1_det = 0; + ctr->l_det = 0; +} + + +void +pit_reset(pit_t *dev) +{ + int i; + + memset(dev, 0, sizeof(pit_t)); + + dev->clock = 0; + + for (i = 0; i < 3; i++) + ctr_reset(&dev->counters[i]); + + /* Disable speaker gate. */ + dev->counters[2].gate = 0; +} + + +void +pit_handler(int set, uint16_t base, int size, void *priv) +{ + io_handler(set, base, size, pit_read, NULL, NULL, pit_write, NULL, NULL, priv); +} + + +static void +pit_close(void *priv) +{ + pit_t *dev = (pit_t *) priv; + + if (dev == pit) + pit = NULL; + + if (dev == pit2) + pit2 = NULL; + + if (dev != NULL) + free(dev); +} + + +static void * +pit_init(const device_t *info) +{ + pit_t *dev = (pit_t *) malloc(sizeof(pit_t)); + pit_reset(dev); + + if (!(dev->flags & PIT_PS2)) { + timer_add(&dev->callback_timer, pit_timer_over, (void *) dev, 0); + timer_set_delay_u64(&dev->callback_timer, PITCONST >> 1ULL); + } + + dev->flags = info->local; + + if (!(dev->flags & PIT_EXT_IO)) + io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, dev); + + return dev; +} + + +const device_t i8253_device = +{ + "Intel 8253/8253-5 Programmable Interval Timer", + DEVICE_ISA, + PIT_8253, + pit_init, pit_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t i8254_device = +{ + "Intel 8254 Programmable Interval Timer", + DEVICE_ISA, + PIT_8254, + pit_init, pit_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t i8254_ext_io_device = +{ + "Intel 8254 Programmable Interval Timer (External I/O)", + DEVICE_ISA, + PIT_8254 | PIT_EXT_IO, + pit_init, pit_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t i8254_ps2_device = +{ + "Intel 8254 Programmable Interval Timer (PS/2)", + DEVICE_ISA, + PIT_8254 | PIT_PS2 | PIT_EXT_IO, + pit_init, pit_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +pit_t * +pit_common_init(int type, void (*out0)(int new_out, int old_out), void (*out1)(int new_out, int old_out)) +{ + int i; + + switch (type) { + case PIT_8253: + default: + pit = device_add(&i8253_device); + break; + case PIT_8254: + pit = device_add(&i8254_device); + break; + } + + for (i = 0; i < 3; i++) { + pit->counters[i].gate = 1; + pit->counters[i].using_timer = 1; + } + + pit_ctr_set_out_func(&pit->counters[0], out0); + pit_ctr_set_out_func(&pit->counters[1], out1); + pit_ctr_set_out_func(&pit->counters[2], pit_speaker_timer); + pit_ctr_set_load_func(&pit->counters[2], speaker_set_count); + pit->counters[2].gate = 0; + + return pit; +} + + +pit_t * +pit_ps2_init(void) +{ + pit2 = device_add(&i8254_ps2_device); + + pit_handler(1, 0x0044, 0x0001, pit2); + pit_handler(1, 0x0047, 0x0001, pit2); + + pit2->counters[0].gate = 0; + pit2->counters[0].using_timer = pit2->counters[1].using_timer = pit2->counters[2].using_timer = 0; + + pit_ctr_set_out_func(&pit->counters[0], pit_irq0_timer_ps2); + pit_ctr_set_out_func(&pit2->counters[0], pit_nmi_timer_ps2); + + return pit2; +} + + +void +pit_set_clock(int clock) +{ + /* Set default CPU/crystal clock and xt_cpu_multi. */ + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) { + if (clock == 66666666) + cpuclock = 200000000.0 / 3.0; + else if (clock == 33333333) + cpuclock = 100000000.0 / 3.0; + else + cpuclock = (double) clock; + + PITCONSTD = (cpuclock / 1193182.0); + PITCONST = (uint64_t) (PITCONSTD * (double)(1ull << 32)); + CGACONST = (uint64_t) ((cpuclock / (19687503.0/11.0)) * (double)(1ull << 32)); + ISACONST = (uint64_t) ((cpuclock / 8000000.0) * (double)(1ull << 32)); + xt_cpu_multi = 1ULL; + } else { + cpuclock = 14318184.0; + PITCONSTD = 12.0; + PITCONST = (12ULL << 32ULL); + CGACONST = (8ULL << 32ULL); + xt_cpu_multi = 3ULL; + + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed) { + case 7159092: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_flags & CPU_ALTERNATE_XTAL) { + cpuclock = 28636368.0; + xt_cpu_multi = 4ULL; + } else + xt_cpu_multi = 2ULL; + break; + + case 8000000: + cpuclock = 24000000.0; + break; + case 9545456: + cpuclock = 28636368.0; + break; + case 10000000: + cpuclock = 30000000.0; + break; + case 12000000: + cpuclock = 36000000.0; + break; + case 16000000: + cpuclock = 48000000.0; + break; + + default: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_flags & CPU_ALTERNATE_XTAL) { + cpuclock = 28636368.0; + xt_cpu_multi = 6ULL; + } + break; + } + + if (cpuclock == 28636368.0) { + PITCONSTD = 24.0; + PITCONST = (24ULL << 32LL); + CGACONST = (16ULL << 32LL); + } else if (cpuclock != 14318184.0) { + PITCONSTD = (cpuclock / 1193182.0); + PITCONST = (uint64_t) (PITCONSTD * (double)(1ull << 32)); + CGACONST = (uint64_t) (((cpuclock/(19687503.0/11.0)) * (double)(1ull << 32))); + } + + ISACONST = (1ULL << 32ULL); + } + xt_cpu_multi <<= 32ULL; + + /* Delay for empty I/O ports. */ + io_delay = (int) round(((double) machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed) / 1000000.0); + + MDACONST = (uint64_t) (cpuclock / 2032125.0 * (double)(1ull << 32)); + HERCCONST = MDACONST; + VGACONST1 = (uint64_t) (cpuclock / 25175000.0 * (double)(1ull << 32)); + VGACONST2 = (uint64_t) (cpuclock / 28322000.0 * (double)(1ull << 32)); + RTCCONST = (uint64_t) (cpuclock / 32768.0 * (double)(1ull << 32)); + + TIMER_USEC = (uint64_t)((cpuclock / 1000000.0) * (double)(1ull << 32)); + + isa_timing = (cpuclock / (double)8000000.0); + bus_timing = (cpuclock / (double)cpu_busspeed); + + if (cpu_busspeed >= 30000000) + SYSCLK = bus_timing * 4.0; + else + SYSCLK = bus_timing * 3.0; + + video_update_timing(); + + device_speed_changed(); } diff --git a/src/pit.h b/src/pit.h index 00297eb26..e0a4a42ff 100644 --- a/src/pit.h +++ b/src/pit.h @@ -1,74 +1,96 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header of the implementation of the Intel 8253/8254 + * Programmable Interval Timer. + * + * Version: @(#)pit.h 1.0.0 2019/12/02 + * + * Author: Miran Grca, + * Copyright 2019 Miran Grca. + */ #ifndef EMU_PIT_H # define EMU_PIT_H typedef struct { - int64_t nr; - struct PIT *pit; -} PIT_nr; + uint8_t m, ctrl, + read_status, latch, + s1_det, l_det; + + uint16_t rl; + + int rm, wm, gate, out, + newcount, count, using_timer, latched, + state, null_count, do_read_status, pad1; + + uint32_t l; + + void (*load_func)(uint8_t new_m, int new_count); + void (*out_func)(int new_out, int old_out); +} ctr_t; + typedef struct PIT { - uint32_t l[3]; - int64_t c[3]; - uint8_t m[3]; - uint8_t ctrl, - ctrls[3]; - int wp, - rm[3], - wm[3]; - uint16_t rl[3]; - int thit[3]; - int delay[3]; - int rereadlatch[3]; - int gate[3]; - int out[3]; - int64_t running[3]; - int enabled[3]; - int newcount[3]; - int count[3]; - int using_timer[3]; - int initial[3]; - int latched[3]; - int disabled[3]; + int flags, clock; + pc_timer_t callback_timer; - uint8_t read_status[3]; - int do_read_status[3]; + ctr_t counters[3]; - PIT_nr pit_nr[3]; - - void (*set_out_funcs[3])(int new_out, int old_out); -} PIT; + uint8_t ctrl; +} pit_t; -extern PIT pit, - pit2; -extern double PITCONST; -extern float CGACONST, +extern pit_t *pit, + *pit2; + +extern double SYSCLK; + +extern uint64_t PITCONST, ISACONST, + CGACONST, MDACONST, + HERCCONST, VGACONST1, VGACONST2, RTCCONST; -extern void pit_init(void); -extern void pit_ps2_init(void); -extern void pit_reset(PIT *pit); -extern void pit_set_gate(PIT *pit, int channel, int gate); -extern void pit_set_using_timer(PIT *pit, int t, int using_timer); -extern void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)); -extern void pit_clock(PIT *pit, int t); +extern uint16_t pit_ctr_get_count(ctr_t *ctr); +extern void pit_ctr_set_load_func(ctr_t *ctr, void (*func)(uint8_t new_m, int new_count)); +extern void pit_ctr_set_out_func(ctr_t *ctr, void (*func)(int new_out, int old_out)); +extern void pit_ctr_set_gate(ctr_t *ctr, int gate); +extern void pit_ctr_set_using_timer(ctr_t *ctr, int using_timer); -extern void setrtcconst(float clock); +extern pit_t * pit_common_init(int type, void (*out0)(int new_out, int old_out), void (*out1)(int new_out, int old_out)); +extern pit_t * pit_ps2_init(void); +extern void pit_reset(pit_t *dev); -extern void setpitclock(float clock); -extern float pit_timer0_freq(void); - -extern void pit_null_timer(int new_out, int old_out); extern void pit_irq0_timer(int new_out, int old_out); extern void pit_irq0_timer_pcjr(int new_out, int old_out); +extern void pit_irq0_timer_ps2(int new_out, int old_out); + extern void pit_refresh_timer_xt(int new_out, int old_out); extern void pit_refresh_timer_at(int new_out, int old_out); + extern void pit_speaker_timer(int new_out, int old_out); +extern void pit_nmi_timer_ps2(int new_out, int old_out); + +extern void pit_set_clock(int clock); +extern void pit_handler(int set, uint16_t base, int size, void *priv); + + +#ifdef EMU_DEVICE_H +extern const device_t i8253_device; +extern const device_t i8254_device; +extern const device_t i8254_ext_io_device; +extern const device_t i8254_ps2_device; +#endif + #endif /*EMU_PIT_H*/ diff --git a/src/plat.h b/src/plat.h index fc7e5e252..065d50aa0 100644 --- a/src/plat.h +++ b/src/plat.h @@ -8,13 +8,13 @@ * * Define the various platform support functions. * - * Version: @(#)plat.h 1.0.26 2018/02/14 + * Version: @(#)plat.h 1.0.28 2019/03/06 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_PLAT_H # define EMU_PLAT_H @@ -68,10 +68,14 @@ GLOBAL int unscaled_size_x, /* current unscaled size X */ /* System-related functions. */ extern wchar_t *fix_exe_path(wchar_t *str); extern FILE *plat_fopen(wchar_t *path, wchar_t *mode); +extern FILE *plat_fopen64(const wchar_t *path, const wchar_t *mode); extern void plat_remove(wchar_t *path); extern int plat_getcwd(wchar_t *bufp, int max); extern int plat_chdir(wchar_t *path); +extern void plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix); extern void plat_get_exe_name(wchar_t *s, int size); +extern wchar_t *plat_get_basename(const wchar_t *path); +extern void plat_get_dirname(wchar_t *dest, const wchar_t *path); extern wchar_t *plat_get_filename(wchar_t *s); extern wchar_t *plat_get_extension(wchar_t *s); extern void plat_append_filename(wchar_t *dest, wchar_t *s1, wchar_t *s2); @@ -91,6 +95,7 @@ extern int plat_setvid(int api); extern void plat_vidsize(int x, int y); extern void plat_setfullscreen(int on); extern void plat_resize(int x, int y); +extern void plat_vidapi_enable(int enabled); /* Resource management. */ @@ -104,14 +109,7 @@ extern void do_stop(void); /* Platform-specific device support. */ -extern uint8_t host_cdrom_drive_available[26]; -extern uint8_t host_cdrom_drive_available_num; - -#ifdef USE_IOCTL -extern void cdrom_init_host_drives(void); -#endif -extern void cdrom_eject(uint8_t id); -extern void cdrom_reload(uint8_t id); +extern void plat_cdrom_ui_update(uint8_t id, uint8_t reload); extern void zip_eject(uint8_t id); extern void zip_reload(uint8_t id); extern int ioctl_open(uint8_t id, char d); diff --git a/src/plat_dynld.h b/src/plat_dynld.h index 74af2e8f8..72bc75c2f 100644 --- a/src/plat_dynld.h +++ b/src/plat_dynld.h @@ -23,8 +23,16 @@ typedef struct { } dllimp_t; +#ifdef __cplusplus +extern "C" { +#endif + extern void *dynld_module(const char *, dllimp_t *); extern void dynld_close(void *); +#ifdef __cplusplus +} +#endif + #endif /*PLAT_DYNLD_H*/ diff --git a/src/plat_midi.h b/src/plat_midi.h index 1d167c475..933e49ee6 100644 --- a/src/plat_midi.h +++ b/src/plat_midi.h @@ -1,8 +1,15 @@ extern void plat_midi_init(void); extern void plat_midi_close(void); -extern void plat_midi_play_msg(uint8_t* val); -extern void plat_midi_play_sysex(uint8_t* data, unsigned int len); +extern void plat_midi_play_msg(uint8_t *msg); +extern void plat_midi_play_sysex(uint8_t *sysex, unsigned int len); extern int plat_midi_write(uint8_t val); -extern int plat_midi_get_num_devs(); + +extern int plat_midi_get_num_devs(void); extern void plat_midi_get_dev_name(int num, char *s); + +extern void plat_midi_input_init(void); +extern void plat_midi_input_close(void); + +extern int plat_midi_in_get_num_devs(void); +extern void plat_midi_in_get_dev_name(int num, char *s); diff --git a/src/port_92.c b/src/port_92.c new file mode 100644 index 000000000..1c5f1b2bf --- /dev/null +++ b/src/port_92.c @@ -0,0 +1,252 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Port 92 used by PS/2 machines and 386+ + * clones. + * + * Version: @(#)port_92.c 1.0.0 2019/05/14 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "device.h" +#ifdef USE_NEW_DYNAREC +#include "cpu_new/cpu.h" +#else +#include "cpu/cpu.h" +#endif +#include "timer.h" +#include "io.h" +#include "keyboard.h" +#include "mem.h" +#include "pit.h" +#include "port_92.h" + + +#define PORT_92_INV 1 +#define PORT_92_WORD 2 +#define PORT_92_PCI 4 +#define PORT_92_RESET 8 +#define PORT_92_A20 16 + + +static uint8_t +port_92_readb(uint16_t port, void *priv) +{ + uint8_t ret = 0x00; + port_92_t *dev = (port_92_t *) priv; + + if (port == 0x92) { + /* Return bit 1 directly from mem_a20_alt, so the + pin can be reset independently of the device. */ + ret = (dev->reg & ~0x03) | (mem_a20_alt & 2) | + (cpu_alt_reset & 1); + + if (dev->flags & PORT_92_INV) + ret |= 0xfc; + else if (dev->flags & PORT_92_PCI) + ret |= 0x24; /* Intel SIO datasheet says bits 2 and 5 are always 1. */ + } else if (dev->flags & PORT_92_INV) + ret = 0xff; + + return ret; +} + + +static uint16_t +port_92_readw(uint16_t port, void *priv) +{ + return port_92_readb(port, priv); +} + + +static void +port_92_pulse(void *priv) +{ + softresetx86(); + cpu_set_edx(); +} + + +static void +port_92_writeb(uint16_t port, uint8_t val, void *priv) +{ + port_92_t *dev = (port_92_t *) priv; + + if (port != 0x92) + return; + + dev->reg = val & 0x03; + + if ((mem_a20_alt ^ val) & 2) { + mem_a20_alt = (val & 2); + mem_a20_recalc(); + } + + if ((~cpu_alt_reset & val) & 1) + timer_set_delay_u64(&dev->pulse_timer, dev->pulse_period); + else if (!(val & 1)) + timer_disable(&dev->pulse_timer); + + cpu_alt_reset = (val & 1); + + if (dev->flags & PORT_92_INV) + dev->reg |= 0xfc; +} + + +static void +port_92_writew(uint16_t port, uint16_t val, void *priv) +{ + port_92_writeb(port, val & 0xff, priv); +} + + +void +port_92_set_period(void *priv, uint64_t pulse_period) +{ + port_92_t *dev = (port_92_t *) priv; + + dev->pulse_period = pulse_period; +} + + +void +port_92_set_features(void *priv, int reset, int a20) +{ + port_92_t *dev = (port_92_t *) priv; + + dev->flags &= ~(PORT_92_RESET | PORT_92_A20); + + if (reset) + dev->flags |= PORT_92_RESET; + + timer_disable(&dev->pulse_timer); + + if (a20) { + dev->flags |= PORT_92_A20; + mem_a20_alt = (dev->reg & 2); + } else + mem_a20_alt = 0; + + mem_a20_recalc(); +} + + +void +port_92_add(void *priv) +{ + port_92_t *dev = (port_92_t *) priv; + + if (dev->flags & PORT_92_WORD) + io_sethandler(0x0092, 2, + port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev); + else + io_sethandler(0x0092, 1, + port_92_readb, NULL, NULL, port_92_writeb, NULL, NULL, dev); +} + + +void +port_92_remove(void *priv) +{ + port_92_t *dev = (port_92_t *) priv; + + if (dev->flags & PORT_92_WORD) + io_removehandler(0x0092, 2, + port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev); + else + io_removehandler(0x0092, 1, + port_92_readb, NULL, NULL, port_92_writeb, NULL, NULL, dev); +} + + +static void +port_92_close(void *priv) +{ + port_92_t *dev = (port_92_t *) priv; + + timer_disable(&dev->pulse_timer); + + free(dev); +} + + +void * +port_92_init(const device_t *info) +{ + port_92_t *dev = (port_92_t *) malloc(sizeof(port_92_t)); + memset(dev, 0, sizeof(port_92_t)); + + dev->flags = info->local & 0xff; + + timer_add(&dev->pulse_timer, port_92_pulse, dev, 0); + + dev->reg = 0; + mem_a20_alt = 0; + mem_a20_recalc(); + + cpu_alt_reset = 0; + + flushmmucache(); + + port_92_add(dev); + + dev->pulse_period = (uint64_t) (4.0 * SYSCLK * (double)(1ULL << 32ULL)); + + dev->flags |= (PORT_92_RESET | PORT_92_A20); + + return dev; +} + + +const device_t port_92_device = { + "Port 92 Register", + 0, + 0, + port_92_init, port_92_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t port_92_inv_device = { + "Port 92 Register (inverted bits 2-7)", + 0, + PORT_92_INV, + port_92_init, port_92_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t port_92_word_device = { + "Port 92 Register (16-bit)", + 0, + PORT_92_WORD, + port_92_init, port_92_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t port_92_pci_device = { + "Port 92 Register (PCI)", + 0, + PORT_92_PCI, + port_92_init, port_92_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/port_92.h b/src/port_92.h new file mode 100644 index 000000000..4b41eb09d --- /dev/null +++ b/src/port_92.h @@ -0,0 +1,47 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header for the implementation of Port 92 used by PS/2 + * machines and 386+ clones. + * + * Version: @(#)port_92.h 1.0.0 2019/05/14 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#ifndef EMU_PORT_92_H +# define EMU_PORT_92_H + + +#ifdef _TIMER_H_ +typedef struct +{ + uint8_t reg, flags; + + pc_timer_t pulse_timer; + + uint64_t pulse_period; +} port_92_t; +#endif + + +extern void port_92_set_period(void *priv, uint64_t pulse_period); +extern void port_92_set_features(void *priv, int reset, int a20); + +extern void port_92_add(void *priv); +extern void port_92_remove(void *priv); + + +extern const device_t port_92_device; +extern const device_t port_92_inv_device; +extern const device_t port_92_word_device; +extern const device_t port_92_pci_device; + + +#endif /*EMU_PORT_92_H*/ diff --git a/src/ppi.c b/src/ppi.c index ef81ee19c..e91b445d2 100644 --- a/src/ppi.c +++ b/src/ppi.c @@ -11,6 +11,7 @@ #include #include #include +#include "timer.h" #include "pit.h" #include "ppi.h" diff --git a/src/printer/png.c b/src/printer/png.c new file mode 100644 index 000000000..752df0080 --- /dev/null +++ b/src/printer/png.c @@ -0,0 +1,264 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Provide centralized access to the PNG image handler. + * + * Version: @(#)png.c 1.0.5 2018/11/19 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + */ +#include +#include +#include +#include +#include +#include +#define PNG_DEBUG 0 +#include +#include "../86box.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../ui.h" +#include "../video/video.h" +#include "png_struct.h" + +#ifdef _WIN32 +# define PATH_PNG_DLL "libpng16-16.dll" +#else +# define PATH_PNG_DLL "libpng16.so" +#endif + + +# define PNGFUNC(x) png_ ## x + + +#ifdef ENABLE_ESCP_LOG +int png_do_log = ENABLE_ESCP_LOG; + + +static void +png_log(const char *fmt, ...) +{ + va_list ap; + + if (escp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define png_log(fmt, ...) +#endif + + +static void +error_handler(png_structp arg, const char *str) +{ + png_log("PNG: stream 0x%08lx error '%s'\n", arg, str); +} + + +static void +warning_handler(png_structp arg, const char *str) +{ + png_log("PNG: stream 0x%08lx warning '%s'\n", arg, str); +} + + +/* Write the given image as an 8-bit GrayScale PNG image file. */ +int +png_write_gray(wchar_t *fn, int inv, uint8_t *pix, int16_t w, int16_t h) +{ + png_structp png = NULL; + png_infop info = NULL; + png_bytep row; + int16_t x, y; + FILE *fp; + + /* Create the image file. */ + fp = plat_fopen(fn, L"wb"); + if (fp == NULL) { + /* Yes, this looks weird. */ + if (fp == NULL) + png_log("PNG: file %ls could not be opened for writing!\n", fn); + else +error: + png_log("PNG: fatal error, bailing out, error = %i\n", errno); + if (png != NULL) + PNGFUNC(destroy_write_struct)(&png, &info); + if (fp != NULL) + (void)fclose(fp); + return(0); + } + + /* Initialize PNG stuff. */ + png = PNGFUNC(create_write_struct)(PNG_LIBPNG_VER_STRING, NULL, + error_handler, warning_handler); + if (png == NULL) { + png_log("PNG: create_write_struct failed!\n"); + goto error; + } + + info = PNGFUNC(create_info_struct)(png); + if (info == NULL) { + png_log("PNG: create_info_struct failed!\n"); + goto error; + } + + + PNGFUNC(init_io)(png, fp); + + PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + PNGFUNC(write_info)(png, info); + + /* Create a buffer for one scanline of pixels. */ + row = (png_bytep)malloc(PNGFUNC(get_rowbytes)(png, info)); + + /* Process all scanlines in the image. */ + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + /* Copy the pixel data. */ + if (inv) + row[x] = 255 - pix[(y * w) + x]; + else + row[x] = pix[(y * w) + x]; + } + + /* Write image to the file. */ + PNGFUNC(write_rows)(png, &row, 1); + } + + /* No longer need the row buffer. */ + free(row); + + PNGFUNC(write_end)(png, NULL); + + PNGFUNC(destroy_write_struct)(&png, &info); + + /* Clean up. */ + (void)fclose(fp); + + return(1); +} + + +/* Write the given BITMAP-format image as an 8-bit RGBA PNG image file. */ +void +png_write_rgb(wchar_t *fn, uint8_t *pix, int16_t w, int16_t h, uint16_t pitch, PALETTE palcol) +{ + png_structp png = NULL; + png_infop info = NULL; + png_bytep* rows; + png_color palette[256]; + FILE *fp; + int i; + + /* Create the image file. */ + fp = plat_fopen(fn, L"wb"); + if (fp == NULL) { + png_log("PNG: File %ls could not be opened for writing!\n", fn); +error: + if (png != NULL) + PNGFUNC(destroy_write_struct)(&png, &info); + if (fp != NULL) + (void)fclose(fp); + return; + } + + /* Initialize PNG stuff. */ + png = PNGFUNC(create_write_struct)(PNG_LIBPNG_VER_STRING, NULL, + error_handler, warning_handler); + if (png == NULL) { + png_log("PNG: create_write_struct failed!\n"); + goto error; + } + + info = PNGFUNC(create_info_struct)(png); + if (info == NULL) { + png_log("PNG: create_info_struct failed!\n"); + goto error; + } + + /* Finalize the initing of png library */ + PNGFUNC(init_io)(png, fp); + PNGFUNC(set_compression_level)(png, 9); + + /* set other zlib parameters */ + PNGFUNC(set_compression_mem_level)(png, 8); + PNGFUNC(set_compression_strategy)(png, PNG_Z_DEFAULT_STRATEGY); + PNGFUNC(set_compression_window_bits)(png, 15); + PNGFUNC(set_compression_method)(png, 8); + PNGFUNC(set_compression_buffer_size)(png, 8192); + + PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_PALETTE, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + for (i = 0; i < 256; i++) { + palette[i].red = palcol[i].r; + palette[i].green = palcol[i].g; + palette[i].blue = palcol[i].b; + } + + PNGFUNC(set_PLTE)(png, info, palette, 256); + + /* Create a buffer for scanlines of pixels. */ + rows = (png_bytep *)malloc(sizeof(png_bytep) * h); + for (i = 0; i < h; i++) { + /* Create a buffer for this scanline. */ + rows[i] = (pix + (i * pitch)); + } + + PNGFUNC(set_rows)(png, info, rows); + + PNGFUNC(write_png)(png, info, 0, NULL); + + /* Clean up. */ + (void)fclose(fp); + + PNGFUNC(destroy_write_struct)(&png, &info); + + /* No longer need the row buffers. */ + free(rows); +} diff --git a/src/printer/png_struct.h b/src/printer/png_struct.h new file mode 100644 index 000000000..6647b41b9 --- /dev/null +++ b/src/printer/png_struct.h @@ -0,0 +1,66 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the centralized PNG image handler. + * + * Version: @(#)png_struct.h 1.0.2 2018/11/19 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + */ +#ifndef EMU_PNG_STRUCT_H +# define EMU_PNG_STRUCT_H + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int png_write_gray(wchar_t *path, int invert, + uint8_t *pix, int16_t w, int16_t h); + +extern void png_write_rgb(wchar_t *fn, + uint8_t *pix, int16_t w, int16_t h, uint16_t pitch, PALETTE palcol); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_PNG_STRUCT_H*/ diff --git a/src/printer/printer.h b/src/printer/printer.h new file mode 100644 index 000000000..33f7d58c9 --- /dev/null +++ b/src/printer/printer.h @@ -0,0 +1,65 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the printers module. + * + * Version: @(#)printer.h 1.0.3 2018/09/03 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + */ +#ifndef PRINTER_H +# define PRINTER_H + + +#define FONT_FILE_DOTMATRIX L"dotmatrix.ttf" + +#define FONT_FILE_ROMAN L"roman.ttf" +#define FONT_FILE_SANSSERIF L"sansserif.ttf" +#define FONT_FILE_COURIER L"courier.ttf" +#define FONT_FILE_SCRIPT L"script.ttf" +#define FONT_FILE_OCRA L"ocra.ttf" +#define FONT_FILE_OCRB L"ocra.ttf" + + +extern void +select_codepage(uint16_t code, uint16_t *curmap); + + +#endif /*PRINTER_H*/ diff --git a/src/printer/prt_cpmap.c b/src/printer/prt_cpmap.c new file mode 100644 index 000000000..f7c7330f6 --- /dev/null +++ b/src/printer/prt_cpmap.c @@ -0,0 +1,593 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Various ASCII to Unicode maps, for the various codepages. + * + * Version: @(#)prt_cpmap.c 1.0.2 2018/10/05 + * + * Authors: Michael Dr�ing, + * Fred N. van Kempen, + * + * Based on code by Frederic Weymann (originally for DosBox.) + * + * Copyright 2018 Michael Dr�ing. + * Copyright 2018 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" +#include "printer.h" + + +static const uint16_t cp437Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, + 0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp737Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398, + 0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0, + 0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9, + 0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8, + 0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0, + 0x03c1,0x03c3,0x03c2,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03c9,0x03ac,0x03ad,0x03ae,0x03ca,0x03af,0x03cc,0x03cd, + 0x03cb,0x03ce,0x0386,0x0388,0x0389,0x038a,0x038c,0x038e, + 0x038f,0x00b1,0x2265,0x2264,0x03aa,0x03ab,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp775Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x0106,0x00fc,0x00e9,0x0101,0x00e4,0x0123,0x00e5,0x0107, + 0x0142,0x0113,0x0156,0x0157,0x012b,0x0179,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x014d,0x00f6,0x0122,0x00a2,0x015a, + 0x015b,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x00a4, + 0x0100,0x012a,0x00f3,0x017b,0x017c,0x017a,0x201d,0x00a6, + 0x00a9,0x00ae,0x00ac,0x00bd,0x00bc,0x0141,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x0104,0x010c,0x0118, + 0x0116,0x2563,0x2551,0x2557,0x255d,0x012e,0x0160,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0172,0x016a, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x017d, + 0x0105,0x010d,0x0119,0x0117,0x012f,0x0161,0x0173,0x016b, + 0x017e,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x00d3,0x00df,0x014c,0x0143,0x00f5,0x00d5,0x00b5,0x0144, + 0x0136,0x0137,0x013b,0x013c,0x0146,0x0112,0x0145,0x2019, + 0x00ad,0x00b1,0x201c,0x00be,0x00b6,0x00a7,0x00f7,0x201e, + 0x00b0,0x2219,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp850Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, + 0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0, + 0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, + 0x00f0,0x00d0,0x00ca,0x00cb,0x00c8,0x0131,0x00cd,0x00ce, + 0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580, + 0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,0x00fe, + 0x00de,0x00da,0x00db,0x00d9,0x00fd,0x00dd,0x00af,0x00b4, + 0x00ad,0x00b1,0x2017,0x00be,0x00b6,0x00a7,0x00f7,0x00b8, + 0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp852Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x016f,0x0107,0x00e7, + 0x0142,0x00eb,0x0150,0x0151,0x00ee,0x0179,0x00c4,0x0106, + 0x00c9,0x0139,0x013a,0x00f4,0x00f6,0x013d,0x013e,0x015a, + 0x015b,0x00d6,0x00dc,0x0164,0x0165,0x0141,0x00d7,0x010d, + 0x00e1,0x00ed,0x00f3,0x00fa,0x0104,0x0105,0x017d,0x017e, + 0x0118,0x0119,0x00ac,0x017a,0x010c,0x015f,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x011a, + 0x015e,0x2563,0x2551,0x2557,0x255d,0x017b,0x017c,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0102,0x0103, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, + 0x0111,0x0110,0x010e,0x00cb,0x010f,0x0147,0x00cd,0x00ce, + 0x011b,0x2518,0x250c,0x2588,0x2584,0x0162,0x016e,0x2580, + 0x00d3,0x00df,0x00d4,0x0143,0x0144,0x0148,0x0160,0x0161, + 0x0154,0x00da,0x0155,0x0170,0x00fd,0x00dd,0x0163,0x00b4, + 0x00ad,0x02dd,0x02db,0x02c7,0x02d8,0x00a7,0x00f7,0x00b8, + 0x00b0,0x00a8,0x02d9,0x0171,0x0158,0x0159,0x25a0,0x00a0 +}; + +static const uint16_t cp855Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x0452,0x0402,0x0453,0x0403,0x0451,0x0401,0x0454,0x0404, + 0x0455,0x0405,0x0456,0x0406,0x0457,0x0407,0x0458,0x0408, + 0x0459,0x0409,0x045a,0x040a,0x045b,0x040b,0x045c,0x040c, + 0x045e,0x040e,0x045f,0x040f,0x044e,0x042e,0x044a,0x042a, + 0x0430,0x0410,0x0431,0x0411,0x0446,0x0426,0x0434,0x0414, + 0x0435,0x0415,0x0444,0x0424,0x0433,0x0413,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x0445,0x0425,0x0438, + 0x0418,0x2563,0x2551,0x2557,0x255d,0x0439,0x0419,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x043a,0x041a, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, + 0x043b,0x041b,0x043c,0x041c,0x043d,0x041d,0x043e,0x041e, + 0x043f,0x2518,0x250c,0x2588,0x2584,0x041f,0x044f,0x2580, + 0x042f,0x0440,0x0420,0x0441,0x0421,0x0442,0x0422,0x0443, + 0x0423,0x0436,0x0416,0x0432,0x0412,0x044c,0x042c,0x2116, + 0x00ad,0x044b,0x042b,0x0437,0x0417,0x0448,0x0428,0x044d, + 0x042d,0x0449,0x0429,0x0447,0x0427,0x00a7,0x25a0,0x00a0 +}; + +static const uint16_t cp857Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x0131,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, + 0x0130,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x015e,0x015f, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x011e,0x011f, + 0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0, + 0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, + 0x00ba,0x00aa,0x00ca,0x00cb,0x00c8,0x0000,0x00cd,0x00ce, + 0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580, + 0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,0x0000, + 0x00d7,0x00da,0x00db,0x00d9,0x00ec,0x00ff,0x00af,0x00b4, + 0x00ad,0x00b1,0x0000,0x00be,0x00b6,0x00a7,0x00f7,0x00b8, + 0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp860Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e3,0x00e0,0x00c1,0x00e7, + 0x00ea,0x00ca,0x00e8,0x00cd,0x00d4,0x00ec,0x00c3,0x00c2, + 0x00c9,0x00c0,0x00c8,0x00f4,0x00f5,0x00f2,0x00da,0x00f9, + 0x00cc,0x00d5,0x00dc,0x00a2,0x00a3,0x00d9,0x20a7,0x00d3, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x00d2,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp861Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00d0,0x00f0,0x00de,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00fe,0x00fb,0x00dd, + 0x00fd,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00c1,0x00cd,0x00d3,0x00da, + 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp862Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7, + 0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df, + 0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7, + 0x05e8,0x05e9,0x05ea,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp863Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00c2,0x00e0,0x00b6,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x2017,0x00c0,0x00a7, + 0x00c9,0x00c8,0x00ca,0x00f4,0x00cb,0x00cf,0x00fb,0x00f9, + 0x00a4,0x00d4,0x00dc,0x00a2,0x00a3,0x00d9,0x00db,0x0192, + 0x00a6,0x00b4,0x00f3,0x00fa,0x00a8,0x00b8,0x00b3,0x00af, + 0x00ce,0x2310,0x00ac,0x00bd,0x00bc,0x00be,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp864Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x066a,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00b0,0x00b7,0x2219,0x221a,0x2592,0x2500,0x2502,0x253c, + 0x2524,0x252c,0x251c,0x2534,0x2510,0x250c,0x2514,0x2518, + 0x03b2,0x221e,0x03c6,0x00b1,0x00bd,0x00bc,0x2248,0x00ab, + 0x00bb,0xfef7,0xfef8,0x0000,0x0000,0xfefb,0xfefc,0x0000, + 0x00a0,0x00ad,0xfe82,0x00a3,0x00a4,0xfe84,0x0000,0x0000, + 0xfe8e,0xfe8f,0xfe95,0xfe99,0x060c,0xfe9d,0xfea1,0xfea5, + 0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667, + 0x0668,0x0669,0xfed1,0x061b,0xfeb1,0xfeb5,0xfeb9,0x061f, + 0x00a2,0xfe80,0xfe81,0xfe83,0xfe85,0xfeca,0xfe8b,0xfe8d, + 0xfe91,0xfe93,0xfe97,0xfe9b,0xfe9f,0xfea3,0xfea7,0xfea9, + 0xfeab,0xfead,0xfeaf,0xfeb3,0xfeb7,0xfebb,0xfebf,0xfec1, + 0xfec5,0xfecb,0xfecf,0x00a6,0x00ac,0x00f7,0x00d7,0xfec9, + 0x0640,0xfed3,0xfed7,0xfedb,0xfedf,0xfee3,0xfee7,0xfeeb, + 0xfeed,0xfeef,0xfef3,0xfebd,0xfecc,0xfece,0xfecd,0xfee1, + 0xfe7d,0x0651,0xfee5,0xfee9,0xfeec,0xfef0,0xfef2,0xfed0, + 0xfed5,0xfef5,0xfef6,0xfedd,0xfed9,0xfef1,0x25a0,0x00a0 +}; + +static const uint16_t cp865Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, + 0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00a4, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp866Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417, + 0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f, + 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427, + 0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f, + 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437, + 0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447, + 0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f, + 0x0401,0x0451,0x0404,0x0454,0x0407,0x0457,0x040e,0x045e, + 0x00b0,0x2219,0x00b7,0x221a,0x2116,0x00a4,0x25a0,0x00a0 +}; + + +static const struct { + uint16_t code; + const uint16_t *map; +} maps[] = { + { 437, cp437Map }, + { 737, cp737Map }, + { 775, cp775Map }, + { 850, cp850Map }, + { 852, cp852Map }, + { 855, cp855Map }, + { 857, cp857Map }, + { 860, cp860Map }, + { 861, cp861Map }, + { 862, cp862Map }, + { 863, cp863Map }, + { 864, cp864Map }, + { 865, cp865Map }, + { 866, cp866Map }, + { -1, NULL } +}; + + +/* Select a ASCII->Unicode mapping by CP number */ +void +select_codepage(uint16_t code, uint16_t *curmap) +{ + int i = 0; + const uint16_t *map_to_use; + + map_to_use = maps[0].map; + + while (maps[i].code != 0) { + if (maps[i].code == code) { + map_to_use = maps[i].map; + break; + } + i++; + } + + for (i = 0; i < 256; i++) + curmap[i] = map_to_use[i]; +} diff --git a/src/printer/prt_devs.h b/src/printer/prt_devs.h new file mode 100644 index 000000000..7ef25e5cd --- /dev/null +++ b/src/printer/prt_devs.h @@ -0,0 +1,3 @@ +extern const lpt_device_t lpt_prt_text_device; +extern const lpt_device_t lpt_prt_escp_device; +extern const lpt_device_t lpt_prt_ps_device; \ No newline at end of file diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c new file mode 100644 index 000000000..597105cd4 --- /dev/null +++ b/src/printer/prt_escp.c @@ -0,0 +1,2151 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Generic ESC/P Dot-Matrix printer. + * + * Version: @(#)prt_escp.c 1.0.7 2019/09/23 + * + * Authors: Michael Drüing, + * Fred N. van Kempen, + * + * Based on code by Frederic Weymann (originally for DosBox.) + * + * Copyright 2018,2019 Michael Drüing. + * Copyright 2019,2019 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include FT_FREETYPE_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../timer.h" +#include "../mem.h" +#include "../rom.h" +#include "../pit.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../ui.h" +#include "../lpt.h" +#include "../video/video.h" +#include "png_struct.h" +#include "printer.h" +#include "prt_devs.h" + + +/* Default page values (for now.) */ +#define COLOR_BLACK 7<<5 +#define PAGE_WIDTH 8.5 /* standard U.S. Letter */ +#define PAGE_HEIGHT 11.0 +#define PAGE_LMARGIN 0.0 +#define PAGE_RMARGIN PAGE_WIDTH +#define PAGE_TMARGIN 0.0 +#define PAGE_BMARGIN PAGE_HEIGHT +#define PAGE_DPI 360 +#define PAGE_CPI 10.0 /* standard 10 cpi */ +#define PAGE_LPI 6.0 /* standard 6 lpi */ + + +#ifdef _WIN32 +# define PATH_FREETYPE_DLL "freetype.dll" +#else +# define PATH_FREETYPE_DLL "libfreetype.so.6" +#endif + + +/* FreeType library handles - global so they can be shared. */ +FT_Library ft_lib = NULL; +void *ft_handle = NULL; + +static int (*ft_Init_FreeType)(FT_Library *alibrary); +static int (*ft_Done_Face)(FT_Face face); +static int (*ft_New_Face)(FT_Library library, const char *filepathname, + FT_Long face_index, FT_Face *aface); +static int (*ft_Set_Char_Size)(FT_Face face, FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution); +static int (*ft_Set_Transform)(FT_Face face, FT_Matrix *matrix, + FT_Vector *delta); +static int (*ft_Get_Char_Index)(FT_Face face, FT_ULong charcode); +static int (*ft_Load_Glyph)(FT_Face face, FT_UInt glyph_index, + FT_Int32 load_flags); +static int (*ft_Render_Glyph)(FT_GlyphSlot slot, + FT_Render_Mode render_mode); + + +static dllimp_t ft_imports[] = { + { "FT_Init_FreeType", &ft_Init_FreeType }, + { "FT_New_Face", &ft_New_Face }, + { "FT_Done_Face", &ft_Done_Face }, + { "FT_Set_Char_Size", &ft_Set_Char_Size }, + { "FT_Set_Transform", &ft_Set_Transform }, + { "FT_Get_Char_Index", &ft_Get_Char_Index }, + { "FT_Load_Glyph", &ft_Load_Glyph }, + { "FT_Render_Glyph", &ft_Render_Glyph }, + { NULL, NULL } +}; + + +/* The fonts. */ +#define FONT_DEFAULT 0 +#define FONT_ROMAN 1 +#define FONT_SANSSERIF 2 +#define FONT_COURIER 3 +#define FONT_SCRIPT 4 +#define FONT_OCRA 5 +#define FONT_OCRB 6 + +/* Font styles. */ +#define STYLE_PROP 0x0001 +#define STYLE_CONDENSED 0x0002 +#define STYLE_BOLD 0x0004 +#define STYLE_DOUBLESTRIKE 0x0008 +#define STYLE_DOUBLEWIDTH 0x0010 +#define STYLE_ITALICS 0x0020 +#define STYLE_UNDERLINE 0x0040 +#define STYLE_SUPERSCRIPT 0x0080 +#define STYLE_SUBSCRIPT 0x0100 +#define STYLE_STRIKETHROUGH 0x0200 +#define STYLE_OVERSCORE 0x0400 +#define STYLE_DOUBLEWIDTHONELINE 0x0800 +#define STYLE_DOUBLEHEIGHT 0x1000 + +/* Underlining styles. */ +#define SCORE_NONE 0x00 +#define SCORE_SINGLE 0x01 +#define SCORE_DOUBLE 0x02 +#define SCORE_SINGLEBROKEN 0x05 +#define SCORE_DOUBLEBROKEN 0x06 + +/* Print quality. */ +#define QUALITY_DRAFT 0x01 +#define QUALITY_LQ 0x02 + +/* Typefaces. */ +#define TYPEFACE_ROMAN 0 +#define TYPEFACE_SANSSERIF 1 +#define TYPEFACE_COURIER 2 +#define TYPEFACE_PRESTIGE 3 +#define TYPEFACE_SCRIPT 4 +#define TYPEFACE_OCRB 5 +#define TYPEFACE_OCRA 6 +#define TYPEFACE_ORATOR 7 +#define TYPEFACE_ORATORS 8 +#define TYPEFACE_SCRIPTC 9 +#define TYPEFACE_ROMANT 10 +#define TYPEFACE_SANSSERIFH 11 +#define TYPEFACE_SVBUSABA 30 +#define TYPEFACE_SVJITTRA 31 + + +/* Some helper macros. */ +#define PARAM16(x) (dev->esc_parms[x+1] * 256 + dev->esc_parms[x]) +#define PIXX ((unsigned)floor(dev->curr_x * dev->dpi + 0.5)) +#define PIXY ((unsigned)floor(dev->curr_y * dev->dpi + 0.5)) + + +typedef struct { + int8_t dirty; /* has the page been printed on? */ + char pad; + + uint16_t w; /* size and pitch //INFO */ + uint16_t h; + uint16_t pitch; + + uint8_t *pixels; /* grayscale pixel data */ +} psurface_t; + + +typedef struct { + const char *name; + + void *lpt; + + pc_timer_t pulse_timer; + pc_timer_t timeout_timer; + + wchar_t page_fn[260]; + uint8_t color; + + /* page data (TODO: make configurable) */ + double page_width, /* all in inches */ + page_height, + left_margin, + top_margin, + right_margin, + bottom_margin; + uint16_t dpi; + double cpi; /* defined chars per inch */ + double lpi; /* defined lines per inch */ + + /* font data */ + double actual_cpi; /* actual cpi as with current font */ + double linespacing; /* in inch */ + double hmi; /* hor. motion index (inch); overrides CPI */ + + /* tabstops */ + double horizontal_tabs[32]; + uint8_t num_horizontal_tabs; + double vertical_tabs[16]; + uint8_t num_vertical_tabs; + + /* bit graphics data */ + uint16_t bg_h_density; /* in dpi */ + uint16_t bg_v_density; /* in dpi */ + int8_t bg_adjacent; /* print adjacent pixels (ignored) */ + uint8_t bg_bytes_per_column; + uint16_t bg_remaining_bytes; /* #bytes left before img is complete */ + uint8_t bg_column[6]; /* #bytes of the current and last col */ + uint8_t bg_bytes_read; /* #bytes read so far for current col */ + + /* handshake data */ + uint8_t data; + uint8_t ack; + uint8_t select; + uint8_t busy; + uint8_t int_pending; + uint8_t error; + uint8_t autofeed; + + /* ESC command data */ + int8_t esc_seen; /* set to 1 if an ESC char was seen */ + int8_t fss_seen; + uint16_t esc_pending; /* in which ESC command are we */ + uint8_t esc_parms_req; + uint8_t esc_parms_curr; + uint8_t esc_parms[20]; /* 20 should be enough for everybody */ + + /* internal page data */ + wchar_t fontpath[1024]; + wchar_t pagepath[1024]; + psurface_t *page; + double curr_x, curr_y; /* print head position (inch) */ + uint16_t current_font; + FT_Face fontface; + int8_t lq_typeface; + uint16_t font_style; + uint8_t print_quality; + uint8_t font_score; + double extra_intra_space; /* extra spacing between chars (inch) */ + + /* other internal data */ + uint16_t char_tables[4]; /* the character tables for ESC t */ + uint8_t curr_char_table; /* the active char table index */ + uint16_t curr_cpmap[256]; /* current ASCII->Unicode map table */ + + int8_t multipoint_mode; /* multipoint mode, ESC X */ + double multipoint_size; /* size of font, in points */ + double multipoint_cpi; /* chars per inch in multipoint mode */ + + uint8_t density_k; /* density modes for ESC K/L/Y/Z */ + uint8_t density_l; + uint8_t density_y; + uint8_t density_z; + + int8_t print_upper_control; /* ESC 6, ESC 7 */ + int8_t print_everything_count; /* for ESC ( ^ */ + + double defined_unit; /* internal unit for some ESC/P + * commands. -1 = use default */ + + uint8_t msb; /* MSB mode, -1 = off */ + uint8_t ctrl; + + PALETTE palcol; +} escp_t; + + +static void +update_font(escp_t *dev); +static void +blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add); +static void +draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken); +static void +init_codepage(escp_t *dev, uint16_t num); +static void +reset_printer(escp_t *dev); +static void +setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns); +static void +print_bit_graph(escp_t *dev, uint8_t ch); +static void +new_page(escp_t *dev, int8_t save, int8_t resetx); + + +/* Codepage table, needed for ESC t ( */ +static const uint16_t codepages[15] = { + 0, 437, 932, 850, 851, 853, 855, 860, + 863, 865, 852, 857, 862, 864, 866 +}; + + +/* "patches" to the codepage for the international charsets + * these bytes patch the following 12 positions of the char table, in order: + * 0x23 0x24 0x40 0x5b 0x5c 0x5d 0x5e 0x60 0x7b 0x7c 0x7d 0x7e + * TODO: Implement the missing international charsets + */ +static const uint16_t intCharSets[15][12] = { + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 0 USA */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, + + { 0x0023, 0x0024, 0x00e0, 0x00ba, 0x00e7, 0x00a7, /* 1 France */ + 0x005e, 0x0060, 0x00e9, 0x00f9, 0x00e8, 0x00a8 }, + + { 0x0023, 0x0024, 0x00a7, 0x00c4, 0x00d6, 0x00dc, /* 2 Germany */ + 0x005e, 0x0060, 0x00e4, 0x00f6, 0x00fc, 0x00df }, + + { 0x00a3, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 3 UK */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, + + { 0x0023, 0x0024, 0x0040, 0x00c6, 0x00d8, 0x00c5, /* 4 Denmark (1) */ + 0x005e, 0x0060, 0x00e6, 0x00f8, 0x00e5, 0x007e }, + + { 0x0023, 0x00a4, 0x00c9, 0x00c4, 0x00d6, 0x00c5, /* 5 Sweden */ + 0x00dc, 0x00e9, 0x00e4, 0x00f6, 0x00e5, 0x00fc }, + + { 0x0023, 0x0024, 0x0040, 0x00ba, 0x005c, 0x00e9, /* 6 Italy */ + 0x005e, 0x00f9, 0x00e0, 0x00f2, 0x00e8, 0x00ec }, + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 7 Spain 1 */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 8 Japan (English) */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 9 Norway */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 10 Denmark (2) */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 11 Spain (2) */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 12 Latin America */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 13 Korea */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x00a7, 0x00c4, 0x0027, 0x0022, /* 14 Legal */ + 0x00b6, 0x0060, 0x00a9, 0x00ae, 0x2020, 0x2122 } +}; + + +#ifdef ENABLE_ESCP_LOG +int escp_do_log = ENABLE_ESCP_LOG; + + +static void +escp_log(const char *fmt, ...) +{ + va_list ap; + + if (escp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define escp_log(fmt, ...) +#endif + + +/* Dump the current page into a formatted file. */ +static void +dump_page(escp_t *dev) +{ + wchar_t path[1024]; + + wcscpy(path, dev->pagepath); + wcscat(path, dev->page_fn); + png_write_rgb(path, dev->page->pixels, dev->page->w, dev->page->h, dev->page->pitch, dev->palcol); +} + + +static void +new_page(escp_t *dev, int8_t save, int8_t resetx) +{ + /* Dump the current page if needed. */ + if (save) + dump_page(dev); + if (resetx) + dev->curr_x = dev->left_margin; + + /* Clear page. */ + dev->curr_y = dev->top_margin; + dev->page->dirty = 0; + memset(dev->page->pixels, 0x00, dev->page->pitch * dev->page->h); + + /* Make the page's file name. */ + plat_tempfile(dev->page_fn, NULL, L".png"); +} + + +static void +pulse_timer(void *priv) +{ + escp_t *dev = (escp_t *) priv; + + if (dev->ack) { + dev->ack = 0; + lpt_irq(dev->lpt, 1); + } + + timer_disable(&dev->pulse_timer); +} + + +static void +timeout_timer(void *priv) +{ + escp_t *dev = (escp_t *) priv; + + if (dev->page->dirty) + new_page(dev, 1, 1); + + timer_disable(&dev->timeout_timer); +} + + +static void +fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, escp_t *dev) +{ + uint8_t colormask; + int i; + + float red = (float)redmax / (float)30.9; + float green = (float)greenmax / (float)30.9; + float blue = (float)bluemax / (float)30.9; + + colormask = colorID<<=5; + + for(i = 0; i < 32; i++) { + dev->palcol[i+colormask].r = 255 - (uint8_t)floor(red * (float)i); + dev->palcol[i+colormask].g = 255 - (uint8_t)floor(green * (float)i); + dev->palcol[i+colormask].b = 255 - (uint8_t)floor(blue * (float)i); + } +} + + +static void +reset_printer(escp_t *dev) +{ + int i; + + /* TODO: these should be configurable. */ + dev->color = COLOR_BLACK; + dev->curr_x = dev->curr_y = 0.0; + dev->esc_seen = 0; + dev->fss_seen = 0; + dev->esc_pending = 0; + dev->esc_parms_req = dev->esc_parms_curr = 0; + dev->top_margin = dev->left_margin = 0.0; + dev->right_margin = dev->page_width = PAGE_WIDTH; + dev->bottom_margin = dev->page_height = PAGE_HEIGHT; + dev->lpi = PAGE_LPI; + dev->linespacing = 1.0 / dev->lpi; + dev->cpi = PAGE_CPI; + dev->curr_char_table = 1; + dev->font_style = 0; + dev->extra_intra_space = 0.0; + dev->print_upper_control = 1; + dev->bg_remaining_bytes = 0; + dev->density_k = 0; + dev->density_l = 1; + dev->density_y = 2; + dev->density_z = 3; + dev->char_tables[0] = 0; /* italics */ + dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ + dev->defined_unit = -1.0; + dev->multipoint_mode = 0; + dev->multipoint_size = 0.0; + dev->multipoint_cpi = 0.0; + dev->hmi = -1; + dev->msb = 255; + dev->print_everything_count = 0; + dev->lq_typeface = TYPEFACE_COURIER; + + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + + update_font(dev); + + new_page(dev, 0, 1); + + for (i = 0; i < 32; i++) + dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); + dev->num_horizontal_tabs = 32; + dev->num_vertical_tabs = 255; + + if (dev->page != NULL) + dev->page->dirty = 0; + + escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", + dev->page_width, dev->page_height, (int)dev->dpi, + (int)dev->cpi, (int)dev->lpi); +} + + +static void +reset_printer_hard(escp_t *dev) +{ + dev->ack = 0; + timer_disable(&dev->pulse_timer); + timer_disable(&dev->timeout_timer); + reset_printer(dev); +} + + +/* Select a ASCII->Unicode mapping by CP number */ +static void +init_codepage(escp_t *dev, uint16_t num) +{ + /* Get the codepage map for this number. */ + select_codepage(num, dev->curr_cpmap); +} + + +static void +update_font(escp_t *dev) +{ + wchar_t path[1024]; + wchar_t *fn; + char temp[1024]; + FT_Matrix matrix; + double hpoints = 10.5; + double vpoints = 10.5; + + /* We need the FreeType library. */ + if (ft_lib == NULL) + return; + + /* Release current font if we have one. */ + if (dev->fontface) + ft_Done_Face(dev->fontface); + + if (dev->print_quality == QUALITY_DRAFT) + fn = FONT_FILE_DOTMATRIX; + else switch (dev->lq_typeface) { + case TYPEFACE_ROMAN: + fn = FONT_FILE_ROMAN; + break; + case TYPEFACE_SANSSERIF: + fn = FONT_FILE_SANSSERIF; + break; + case TYPEFACE_COURIER: + fn = FONT_FILE_COURIER; + break; + case TYPEFACE_SCRIPT: + fn = FONT_FILE_SCRIPT; + break; + case TYPEFACE_OCRA: + fn = FONT_FILE_OCRA; + break; + case TYPEFACE_OCRB: + fn = FONT_FILE_OCRB; + break; + default: + fn = FONT_FILE_DOTMATRIX; + } + + /* Create a full pathname for the ROM file. */ + wcscpy(path, dev->fontpath); + plat_path_slash(path); + wcscat(path, fn); + + /* Convert (back) to ANSI for the FreeType API. */ + wcstombs(temp, path, sizeof(temp)); + + escp_log("Temp file=%s\n", temp); + + /* Load the new font. */ + if (ft_New_Face(ft_lib, temp, 0, &dev->fontface)) { + escp_log("ESC/P: unable to load font '%s'\n", temp); + dev->fontface = NULL; + } + + if (!dev->multipoint_mode) { + dev->actual_cpi = dev->cpi; + + if (!(dev->font_style & STYLE_CONDENSED)) { + hpoints *= 10.0 / dev->cpi; + vpoints *= 10.0 / dev->cpi; + } + + if (!(dev->font_style & STYLE_PROP)) { + if ((dev->cpi == 10.0) && (dev->font_style & STYLE_CONDENSED)) { + dev->actual_cpi = 17.14; + hpoints *= 10.0 / 17.14; + } + + if ((dev->cpi == 12) && (dev->font_style & STYLE_CONDENSED)) { + dev->actual_cpi = 20.0; + hpoints *= 10.0 / 20.0; + vpoints *= 10.0 / 12.0; + } + } + else if (dev->font_style & STYLE_CONDENSED) + hpoints /= 2.0; + + if ((dev->font_style & STYLE_DOUBLEWIDTH) || + (dev->font_style & STYLE_DOUBLEWIDTHONELINE)) { + dev->actual_cpi /= 2.0; + hpoints *= 2.0; + } + + if (dev->font_style & STYLE_DOUBLEHEIGHT) + vpoints *= 2.0; + } else { + /* Multipoint mode. */ + dev->actual_cpi = dev->multipoint_cpi; + hpoints = vpoints = dev->multipoint_size; + } + + if ((dev->font_style & STYLE_SUPERSCRIPT) || (dev->font_style & STYLE_SUBSCRIPT)) { + hpoints *= 2.0 / 3.0; + vpoints *= 2.0 / 3.0; + dev->actual_cpi /= 2.0 / 3.0; + } + + ft_Set_Char_Size(dev->fontface, + (uint16_t)(hpoints * 64), (uint16_t)(vpoints * 64), + dev->dpi, dev->dpi); + + if ((dev->font_style & STYLE_ITALICS) || + (dev->char_tables[dev->curr_char_table] == 0)) { + /* Italics transformation. */ + matrix.xx = 0x10000L; + matrix.xy = (FT_Fixed)(0.20 * 0x10000L); + matrix.yx = 0; + matrix.yy = 0x10000L; + ft_Set_Transform(dev->fontface, &matrix, 0); + } +} + + +/* This is the actual ESC/P interpreter. */ +static int +process_char(escp_t *dev, uint8_t ch) +{ + double new_x, new_y; + double move_to; + double unit_size; + double reverse; + double new_top, new_bottom; + uint16_t rel_move; + int16_t i; + + escp_log("Esc_seen=%d, fss_seen=%d\n", dev->esc_seen, dev->fss_seen); + /* Determine number of additional command params that are expected. */ + if (dev->esc_seen || dev->fss_seen) { + dev->esc_pending = ch; + if (dev->fss_seen) + dev->esc_pending |= 0x800; + dev->esc_seen = dev->fss_seen = 0; + dev->esc_parms_curr = 0; + + escp_log("Command pending=%02x, font path=%ls\n", dev->esc_pending, dev->fontpath); + switch (dev->esc_pending) { + case 0x02: // Undocumented + case 0x0a: // Reverse line feed + case 0x0c: // Return to top of current page + case 0x0e: // Select double-width printing (one line) (ESC SO) + case 0x0f: // Select condensed printing (ESC SI) + case 0x23: // Cancel MSB control (ESC #) + case 0x30: // Select 1/8-inch line spacing (ESC 0) + case 0x31: // Select 7/60-inch line spacing + case 0x32: // Select 1/6-inch line spacing (ESC 2) + case 0x34: // Select italic font (ESC 4) + case 0x35: // Cancel italic font (ESC 5) + case 0x36: // Enable printing of upper control codes (ESC 6) + case 0x37: // Enable upper control codes (ESC 7) + case 0x38: // Disable paper-out detector + case 0x39: // Enable paper-out detector + case 0x3c: // Unidirectional mode (one line) (ESC <) + case 0x3d: // Set MSB to 0 (ESC =) + case 0x3e: // Set MSB to 1 (ESC >) + case 0x40: // Initialize printer (ESC @) + case 0x45: // Select bold font (ESC E) + case 0x46: // Cancel bold font (ESC F) + case 0x47: // Select double-strike printing (ESC G) + case 0x48: // Cancel double-strike printing (ESC H) + case 0x4d: // Select 10.5-point, 12-cpi (ESC M) + case 0x4f: // Cancel bottom margin + case 0x50: // Select 10.5-point, 10-cpi (ESC P) + case 0x54: // Cancel superscript/subscript printing (ESC T) + case 0x5e: // Enable printing of all character codes on next character + case 0x67: // Select 10.5-point, 15-cpi (ESC g) + + case 0x834: // Select italic font (FS 4) (= ESC 4) + case 0x835: // Cancel italic font (FS 5) (= ESC 5) + case 0x846: // Select forward feed mode (FS F) + case 0x852: // Select reverse feed mode (FS R) + dev->esc_parms_req = 0; + break; + + case 0x19: // Control paper loading/ejecting (ESC EM) + case 0x20: // Set intercharacter space (ESC SP) + case 0x21: // Master select (ESC !) + case 0x2b: // Set n/360-inch line spacing (ESC +) + case 0x2d: // Turn underline on/off (ESC -) + case 0x2f: // Select vertical tab channel (ESC /) + case 0x33: // Set n/180-inch line spacing (ESC 3) + case 0x41: // Set n/60-inch line spacing + case 0x43: // Set page length in lines (ESC C) + case 0x49: // Select character type and print pitch + case 0x4a: // Advance print position vertically (ESC J n) + case 0x4e: // Set bottom margin (ESC N) + case 0x51: // Set right margin (ESC Q) + case 0x52: // Select an international character set (ESC R) + case 0x53: // Select superscript/subscript printing (ESC S) + case 0x55: // Turn unidirectional mode on/off (ESC U) + case 0x57: // Turn double-width printing on/off (ESC W) + case 0x61: // Select justification (ESC a) + case 0x66: // Absolute horizontal tab in columns [conflict] + case 0x68: // Select double or quadruple size + case 0x69: // Immediate print + case 0x6a: // Reverse paper feed + case 0x6b: // Select typeface (ESC k) + case 0x6c: // Set left margin (ESC 1) + case 0x70: // Turn proportional mode on/off (ESC p) + case 0x72: // Select printing color (ESC r) + case 0x73: // Select low-speed mode (ESC s) + case 0x74: // Select character table (ESC t) + case 0x77: // Turn double-height printing on/off (ESC w) + case 0x78: // Select LQ or draft (ESC x) + case 0x7e: // Select/Deselect slash zero (ESC ~) + case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) + case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) + case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) + case 0x843: // Select LQ type style (FS C) (= ESC k) + case 0x845: // Select character width (FS E) + case 0x849: // Select character table (FS I) (= ESC t) + case 0x853: // Select High Speed/High Density elite pitch (FS S) + case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) + dev->esc_parms_req = 1; + break; + + case 0x24: // Set absolute horizontal print position (ESC $) + case 0x3f: // Reassign bit-image mode (ESC ?) + case 0x4b: // Select 60-dpi graphics (ESC K) + case 0x4c: // Select 120-dpi graphics (ESC L) + case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) + case 0x5a: // Select 240-dpi graphics (ESC Z) + case 0x5c: // Set relative horizontal print position (ESC \) + case 0x63: // Set horizontal motion index (HMI) (ESC c) + case 0x65: // Set vertical tab stops every n lines (ESC e) + case 0x85a: // Print 24-bit hex-density graphics (FS Z) + dev->esc_parms_req = 2; + break; + + case 0x2a: // Select bit image (ESC *) + case 0x58: // Select font by pitch and point (ESC X) + dev->esc_parms_req = 3; + break; + + case 0x5b: // Select character height, width, line spacing + dev->esc_parms_req = 7; + break; + + case 0x62: // Set vertical tabs in VFU channels (ESC b) + case 0x42: // Set vertical tabs (ESC B) + dev->num_vertical_tabs = 0; + return 1; + + case 0x44: // Set horizontal tabs (ESC D) + dev->num_horizontal_tabs = 0; + return 1; + + case 0x25: // Select user-defined set (ESC %) + case 0x26: // Define user-defined characters (ESC &) + case 0x3a: // Copy ROM to RAM (ESC :) + escp_log("ESC/P: User-defined characters not supported (0x%02x).\n", dev->esc_pending); + return 1; + + case 0x28: // Two bytes sequence + /* return and wait for second ESC byte */ + return 1; + + case 0x2e: + fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); + exit(-1); + return 1; + + default: + escp_log("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", + dev->esc_pending >= 0x20 ? dev->esc_pending : '?', dev->esc_pending); + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + + if (dev->esc_parms_req > 0) { + /* return and wait for parameters to appear */ + return 1; + } + } + + /* parameter checking for the 2-byte ESC/P2 commands */ + if (dev->esc_pending == '(') { + dev->esc_pending = 0x0200 + ch; + + escp_log("Two-byte command pending=%03x, font path=%ls\n", dev->esc_pending, dev->fontpath); + switch (dev->esc_pending) { + case 0x0242: // Bar code setup and print (ESC (B) + case 0x025e: // Print data as characters (ESC (^) + dev->esc_parms_req = 2; + break; + + case 0x0255: // Set unit (ESC (U) + dev->esc_parms_req = 3; + break; + + case 0x0243: // Set page length in defined unit (ESC (C) + case 0x0256: // Set absolute vertical print position (ESC (V) + case 0x0276: // Set relative vertical print position (ESC (v) + dev->esc_parms_req = 4; + break; + + case 0x0228: // Assign character table (ESC (t) + case 0x022d: // Select line/score (ESC (-) + dev->esc_parms_req = 5; + break; + + case 0x0263: // Set page format (ESC (c) + dev->esc_parms_req = 6; + break; + + default: + /* ESC ( commands are always followed by a "number of parameters" word parameter */ + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; /* dummy value to be checked later */ + return 1; + } + + /* If we need parameters, return and wait for them to appear. */ + if (dev->esc_parms_req > 0) + return 1; + } + + /* Ignore VFU channel setting. */ + if (dev->esc_pending == 0x62) { + dev->esc_pending = 0x42; + return 1; + } + + /* Collect vertical tabs. */ + if (dev->esc_pending == 0x42) { + /* check if we're done */ + if ((ch == 0) || + (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double)ch * dev->linespacing)) { + dev->esc_pending = 0; + } else { + if (dev->num_vertical_tabs < 16) + dev->vertical_tabs[dev->num_vertical_tabs++] = (double)ch * dev->linespacing; + } + } + + /* Collect horizontal tabs. */ + if (dev->esc_pending == 0x44) { + /* check if we're done... */ + if ((ch == 0) || + (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double)ch * (1.0 / dev->cpi))) { + dev->esc_pending = 0; + } else { + if (dev->num_horizontal_tabs < 32) + dev->horizontal_tabs[dev->num_horizontal_tabs++] = (double)ch * (1.0 / dev->cpi); + } + } + + /* Check if we're still collecting parameters for the current command. */ + if (dev->esc_parms_curr < dev->esc_parms_req) { + /* store current parameter */ + dev->esc_parms[dev->esc_parms_curr++] = ch; + + /* do we still need to continue collecting parameters? */ + if (dev->esc_parms_curr < dev->esc_parms_req) + return 1; + } + + /* Handle the pending ESC command. */ + if (dev->esc_pending != 0) { + switch (dev->esc_pending) { + case 0x02: /* undocumented; ignore */ + break; + + case 0x0e: /* select double-width (one line) (ESC SO) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + break; + + case 0x0f: /* select condensed printing (ESC SI) */ + if (! dev->multipoint_mode && (dev->cpi != 15.0)) { + dev->hmi = -1; + dev->font_style |= STYLE_CONDENSED; + update_font(dev); + } + break; + + case 0x19: /* control paper loading/ejecting (ESC EM) */ + /* We are not really loading paper, so most + * commands can be ignored */ + if (dev->esc_parms[0] == 'R') + new_page(dev, 1, 0); + + break; + case 0x20: /* set intercharacter space (ESC SP) */ + if (! dev->multipoint_mode) { + dev->extra_intra_space = (double)dev->esc_parms[0] / (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); + dev->hmi = -1; + update_font(dev); + } + break; + + case 0x21: /* master select (ESC !) */ + dev->cpi = dev->esc_parms[0] & 0x01 ? 12.0 : 10.0; + + /* Reset first seven bits. */ + dev->font_style &= 0xFF80; + if (dev->esc_parms[0] & 0x02) + dev->font_style |= STYLE_PROP; + if (dev->esc_parms[0] & 0x04) + dev->font_style |= STYLE_CONDENSED; + if (dev->esc_parms[0] & 0x08) + dev->font_style |= STYLE_BOLD; + if (dev->esc_parms[0] & 0x10) + dev->font_style |= STYLE_DOUBLESTRIKE; + if (dev->esc_parms[0] & 0x20) + dev->font_style |= STYLE_DOUBLEWIDTH; + if (dev->esc_parms[0] & 0x40) + dev->font_style |= STYLE_ITALICS; + if (dev->esc_parms[0] & 0x80) { + dev->font_score = SCORE_SINGLE; + dev->font_style |= STYLE_UNDERLINE; + } + + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x23: /* cancel MSB control (ESC #) */ + dev->msb = 255; + break; + + case 0x24: /* set abs horizontal print position (ESC $) */ + unit_size = dev->defined_unit; + if (unit_size < 0) + unit_size = 60.0; + + new_x = dev->left_margin + ((double)PARAM16(0) / unit_size); + if (new_x <= dev->right_margin) + dev->curr_x = new_x; + break; + + case 0x85a: /* Print 24-bit hex-density graphics (FS Z) */ + setup_bit_image(dev, 40, PARAM16(0)); + break; + + case 0x2a: /* select bit image (ESC *) */ + setup_bit_image(dev, dev->esc_parms[0], PARAM16(1)); + break; + + case 0x2b: /* set n/360-inch line spacing (ESC +) */ + case 0x833: /* Set n/360-inch line spacing (FS 3) */ + dev->linespacing = (double)dev->esc_parms[0] / 360.0; + break; + + case 0x2d: /* turn underline on/off (ESC -) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_UNDERLINE; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { + dev->font_style |= STYLE_UNDERLINE; + dev->font_score = SCORE_SINGLE; + } + update_font(dev); + break; + + case 0x2f: /* select vertical tab channel (ESC /) */ + /* Ignore */ + break; + + case 0x30: /* select 1/8-inch line spacing (ESC 0) */ + dev->linespacing = 1.0 / 8.0; + break; + + case 0x31: /* select 7/60-inch line spacing */ + dev->linespacing = 7.0 / 60.0; + break; + + case 0x32: /* select 1/6-inch line spacing (ESC 2) */ + dev->linespacing = 1.0 / 6.0; + break; + + case 0x33: /* set n/180-inch line spacing (ESC 3) */ + dev->linespacing = (double)dev->esc_parms[0] / 180.0; + break; + + case 0x34: /* select italic font (ESC 4) */ + dev->font_style |= STYLE_ITALICS; + update_font(dev); + break; + + case 0x35: /* cancel italic font (ESC 5) */ + dev->font_style &= ~STYLE_ITALICS; + update_font(dev); + break; + + case 0x36: /* enable printing of upper control codes (ESC 6) */ + dev->print_upper_control = 1; + break; + + case 0x37: /* enable upper control codes (ESC 7) */ + dev->print_upper_control = 0; + break; + + case 0x3c: /* unidirectional mode (one line) (ESC <) */ + /* We don't have a print head, so just + * ignore this. */ + break; + + case 0x3d: /* set MSB to 0 (ESC =) */ + dev->msb = 0; + break; + + case 0x3e: /* set MSB to 1 (ESC >) */ + dev->msb = 1; + break; + + case 0x3f: /* reassign bit-image mode (ESC ?) */ + if (dev->esc_parms[0] == 'K') + dev->density_k = dev->esc_parms[1]; + if (dev->esc_parms[0] == 'L') + dev->density_l = dev->esc_parms[1]; + if (dev->esc_parms[0] == 'Y') + dev->density_y = dev->esc_parms[1]; + if (dev->esc_parms[0] == 'Z') + dev->density_z = dev->esc_parms[1]; + break; + + case 0x40: /* initialize printer (ESC @) */ + reset_printer(dev); + break; + + case 0x41: /* set n/60-inch line spacing */ + case 0x841: + dev->linespacing = (double)dev->esc_parms[0] / 60.0; + break; + + case 0x43: /* set page length in lines (ESC C) */ + if (dev->esc_parms[0] != 0) { + dev->page_height = dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; + } else { /* == 0 => Set page length in inches */ + dev->esc_parms_req = 1; + dev->esc_parms_curr = 0; + dev->esc_pending = 0x100; /* dummy value for later */ + return 1; + } + break; + + case 0x45: /* select bold font (ESC E) */ + dev->font_style |= STYLE_BOLD; + update_font(dev); + break; + + case 0x46: /* cancel bold font (ESC F) */ + dev->font_style &= ~STYLE_BOLD; + update_font(dev); + break; + + case 0x47: /* select dobule-strike printing (ESC G) */ + dev->font_style |= STYLE_DOUBLESTRIKE; + break; + + case 0x48: /* cancel double-strike printing (ESC H) */ + dev->font_style &= ~STYLE_DOUBLESTRIKE; + break; + + case 0x4a: /* advance print pos vertically (ESC J n) */ + dev->curr_y += (double)((double)dev->esc_parms[0] / 180.0); + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + break; + + case 0x4b: /* select 60-dpi graphics (ESC K) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_k, PARAM16(0)); + break; + + case 0x4c: /* select 120-dpi graphics (ESC L) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_l, PARAM16(0)); + break; + + case 0x4d: /* select 10.5-point, 12-cpi (ESC M) */ + dev->cpi = 12.0; + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x4e: /* set bottom margin (ESC N) */ + dev->top_margin = 0.0; + dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; + break; + + case 0x4f: /* cancel bottom (and top) margin */ + dev->top_margin = 0.0; + dev->bottom_margin = dev->page_height; + break; + + case 0x50: /* select 10.5-point, 10-cpi (ESC P) */ + dev->cpi = 10.0; + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x51: /* set right margin */ + dev->right_margin = ((double)dev->esc_parms[0] - 1.0) / dev->cpi; + break; + + case 0x52: /* select an intl character set (ESC R) */ + if (dev->esc_parms[0] <= 13 || dev->esc_parms[0] == '@') { + if (dev->esc_parms[0] == '@') + dev->esc_parms[0] = 14; + + dev->curr_cpmap[0x23] = intCharSets[dev->esc_parms[0]][0]; + dev->curr_cpmap[0x24] = intCharSets[dev->esc_parms[0]][1]; + dev->curr_cpmap[0x40] = intCharSets[dev->esc_parms[0]][2]; + dev->curr_cpmap[0x5b] = intCharSets[dev->esc_parms[0]][3]; + dev->curr_cpmap[0x5c] = intCharSets[dev->esc_parms[0]][4]; + dev->curr_cpmap[0x5d] = intCharSets[dev->esc_parms[0]][5]; + dev->curr_cpmap[0x5e] = intCharSets[dev->esc_parms[0]][6]; + dev->curr_cpmap[0x60] = intCharSets[dev->esc_parms[0]][7]; + dev->curr_cpmap[0x7b] = intCharSets[dev->esc_parms[0]][8]; + dev->curr_cpmap[0x7c] = intCharSets[dev->esc_parms[0]][9]; + dev->curr_cpmap[0x7d] = intCharSets[dev->esc_parms[0]][10]; + dev->curr_cpmap[0x7e] = intCharSets[dev->esc_parms[0]][11]; + } + break; + + case 0x53: /* select superscript/subscript printing (ESC S) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style |= STYLE_SUBSCRIPT; + if (dev->esc_parms[0] == 1 || dev->esc_parms[1] == '1') + dev->font_style |= STYLE_SUPERSCRIPT; + update_font(dev); + break; + + case 0x54: /* cancel superscript/subscript printing (ESC T) */ + dev->font_style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; + update_font(dev); + break; + + case 0x55: /* turn unidirectional mode on/off (ESC U) */ + /* We don't have a print head, so just ignore this. */ + break; + + case 0x57: /* turn double-width printing on/off (ESC W) */ + if (!dev->multipoint_mode) { + dev->hmi = -1; + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_DOUBLEWIDTH; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') + dev->font_style |= STYLE_DOUBLEWIDTH; + update_font(dev); + } + break; + + case 0x58: /* select font by pitch and point (ESC X) */ + dev->multipoint_mode = 1; + /* Copy currently non-multipoint CPI if no value was set so far. */ + if (dev->multipoint_cpi == 0.0) { + dev->multipoint_cpi= dev->cpi; + } + if (dev->esc_parms[0] > 0) { /* set CPI */ + if (dev->esc_parms[0] == 1) { + /* Proportional spacing. */ + dev->font_style |= STYLE_PROP; + } else if (dev->esc_parms[0] >= 5) + dev->multipoint_cpi = 360.0 / (double)dev->esc_parms[0]; + } + if (dev->multipoint_size == 0.0) + dev->multipoint_size = 10.5; + if (PARAM16(1) > 0) { + /* set points */ + dev->multipoint_size = ((double)PARAM16(1)) / 2.0; + } + update_font(dev); + break; + + case 0x59: /* select 120-dpi, double-speed graphics (ESC Y) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_y, PARAM16(0)); + break; + + case 0x5a: /* select 240-dpi graphics (ESC Z) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_z, PARAM16(0)); + break; + + case 0x5c: /* set relative horizontal print pos (ESC \) */ + rel_move = PARAM16(0); + unit_size = dev->defined_unit; + if (unit_size < 0) + unit_size = (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); + dev->curr_x += ((double)rel_move / unit_size); + break; + + case 0x61: /* select justification (ESC a) */ + /* Ignore. */ + break; + + case 0x63: /* set horizontal motion index (HMI) (ESC c) */ + dev->hmi = (double)PARAM16(0) / 360.0; + dev->extra_intra_space = 0.0; + break; + + case 0x67: /* select 10.5-point, 15-cpi (ESC g) */ + dev->cpi = 15; + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x846: // Select forward feed mode (FS F) - set reverse not implemented yet + if (dev->linespacing < 0) + dev->linespacing *= -1; + break; + + case 0x6a: // Reverse paper feed (ESC j) + reverse = (double)PARAM16(0) / (double)216.0; + reverse = dev->curr_y - reverse; + if (reverse < dev->left_margin) + dev->curr_y = dev->left_margin; + else + dev->curr_y = reverse; + break; + + case 0x6b: /* select typeface (ESC k) */ + if (dev->esc_parms[0] <= 11 || dev->esc_parms[0] == 30 || dev->esc_parms[0] == 31) { + dev->lq_typeface = dev->esc_parms[0]; + } + update_font(dev); + break; + + case 0x6c: /* set left margin (ESC 1) */ + dev->left_margin = ((double)dev->esc_parms[0] - 1.0) / dev->cpi; + if (dev->curr_x < dev->left_margin) + dev->curr_x = dev->left_margin; + break; + + case 0x70: /* Turn proportional mode on/off (ESC p) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_PROP; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { + dev->font_style |= STYLE_PROP; + dev->print_quality = QUALITY_LQ; + } + dev->multipoint_mode = 0; + dev->hmi = -1; + update_font(dev); + break; + + case 0x72: /* select printing color (ESC r) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] > 6) + dev->color = COLOR_BLACK; + else + dev->color = dev->esc_parms[0] << 5; + break; + + case 0x73: /* select low-speed mode (ESC s) */ + /* Ignore. */ + break; + + case 0x74: /* select character table (ESC t) */ + case 0x849: /* Select character table (FS I) */ + if (dev->esc_parms[0] < 4) { + dev->curr_char_table = dev->esc_parms[0]; + } else if ((dev->esc_parms[0] >= '0') && (dev->esc_parms[0] <= '3')) { + dev->curr_char_table = dev->esc_parms[0] - '0'; + } + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + update_font(dev); + break; + + case 0x77: /* turn double-height printing on/off (ESC w) */ + if (! dev->multipoint_mode) { + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_DOUBLEHEIGHT; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') + dev->font_style |= STYLE_DOUBLEHEIGHT; + update_font(dev); + } + break; + + case 0x78: /* select LQ or draft (ESC x) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') { + dev->print_quality = QUALITY_DRAFT; + dev->font_style |= STYLE_CONDENSED; + } + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { + dev->print_quality = QUALITY_LQ; + dev->font_style &= ~STYLE_CONDENSED; + } + dev->hmi = -1; + update_font(dev); + break; + + /* Our special command markers. */ + case 0x0100: /* set page length in inches (ESC C NUL) */ + dev->page_height = (double)dev->esc_parms[0]; + dev->bottom_margin = dev->page_height; + dev->top_margin = 0.0; + break; + + case 0x0101: /* skip unsupported ESC ( command */ + dev->esc_parms_req = PARAM16(0); + dev->esc_parms_curr = 0; + break; + + /* Extended ESC ( commands */ + case 0x0228: /* assign character table (ESC (t) */ + case 0x0274: + if (dev->esc_parms[2] < 4 && dev->esc_parms[3] < 16) { + dev->char_tables[dev->esc_parms[2]] = codepages[dev->esc_parms[3]]; + if (dev->esc_parms[2] == dev->curr_char_table) + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + } + break; + + case 0x022d: /* select line/score (ESC (-) */ + dev->font_style &= ~(STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE); + dev->font_score = dev->esc_parms[4]; + if (dev->font_score) { + if (dev->esc_parms[3] == 1) + dev->font_style |= STYLE_UNDERLINE; + if (dev->esc_parms[3] == 2) + dev->font_style |= STYLE_STRIKETHROUGH; + if (dev->esc_parms[3] == 3) + dev->font_style |= STYLE_OVERSCORE; + } + update_font(dev); + break; + + case 0x0242: /* bar code setup and print (ESC (B) */ + //ERRLOG("ESC/P: Barcode printing not supported.\n"); + + /* Find out how many bytes to skip. */ + dev->esc_parms_req = PARAM16(0); + dev->esc_parms_curr = 0; + break; + + case 0x0243: /* set page length in defined unit (ESC (C) */ + if (dev->esc_parms[0] && (dev->defined_unit> 0)) { + dev->page_height = dev->bottom_margin = (double)PARAM16(2) * dev->defined_unit; + dev->top_margin = 0.0; + } + break; + + case 0x0255: /* set unit (ESC (U) */ + dev->defined_unit = 3600.0 / (double)dev->esc_parms[2]; + break; + + case 0x0256: /* set abse vertical print pos (ESC (V) */ + unit_size = dev->defined_unit; + if (unit_size < 0) + unit_size = 360.0; + new_y = dev->top_margin + (double)PARAM16(2) * unit_size; + if (new_y > dev->bottom_margin) + new_page(dev, 1, 0); + else + dev->curr_y = new_y; + break; + + case 0x025e: /* print data as characters (ESC (^) */ + dev->print_everything_count = PARAM16(0); + break; + + case 0x0263: /* set page format (ESC (c) */ + if (dev->defined_unit > 0.0) { + new_top = (double)PARAM16(2) * dev->defined_unit; + new_bottom = (double)PARAM16(4) * dev->defined_unit; + if (new_top >= new_bottom) + break; + if (new_top < dev->page_height) + dev->top_margin = new_top; + if (new_bottom < dev->page_height) + dev->bottom_margin = new_bottom; + if (dev->top_margin > dev->curr_y) + dev->curr_y = dev->top_margin; + } + break; + + case 0x0276: /* set relative vertical print pos (ESC (v) */ + { + unit_size = dev->defined_unit; + if (unit_size < 0.0) + unit_size = 360.0; + new_y = dev->curr_y + (double)((int16_t)PARAM16(2)) * unit_size; + if (new_y > dev->top_margin) { + if (new_y > dev->bottom_margin) + new_page(dev, 1, 0); + else + dev->curr_y = new_y; + } + } + break; + + default: + break; + } + + dev->esc_pending = 0; + return 1; + } + + escp_log("CH=%02x\n", ch); + + /* Now handle the "regular" control characters. */ + switch (ch) { + case 0x00: + return 1; + + case 0x07: /* Beeper (BEL) */ + /* TODO: beep? */ + return 1; + + case 0x08: /* Backspace (BS) */ + new_x = dev->curr_x - (1.0 / dev->actual_cpi); + if (dev->hmi > 0) + new_x = dev->curr_x - dev->hmi; + if (new_x >= dev->left_margin) + dev->curr_x = new_x; + return 1; + + case 0x09: /* Tab horizontally (HT) */ + /* Find tab right to current pos. */ + move_to = -1.0; + for (i = 0; i < dev->num_horizontal_tabs; i++) { + if (dev->horizontal_tabs[i] > dev->curr_x) + move_to = dev->horizontal_tabs[i]; + } + + /* Nothing found or out of page bounds => Ignore. */ + if (move_to > 0.0 && move_to < dev->right_margin) + dev->curr_x = move_to; + + return 1; + + case 0x0b: /* Tab vertically (VT) */ + if (dev->num_vertical_tabs == 0) { + /* All tabs cleared? => Act like CR */ + dev->curr_x = dev->left_margin; + } else if (dev->num_vertical_tabs < 0) { + /* No tabs set since reset => Act like LF */ + dev->curr_x = dev->left_margin; + dev->curr_y += dev->linespacing; + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + } else { + /* Find tab below current pos. */ + move_to = -1; + for (i = 0; i < dev->num_vertical_tabs; i++) { + if (dev->vertical_tabs[i] > dev->curr_y) + move_to = dev->vertical_tabs[i]; + } + + /* Nothing found => Act like FF. */ + if (move_to > dev->bottom_margin || move_to < 0) + new_page(dev, 1, 0); + else + dev->curr_y = move_to; + } + + if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { + dev->font_style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + return 1; + + case 0x0c: /* Form feed (FF) */ + if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + new_page(dev, 1, 1); + return 1; + + case 0x0d: /* Carriage Return (CR) */ + dev->curr_x = dev->left_margin; + if (!dev->autofeed) + return 1; + /*FALLTHROUGH*/ + + case 0x0a: /* Line feed */ + if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + dev->curr_x = dev->left_margin; + dev->curr_y += dev->linespacing; + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + return 1; + + case 0x0e: /* select Real64-width printing (one line) (SO) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + return 1; + + case 0x0f: /* select condensed printing (SI) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_CONDENSED; + update_font(dev); + } + return 1; + + case 0x11: /* select printer (DC1) */ + /* Ignore. */ + return 0; + + case 0x12: /* cancel condensed printing (DC2) */ + dev->hmi = -1; + dev->font_style &= ~STYLE_CONDENSED; + update_font(dev); + return 1; + + case 0x13: /* deselect printer (DC3) */ + /* Ignore. */ + return 1; + + case 0x14: /* cancel double-width printing (one line) (DC4) */ + dev->hmi = -1; + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + return 1; + + case 0x18: /* cancel line (CAN) */ + return 1; + + case 0x1b: /* ESC */ + dev->esc_seen = 1; + return 1; + + case 0x1c: /* FS (IBM commands) */ + dev->fss_seen = 1; + return 1; + + default: + return 0; + } + + /* This is a printable character -> print it. */ + return 0; +} + + +static void +handle_char(escp_t *dev, uint8_t ch) +{ + FT_UInt char_index; + uint16_t pen_x, pen_y; + uint16_t line_start, line_y; + double x_advance; + + if (dev->page == NULL) + return; + + /* MSB mode */ + if (dev->msb != 255) { + if (dev->msb == 0) + ch &= 0x7f; + else if (dev->msb == 1) + ch |= 0x80; + } + + if (dev->bg_remaining_bytes > 0) { + print_bit_graph(dev, ch); + return; + } + + /* "print everything" mode? aka. ESC ( ^ */ + if (dev->print_everything_count > 0) { + escp_log("Print everything count=%d\n", dev->print_everything_count); + /* do not process command char, just continue */ + dev->print_everything_count--; + } else if (process_char(dev, ch)) { + /* command was processed */ + return; + } + + /* We cannot print if we have no font loaded. */ + if (dev->fontface == NULL) + return; + + if (ch == 0x01) + ch = 0x20; + + /* ok, so we need to print the character now */ + if (ft_lib) { + char_index = ft_Get_Char_Index(dev->fontface, dev->curr_cpmap[ch]); + ft_Load_Glyph(dev->fontface, char_index, FT_LOAD_DEFAULT); + ft_Render_Glyph(dev->fontface->glyph, FT_RENDER_MODE_NORMAL); + } + + pen_x = PIXX + dev->fontface->glyph->bitmap_left; + pen_y = (uint16_t)(PIXY - dev->fontface->glyph->bitmap_top + dev->fontface->size->metrics.ascender / 64); + + if (dev->font_style & STYLE_SUBSCRIPT) + pen_y += dev->fontface->glyph->bitmap.rows / 2; + + /* mark the page as dirty if anything is drawn */ + if ((ch != 0x20) || (dev->font_score != SCORE_NONE)) + dev->page->dirty = 1; + + /* draw the glyph */ + blit_glyph(dev, pen_x, pen_y, 0); + blit_glyph(dev, pen_x + 1, pen_y, 1); + + /* doublestrike -> draw glyph a second time, 1px below */ + if (dev->font_style & STYLE_DOUBLESTRIKE) { + blit_glyph(dev, pen_x, pen_y + 1, 1); + blit_glyph(dev, pen_x + 1, pen_y + 1, 1); + } + + /* bold -> draw glyph a second time, 1px to the right */ + if (dev->font_style & STYLE_BOLD) { + blit_glyph(dev, pen_x + 1, pen_y, 1); + blit_glyph(dev, pen_x + 2, pen_y, 1); + blit_glyph(dev, pen_x + 3, pen_y, 1); + } + + line_start = PIXX; + + if (dev->font_style & STYLE_PROP) + x_advance = dev->fontface->glyph->advance.x / (dev->dpi * 64.0); + else { + if (dev->hmi < 0) + x_advance = 1.0 / dev->actual_cpi; + else + x_advance = dev->hmi; + } + + x_advance += dev->extra_intra_space; + dev->curr_x += x_advance; + + /* Line printing (underline etc.) */ + if (dev->font_score != SCORE_NONE && (dev->font_style & (STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE))) { + /* Find out where to put the line. */ + line_y = PIXY; + + if (dev->font_style & STYLE_UNDERLINE) + line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.height * 0.9)); + if (dev->font_style & STYLE_STRIKETHROUGH) + line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.height * 0.45)); + if (dev->font_style & STYLE_OVERSCORE) + line_y = PIXY - ((dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) ? 5 : 0); + + draw_hline(dev, pen_x, PIXX, line_y, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); + + if (dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) + draw_hline(dev, line_start, PIXX, line_y + 5, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); + } + + if ((dev->curr_x + x_advance) > dev->right_margin) { + dev->curr_x = dev->left_margin; + dev->curr_y += dev->linespacing; + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + } +} + + +/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ +static void +blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) +{ + FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; + unsigned x, y; + uint8_t src, *dst; + + /* check if freetype is available */ + if (ft_lib == NULL) + return; + + for (y = 0; y < bitmap->rows; y++) { + for (x = 0; x < bitmap->width; x++) { + src = *(bitmap->buffer + x + y * bitmap->pitch); + /* ignore background, and respect page size */ + if (src > 0 && (destx + x < (unsigned)dev->page->w) && (desty + y < (unsigned)dev->page->h)) { + dst = (uint8_t *)dev->page->pixels + (x + destx) + (y + desty) * dev->page->pitch; + src >>= 3; + + if (add) { + if (((*dst) & 0x1f) + src > 31) + *dst |= (dev->color | 0x1f); + else { + *dst += src; + *dst |= dev->color; + } + } else + *dst = src|dev->color; + } + } + } +} + + +/* Draw anti-aliased line. */ +static void +draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken) +{ + unsigned breakmod = dev->dpi / 15; + unsigned gapstart = (breakmod * 4) / 5; + unsigned x; + + for (x = from_x; x <= to_x; x++) { + /* Skip parts if broken line or going over the border. */ + if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { + if (y > 0 && (y - 1) < dev->page->h) + *((uint8_t*)dev->page->pixels + x + (y - 1) * (unsigned)dev->page->pitch) = 240; + if (y < dev->page->h) + *((uint8_t*)dev->page->pixels + x + y * (unsigned)dev->page->pitch) = !broken ? 255 : 240; + if (y + 1 < dev->page->h) + *((uint8_t*)dev->page->pixels + x + (y + 1) * (unsigned)dev->page->pitch) = 240; + } + } +} + + +static void +setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) +{ + escp_log("Density=%d\n", density); + switch (density) { + case 0: + dev->bg_h_density = 60; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 1: + dev->bg_h_density = 120; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 2: + dev->bg_h_density = 120; + dev->bg_v_density = 60; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 3: + dev->bg_h_density = 60; + dev->bg_v_density = 240; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 4: + dev->bg_h_density = 80; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 6: + dev->bg_h_density = 90; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 32: + dev->bg_h_density = 60; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 33: + dev->bg_h_density = 120; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 38: + dev->bg_h_density = 90; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 39: + dev->bg_h_density = 180; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 40: + dev->bg_h_density = 360; + dev->bg_v_density = 180; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 3; + break; + + case 71: + dev->bg_h_density = 180; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + case 72: + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 6; + break; + + case 73: + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + default: + escp_log("ESC/P: Unsupported bit image density %d.\n", density); + break; + } + + dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; + dev->bg_bytes_read = 0; +} + + +static void +print_bit_graph(escp_t *dev, uint8_t ch) +{ + uint8_t pixel_w; /* width of the "pixel" */ + uint8_t pixel_h; /* height of the "pixel" */ + unsigned i, j, xx, yy; + double old_y; + + dev->bg_column[dev->bg_bytes_read++] = ch; + dev->bg_remaining_bytes--; + + /* Only print after reading a full column. */ + if (dev->bg_bytes_read < dev->bg_bytes_per_column) + return; + + old_y = dev->curr_y; + + pixel_w = 1; + pixel_h = 1; + + if (dev->bg_adjacent) { + /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ + pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; + pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; + } + + for (i = 0; i < dev->bg_bytes_per_column; i++) { + /* for each byte */ + for (j = 128; j != 0; j >>= 1) { + /* for each bit */ + if (dev->bg_column[i] & j) { + /* draw a "pixel" */ + for (xx = 0; xx < pixel_w; xx++) { + for (yy = 0; yy < pixel_h; yy++) { + if (((PIXX + xx) < (unsigned)dev->page->w) && ((PIXY + yy) < (unsigned)dev->page->h)) + *((uint8_t *)dev->page->pixels + (PIXX + xx) + (PIXY + yy)*dev->page->pitch) |= (dev->color | 0x1f); + } + } + } + + dev->curr_y += 1.0 / (double)dev->bg_v_density; + } + } + + /* Mark page dirty. */ + dev->page->dirty = 1; + + /* Restore Y-position. */ + dev->curr_y = old_y; + + dev->bg_bytes_read = 0; + + /* Advance print head. */ + dev->curr_x += 1.0 / dev->bg_h_density; +} + + +static void +write_data(uint8_t val, void *priv) +{ + escp_t *dev = (escp_t *)priv; + + if (dev == NULL) + return; + + dev->data = val; +} + + +static void +write_ctrl(uint8_t val, void *priv) +{ + escp_t *dev = (escp_t *)priv; + + if (dev == NULL) + return; + + if (val & 0x08) { /* SELECT */ + /* select printer */ + dev->select = 1; + } + + if ((val & 0x04) && !(dev->ctrl & 0x04)) { + /* reset printer */ + dev->select = 0; + + reset_printer_hard(dev); + } + + /* Data is strobed to the parallel printer on the falling edge of the + strobe bit. */ + if (!(val & 0x01) && (dev->ctrl & 0x01)) { + /* Process incoming character. */ + handle_char(dev, dev->data); + + /* ACK it, will be read on next READ STATUS. */ + dev->ack = 1; + timer_set_delay_u64(&dev->pulse_timer, ISACONST); + + timer_set_delay_u64(&dev->timeout_timer, 500000 * TIMER_USEC); + } + + dev->ctrl = val; + + dev->autofeed = ((val & 0x02) > 0); +} + + +static uint8_t +read_data(void *priv) +{ + escp_t *dev = (escp_t *)priv; + + return dev->data; +} + + +static uint8_t +read_ctrl(void *priv) +{ + escp_t *dev = (escp_t *)priv; + + return 0xe0 | dev->autofeed ? 0x02 : 0x00 | (dev->ctrl & 0xfd); +} + + +static uint8_t +read_status(void *priv) +{ + escp_t *dev = (escp_t *)priv; + uint8_t ret = 0x1f; + + ret |= 0x80; + + if (!dev->ack) + ret |= 0x40; + + return(ret); +} + + +static void * +escp_init(void *lpt) +{ + const char *fn = PATH_FREETYPE_DLL; + escp_t *dev; + int i; + + /* Dynamically load FreeType. */ + if (ft_handle == NULL) { + ft_handle = dynld_module(fn, ft_imports); + if (ft_handle == NULL) { + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2119); + return(NULL); + } + } + + /* Initialize FreeType. */ + if (ft_lib == NULL) { + if (ft_Init_FreeType(&ft_lib)) { + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2119); + dynld_close(ft_lib); + ft_lib = NULL; + return(NULL); + } + } + + /* Initialize a device instance. */ + dev = (escp_t *)malloc(sizeof(escp_t)); + memset(dev, 0x00, sizeof(escp_t)); + dev->ctrl = 0x04; + dev->lpt = lpt; + + /* Create a full pathname for the font files. */ + wcscpy(dev->fontpath, exe_path); + plat_path_slash(dev->fontpath); + wcscat(dev->fontpath, L"roms/printer/fonts/"); + + /* Create the full path for the page images. */ + plat_append_filename(dev->pagepath, usr_path, L"printer"); + if (! plat_dir_check(dev->pagepath)) + plat_dir_create(dev->pagepath); + plat_path_slash(dev->pagepath); + + dev->page_width = PAGE_WIDTH; + dev->page_height = PAGE_HEIGHT; + dev->dpi = PAGE_DPI; + + /* Create 8-bit grayscale buffer for the page. */ + dev->page = (psurface_t *)malloc(sizeof(psurface_t)); + dev->page->w = (int)(dev->dpi * dev->page_width); + dev->page->h = (int)(dev->dpi * dev->page_height); + dev->page->pitch = dev->page->w; + dev->page->pixels = (uint8_t *)malloc(dev->page->pitch * dev->page->h); + memset(dev->page->pixels, 0x00, dev->page->pitch * dev->page->h); + + /* Initialize parameters. */ + for (i = 0; i < 32; i++) { + dev->palcol[i].r = 255; + dev->palcol[i].g = 255; + dev->palcol[i].b = 255; + } + + /* 0 = all white needed for logic 000 */ + fill_palette( 0, 0, 0, 1, dev); + /* 1 = magenta* 001 */ + fill_palette( 0, 255, 0, 1, dev); + /* 2 = cyan* 010 */ + fill_palette(255, 0, 0, 2, dev); + /* 3 = "violet" 011 */ + fill_palette(255, 255, 0, 3, dev); + /* 4 = yellow* 100 */ + fill_palette( 0, 0, 255, 4, dev); + /* 5 = red 101 */ + fill_palette( 0, 255, 255, 5, dev); + /* 6 = green 110 */ + fill_palette(255, 0, 255, 6, dev); + /* 7 = black 111 */ + fill_palette(255, 255, 255, 7, dev); + + dev->color = COLOR_BLACK; + dev->fontface = 0; + dev->autofeed = 0; + + reset_printer(dev); + + escp_log("ESC/P: created a virtual page of dimensions %d x %d pixels.\n", + dev->page->w, dev->page->h); + + timer_add(&dev->pulse_timer, pulse_timer, dev, 0); + timer_add(&dev->timeout_timer, timeout_timer, dev, 0); + + return(dev); +} + + +static void +escp_close(void *priv) +{ + escp_t *dev = (escp_t *)priv; + + if (dev == NULL) return; + + if (dev->page != NULL) { + /* Print last page if it contains data. */ + if (dev->page->dirty) + dump_page(dev); + + if (dev->page->pixels != NULL) + free(dev->page->pixels); + free(dev->page); + } + + free(dev); +} + + +const lpt_device_t lpt_prt_escp_device = { + "EPSON ESC/P compatible printer", + escp_init, + escp_close, + write_data, + write_ctrl, + read_data, + read_status, + read_ctrl +}; diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c new file mode 100644 index 000000000..effb2d07e --- /dev/null +++ b/src/printer/prt_ps.c @@ -0,0 +1,407 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of a generic PostScript printer. + * + * Version: @(#)prt_ps.c 1.0.2 2019/12/08 + * + * Authors: David HrdliÄka, + * + * Copyright 2019 David HrdliÄka. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../lang/language.h" +#include "../lpt.h" +#include "../timer.h" +#include "../pit.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../ui.h" +#include "prt_devs.h" + +#if defined(_WIN32) && !defined(__WINDOWS__) +#define __WINDOWS__ +#endif +#include +#include + + +#define PATH_GHOSTSCRIPT_DLL "gsdll32.dll" +#define PATH_GHOSTSCRIPT_SO "libgs.so" + +#define POSTSCRIPT_BUFFER_LENGTH 65536 + +static GSDLLAPI int (*ghostscript_revision)(gsapi_revision_t *pr, int len); +static GSDLLAPI int (*ghostscript_new_instance)(void **pinstance, void *caller_handle); +static GSDLLAPI void (*ghostscript_delete_instance)(void *instance); +static GSDLLAPI int (*ghostscript_set_arg_encoding)(void *instance, int encoding); +static GSDLLAPI int (*ghostscript_init_with_args)(void *instance, int argc, char **argv); +static GSDLLAPI int (*ghostscript_exit)(void *instance); + +static dllimp_t ghostscript_imports[] = { + { "gsapi_revision", &ghostscript_revision }, + { "gsapi_new_instance", &ghostscript_new_instance }, + { "gsapi_delete_instance", &ghostscript_delete_instance }, + { "gsapi_set_arg_encoding", &ghostscript_set_arg_encoding }, + { "gsapi_init_with_args", &ghostscript_init_with_args }, + { "gsapi_exit", &ghostscript_exit }, + { NULL, NULL } +}; + +static void *ghostscript_handle = NULL; + +typedef struct +{ + const char *name; + + void *lpt; + + pc_timer_t pulse_timer; + pc_timer_t timeout_timer; + + char data; + bool ack; + bool select; + bool busy; + bool int_pending; + bool error; + bool autofeed; + uint8_t ctrl; + + wchar_t printer_path[260]; + + wchar_t filename[260]; + + char buffer[POSTSCRIPT_BUFFER_LENGTH]; + uint16_t buffer_pos; +} ps_t; + +static void +reset_ps(ps_t *dev) +{ + if (dev == NULL) { + return; + } + + dev->ack = false; + + dev->buffer[0] = 0; + dev->buffer_pos = 0; + + timer_disable(&dev->pulse_timer); + timer_disable(&dev->timeout_timer); +} + +static void +pulse_timer(void *priv) +{ + ps_t *dev = (ps_t *) priv; + + if (dev->ack) { + dev->ack = 0; + lpt_irq(dev->lpt, 1); + } + + timer_disable(&dev->pulse_timer); +} + +static int +convert_to_pdf(ps_t *dev) +{ + volatile int code; + void *instance = NULL; + wchar_t input_fn[1024], output_fn[1024], *gsargv[9]; + + input_fn[0] = 0; + wcscat(input_fn, dev->printer_path); + wcscat(input_fn, dev->filename); + + output_fn[0] = 0; + wcscat(output_fn, input_fn); + wcscpy(output_fn + wcslen(output_fn) - 3, L".pdf"); + + gsargv[0] = L""; + gsargv[1] = L"-dNOPAUSE"; + gsargv[2] = L"-dBATCH"; + gsargv[3] = L"-dSAFER"; + gsargv[4] = L"-sDEVICE=pdfwrite"; + gsargv[5] = L"-q"; + gsargv[6] = L"-o"; + gsargv[7] = output_fn; + gsargv[8] = input_fn; + + code = ghostscript_new_instance(&instance, dev); + if (code < 0) { + return code; + } + + code = ghostscript_set_arg_encoding(instance, GS_ARG_ENCODING_UTF16LE); + + if (code == 0) { + code = ghostscript_init_with_args(instance, 9, (char **) gsargv); + } + + if (code == 0 || code == gs_error_Quit) { + code = ghostscript_exit(instance); + } else { + ghostscript_exit(instance); + } + + ghostscript_delete_instance(instance); + + if (code == 0) { + plat_remove(input_fn); + } else { + plat_remove(output_fn); + } + + return code; +} + +static void +finish_document(ps_t *dev) +{ + if (ghostscript_handle != NULL) { + convert_to_pdf(dev); + } + + dev->filename[0] = 0; +} + +static void +write_buffer(ps_t *dev, bool newline) +{ + wchar_t path[1024]; + FILE *fp; + + if (dev->buffer[0] == 0) { + return; + } + + if (dev->filename[0] == 0) { + plat_tempfile(dev->filename, NULL, L".ps"); + } + + path[0] = 0; + wcscat(path, dev->printer_path); + wcscat(path, dev->filename); + + fp = plat_fopen(path, L"a"); + if (fp == NULL) { + return; + } + + fseek(fp, 0, SEEK_END); + + fprintf(fp, "%.*s%s", POSTSCRIPT_BUFFER_LENGTH, dev->buffer, newline ? "\n" : ""); + + fclose(fp); + + dev->buffer[0] = 0; + dev->buffer_pos = 0; +} + +static void +timeout_timer(void *priv) +{ + ps_t *dev = (ps_t *) priv; + + write_buffer(dev, false); + finish_document(dev); + + timer_disable(&dev->timeout_timer); +} + +static void +ps_write_data(uint8_t val, void *p) +{ + ps_t *dev = (ps_t *) p; + + if (dev == NULL) { + return; + } + + dev->data = (char) val; +} + +static bool +process_nonprintable(ps_t *dev) +{ + switch (dev->data) { + case '\b': + dev->buffer_pos--; + break; + case '\r': + dev->buffer_pos = 0; + if (dev->autofeed) + write_buffer(dev, true); + break; + case '\v': + case '\f': + case '\n': + write_buffer(dev, true); + break; + case 0x04: // Ctrl+D + write_buffer(dev, false); + finish_document(dev); + break; + + /* Characters that should be written to the buffer as-is */ + case '\t': + return false; + } + + return true; +} + +static void +process_data(ps_t *dev) +{ + if (dev->data < 0x20 || dev->data == 0x7F) { + if (process_nonprintable(dev)) { + return; + } + } + + if (dev->buffer_pos == POSTSCRIPT_BUFFER_LENGTH) { + write_buffer(dev, false); + } + + dev->buffer[dev->buffer_pos++] = dev->data; + dev->buffer[dev->buffer_pos] = 0; +} + +static void +ps_write_ctrl(uint8_t val, void *p) +{ + ps_t *dev = (ps_t *) p; + + if (dev == NULL) { + return; + } + + dev->autofeed = val & 0x02 ? true : false; + + if (val & 0x08) { + dev->select = true; + } + + if ((val & 0x04) && !(dev->ctrl & 0x04)) { + // reset printer + dev->select = false; + + reset_ps(dev); + } + + if (!(val & 0x01) && (dev->ctrl & 0x01)) { + process_data(dev); + + dev->ack = true; + + timer_set_delay_u64(&dev->pulse_timer, ISACONST); + timer_set_delay_u64(&dev->timeout_timer, 500000 * TIMER_USEC); + } + + dev->ctrl = val; +} + +static uint8_t +ps_read_status(void *p) +{ + ps_t *dev = (ps_t *) p; + uint8_t ret = 0x1f; + + ret |= 0x80; + + if (!dev->ack) { + ret |= 0x40; + } + + return(ret); +} + +static void * +ps_init(void *lpt) +{ + ps_t *dev; + gsapi_revision_t rev; + + dev = (ps_t *) malloc(sizeof(ps_t)); + memset(dev, 0x00, sizeof(ps_t)); + dev->ctrl = 0x04; + dev->lpt = lpt; + + reset_ps(dev); + + /* Try loading the DLL. */ + ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL, ghostscript_imports); + if (ghostscript_handle == NULL) { + ui_msgbox(MBX_ERROR, (wchar_t *) IDS_2123); + } else { + if (ghostscript_revision(&rev, sizeof(rev)) == 0) { + pclog("Loaded %s, rev %ld (%ld)\n", rev.product, rev.revision, rev.revisiondate); + } else { + dynld_close(ghostscript_handle); + ghostscript_handle = NULL; + } + } + + // Cache print folder path + memset(dev->printer_path, 0x00, sizeof(dev->printer_path)); + plat_append_filename(dev->printer_path, usr_path, L"printer"); + if (!plat_dir_check(dev->printer_path)) { + plat_dir_create(dev->printer_path); + } + plat_path_slash(dev->printer_path); + + timer_add(&dev->pulse_timer, pulse_timer, dev, 0); + timer_add(&dev->timeout_timer, timeout_timer, dev, 0); + + return(dev); +} + +static void +ps_close(void *p) +{ + ps_t *dev = (ps_t *) p; + + if (dev == NULL) { + return; + } + + if (dev->buffer[0] != 0) { + write_buffer(dev, false); + finish_document(dev); + } + + if (ghostscript_handle != NULL) { + dynld_close(ghostscript_handle); + ghostscript_handle = NULL; + } + + free(dev); +} + +const lpt_device_t lpt_prt_ps_device = { + name: "Generic PostScript printer", + init: ps_init, + close: ps_close, + write_data: ps_write_data, + write_ctrl: ps_write_ctrl, + read_data: NULL, + read_status: ps_read_status, + read_ctrl: NULL +}; \ No newline at end of file diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c new file mode 100644 index 000000000..aa56ae2e1 --- /dev/null +++ b/src/printer/prt_text.c @@ -0,0 +1,493 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of a generic text printer. + * + * Simple old text printers were unable to do any formatting + * of the text. They were just sheets of paper with a fixed + * size (in the U.S., this would be Letter, 8.5"x11") with a + * set of fixed margings to allow for proper operation of the + * printer mechanics. This would lead to a page being 66 lines + * of 80 characters each. + * + * Version: @(#)prt_text.c 1.0.7 2019/09/23 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018,2019 Fred N. van Kempen. + * + * 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 entire + * above 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 copyright holder 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "../pit.h" +#include "../plat.h" +#include "../lpt.h" +#include "printer.h" +#include "prt_devs.h" + + +#define FULL_PAGE 1 /* set if no top/bot margins */ + + +/* Default page values (for now.) */ +#define PAGE_WIDTH 8.5 /* standard U.S. Letter */ +#define PAGE_HEIGHT 11 +#define PAGE_LMARGIN 0.25 /* 0.25" left and right */ +#define PAGE_RMARGIN 0.25 +#if FULL_PAGE +# define PAGE_TMARGIN 0 +# define PAGE_BMARGIN 0 +#else +# define PAGE_TMARGIN 0.25 +# define PAGE_BMARGIN 0.25 +#endif +#define PAGE_CPI 10.0 /* standard 10 cpi */ +#define PAGE_LPI 6.0 /* standard 6 lpi */ + + +typedef struct { + int8_t dirty; /* has the page been printed on? */ + char pad; + + uint8_t w; /* size //INFO */ + uint8_t h; + + char *chars; /* character data */ +} psurface_t; + + +typedef struct { + const char *name; + + void * lpt; + + /* Output file name. */ + wchar_t filename[1024]; + + /* Printer timeout. */ + pc_timer_t pulse_timer; + pc_timer_t timeout_timer; + + /* page data (TODO: make configurable) */ + double page_width, /* all in inches */ + page_height, + left_margin, + top_margin, + right_margin, + bot_margin; + + /* internal page data */ + psurface_t *page; + uint8_t max_chars, + max_lines; + uint8_t curr_x, /* print head position (chars) */ + curr_y; + + /* font data */ + double cpi, /* defined chars per inch */ + lpi; /* defined lines per inch */ + + /* handshake data */ + uint8_t data; + int8_t ack; + int8_t select; + int8_t busy; + int8_t int_pending; + int8_t error; + int8_t autofeed; + uint8_t ctrl; +} prnt_t; + + +/* Dump the current page into a formatted file. */ +static void +dump_page(prnt_t *dev) +{ + wchar_t path[1024]; + uint16_t x, y; + uint8_t ch; + FILE *fp; + + /* Create the full path for this file. */ + memset(path, 0x00, sizeof(path)); + plat_append_filename(path, usr_path, L"printer"); + if (! plat_dir_check(path)) + plat_dir_create(path); + plat_path_slash(path); + wcscat(path, dev->filename); + + /* Create the file. */ + fp = plat_fopen(path, L"a"); + if (fp == NULL) { + //ERRLOG("PRNT: unable to create print page '%ls'\n", path); + return; + } + fseek(fp, 0, SEEK_END); + + /* If this is not a new file, add a formfeed first. */ + if (ftell(fp) != 0) + fputc('\014', fp); + + for (y = 0; y < dev->curr_y; y++) { + for (x = 0; x < dev->page->w; x++) { + ch = dev->page->chars[(y * dev->page->w) + x]; + if (ch == 0x00) { + /* End of line marker. */ + fputc('\n', fp); + break; + } else { + fputc(ch, fp); + } + } + } + + /* All done, close the file. */ + fclose(fp); +} + + +static void +new_page(prnt_t *dev) +{ + /* Dump the current page if needed. */ + if (dev->page->dirty) + dump_page(dev); + + /* Clear page. */ + memset(dev->page->chars, 0x00, dev->page->h * dev->page->w); + dev->curr_y = 0; + dev->page->dirty = 0; +} + + +static void +pulse_timer(void *priv) +{ + prnt_t *dev = (prnt_t *) priv; + + if (dev->ack) { + dev->ack = 0; + lpt_irq(dev->lpt, 1); + } + + timer_disable(&dev->pulse_timer); +} + + +static void +timeout_timer(void *priv) +{ + prnt_t *dev = (prnt_t *) priv; + + if (dev->page->dirty) + new_page(dev); + + timer_disable(&dev->timeout_timer); +} + + +static void +reset_printer(prnt_t *dev) +{ + /* TODO: these three should be configurable */ + dev->page_width = PAGE_WIDTH; + dev->page_height = PAGE_HEIGHT; + dev->left_margin = PAGE_LMARGIN; + dev->right_margin = PAGE_RMARGIN; + dev->top_margin = PAGE_TMARGIN; + dev->bot_margin = PAGE_BMARGIN; + dev->cpi = PAGE_CPI; + dev->lpi = PAGE_LPI; + dev->ack = 0; + + /* Default page layout. */ + dev->max_chars = (int) ((dev->page_width - dev->left_margin - dev->right_margin) * dev->cpi); + dev->max_lines = (int) ((dev->page_height -dev->top_margin - dev->bot_margin) * dev->lpi); + + dev->curr_x = dev->curr_y = 0; + + if (dev->page != NULL) + dev->page->dirty = 0; + + /* Create a file for this page. */ + plat_tempfile(dev->filename, NULL, L".txt"); + + timer_disable(&dev->pulse_timer); + timer_disable(&dev->timeout_timer); +} + + +static int +process_char(prnt_t *dev, uint8_t ch) +{ + uint8_t i; + + switch (ch) { + case 0x07: /* Beeper (BEL) */ + /* TODO: beep? */ + return 1; + + case 0x08: /* Backspace (BS) */ + if (dev->curr_x > 0) + dev->curr_x--; + return 1; + + case 0x09: /* Tab horizontally (HT) */ + /* Find tab right to current pos. */ + i = dev->curr_x; + dev->page->chars[(dev->curr_y * dev->page->w) + i++] = ' '; + while ((i < dev->max_chars) && ((i % 8) != 0)) { + dev->page->chars[(dev->curr_y * dev->page->w) + i] = ' '; + i++; + } + dev->curr_x = i; + return 1; + + case 0x0b: /* Tab vertically (VT) */ + dev->curr_x = 0; + return 1; + + case 0x0c: /* Form feed (FF) */ + new_page(dev); + return 1; + + case 0x0d: /* Carriage Return (CR) */ + dev->curr_x = 0; + if (! dev->autofeed) + return 1; + /*FALLTHROUGH*/ + + case 0x0a: /* Line feed */ + dev->curr_x = 0; + if (++dev->curr_y >= dev->max_lines) + new_page(dev); + return 1; + + case 0x0e: /* select wide printing (SO) */ + /* Ignore. */ + return 1; + + case 0x0f: /* select condensed printing (SI) */ + /* Ignore. */ + return 1; + + case 0x11: /* select printer (DC1) */ + /* Ignore. */ + return 0; + + case 0x12: /* cancel condensed printing (DC2) */ + /* Ignore. */ + return 1; + + case 0x13: /* deselect printer (DC3) */ + /* Ignore. */ + return 1; + + case 0x14: /* cancel double-width printing (one line) (DC4) */ + /* Ignore. */ + return 1; + + case 0x18: /* cancel line (CAN) */ + /* Ignore. */ + return 1; + + case 0x1b: /* ESC */ + /* Ignore. */ + return 1; + + default: + break; + } + + /* Just a printable character. */ + return(0); +} + + +static void +handle_char(prnt_t *dev) +{ + uint8_t ch = dev->data; + + if (dev->page == NULL) return; + + if (process_char(dev, ch) == 1) { + /* Command was processed. */ + return; + } + + /* Store character in the page buffer. */ + dev->page->chars[(dev->curr_y * dev->page->w) + dev->curr_x] = ch; + dev->page->dirty = 1; + + /* Update print head position. */ + if (++dev->curr_x >= dev->max_chars) { + dev->curr_x = 0; + if (++dev->curr_y >= dev->max_lines) + new_page(dev); + } +} + + +static void +write_data(uint8_t val, void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + if (dev == NULL) return; + + dev->data = val; +} + + +static void +write_ctrl(uint8_t val, void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + if (dev == NULL) return; + + /* set autofeed value */ + dev->autofeed = val & 0x02 ? 1 : 0; + + if (val & 0x08) { /* SELECT */ + /* select printer */ + dev->select = 1; + } + + if ((val & 0x04) && !(dev->ctrl & 0x04)) { + /* reset printer */ + dev->select = 0; + + reset_printer(dev); + } + + if (!(val & 0x01) && (dev->ctrl & 0x01)) { /* STROBE */ + /* Process incoming character. */ + handle_char(dev); + + /* ACK it, will be read on next READ STATUS. */ + dev->ack = 1; + + timer_set_delay_u64(&dev->pulse_timer, ISACONST); + timer_set_delay_u64(&dev->timeout_timer, 500000 * TIMER_USEC); + } + + dev->ctrl = val; +} + + +static uint8_t +read_status(void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + uint8_t ret = 0x1f; + + ret |= 0x80; + + if (!dev->ack) + ret |= 0x40; + + return(ret); +} + + +static void * +prnt_init(void *lpt) +{ + prnt_t *dev; + + /* Initialize a device instance. */ + dev = (prnt_t *)malloc(sizeof(prnt_t)); + memset(dev, 0x00, sizeof(prnt_t)); + dev->ctrl = 0x04; + dev->lpt = lpt; + + /* Initialize parameters. */ + reset_printer(dev); + + /* Create a page buffer. */ + dev->page = (psurface_t *)malloc(sizeof(psurface_t)); + dev->page->w = dev->max_chars; + dev->page->h = dev->max_lines; + dev->page->chars = (char *)malloc(dev->page->w * dev->page->h); + memset(dev->page->chars, 0x00, dev->page->w * dev->page->h); + + timer_add(&dev->pulse_timer, pulse_timer, dev, 0); + timer_add(&dev->timeout_timer, timeout_timer, dev, 0); + + return(dev); +} + + +static void +prnt_close(void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + if (dev == NULL) return; + + /* print last page if it contains data */ + if (dev->page->dirty) + dump_page(dev); + + if (dev->page != NULL) { + if (dev->page->chars != NULL) + free(dev->page->chars); + free(dev->page); + } + + free(dev); +} + + +const lpt_device_t lpt_prt_text_device = { + "Generic TEXT printer", + prnt_init, + prnt_close, + write_data, + write_ctrl, + NULL, + read_status, + NULL +}; diff --git a/src/random.c b/src/random.c index 9d7f1b229..c4f28548f 100644 --- a/src/random.c +++ b/src/random.c @@ -9,18 +9,18 @@ * A better random number generation, used for floppy weak bits * and network MAC address generation. * - * Version: @(#)random.c 1.0.3 2017/09/24 + * Version: @(#)random.c 1.0.4 2018/10/02 * * Author: Miran Grca, - * Copyright 2016,2017 Miran Grca. + * Copyright 2016-2018 Miran Grca. */ -#include #include #include -#include -#include #include "random.h" +#if !(defined(__i386__) || defined (__x86_64__)) +#include +#endif uint32_t preconst = 0x6ED9EBA1; @@ -47,6 +47,7 @@ static __inline__ uint32_t rotr32c (uint32_t x, uint32_t n) static __inline__ unsigned long long rdtsc(void) { +#if defined(__i386__) || defined (__x86_64__) unsigned hi, lo; #ifdef __MSC__ __asm { @@ -58,6 +59,9 @@ static __inline__ unsigned long long rdtsc(void) __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); #endif return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); +#else + return time(NULL); +#endif } static uint32_t RDTSC(void) diff --git a/src/rom.c b/src/rom.c index 0fbb102a4..204fd0eee 100644 --- a/src/rom.c +++ b/src/rom.c @@ -11,17 +11,16 @@ * NOTES: - pc2386 BIOS is corrupt (JMP at F000:FFF0 points to RAM) * - pc2386 video BIOS is underdumped (16k instead of 24k) * - c386sx16 BIOS fails checksum - * - the loadfont() calls should be done elsewhere * - * Version: @(#)rom.c 1.0.37 2018/05/20 + * Version: @(#)rom.c 1.0.45 2019/03/03 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #include #include @@ -31,36 +30,31 @@ #include #define HAVE_STDARG_H #include "86box.h" -#include "config.h" -#include "cpu/cpu.h" #include "mem.h" #include "rom.h" -#include "video/video.h" /* for loadfont() */ #include "plat.h" +#include "machine/machine.h" #include "machine/m_xt_xi8088.h" -int romspresent[ROM_MAX]; - - #ifdef ENABLE_ROM_LOG int rom_do_log = ENABLE_ROM_LOG; -#endif static void -rom_log(const char *format, ...) +rom_log(const char *fmt, ...) { -#ifdef ENABLE_ROM_LOG va_list ap; if (rom_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define rom_log(fmt, ...) +#endif FILE * @@ -120,6 +114,10 @@ rom_read(uint32_t addr, void *priv) rom_log("ROM: read byte from BIOS at %06lX\n", addr); #endif + if (addr < rom->mapping.base) + return 0xff; + if (addr >= (rom->mapping.base + rom->sz)) + return 0xff; return(rom->rom[addr & rom->mask]); } @@ -134,6 +132,10 @@ rom_readw(uint32_t addr, void *priv) rom_log("ROM: read word from BIOS at %06lX\n", addr); #endif + if (addr < (rom->mapping.base - 1)) + return 0xffff; + if (addr >= (rom->mapping.base + rom->sz)) + return 0xffff; return(*(uint16_t *)&rom->rom[addr & rom->mask]); } @@ -148,6 +150,10 @@ rom_readl(uint32_t addr, void *priv) rom_log("ROM: read long from BIOS at %06lX\n", addr); #endif + if (addr < (rom->mapping.base - 3)) + return 0xffffffff; + if (addr >= (rom->mapping.base + rom->sz)) + return 0xffffffff; return(*(uint32_t *)&rom->rom[addr & rom->mask]); } @@ -173,8 +179,11 @@ rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) addr &= 0x03ffff; } - (void)fseek(f, off, SEEK_SET); - (void)fread(ptr+addr, sz, 1, f); + if (ptr != NULL) { + (void)fseek(f, off, SEEK_SET); + (void)fread(ptr+addr, sz, 1, f); + } + (void)fclose(f); return(1); @@ -208,9 +217,12 @@ rom_load_linear_inverted(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *p return(0); } - (void)fseek(f, off, SEEK_SET); - (void)fread(ptr+addr+0x10000, sz >> 1, 1, f); - (void)fread(ptr+addr, sz >> 1, 1, f); + if (ptr != NULL) { + (void)fseek(f, off, SEEK_SET); + (void)fread(ptr+addr+0x10000, sz >> 1, 1, f); + (void)fread(ptr+addr, sz >> 1, 1, f); + } + (void)fclose(f); return(1); @@ -244,12 +256,15 @@ rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int off, addr &= 0x03ffff; } - (void)fseek(fl, off, SEEK_SET); - (void)fseek(fh, off, SEEK_SET); - for (c=0; c 0x0000; 0x4000 -> 0x4000; 0x6000 -> 0x4000 */ + int temp_n = n & ~MEM_GRANULARITY_MASK; + + /* 0x2000 -> 0x4000; 0x4000 -> 0x4000; 0x6000 -> 0x8000 */ + if (up && (n % MEM_GRANULARITY_SIZE)) + temp_n += MEM_GRANULARITY_SIZE; + + return temp_n; +} + + + +static uint8_t * +rom_reset(uint32_t addr, int sz) +{ + biosaddr = bios_normalize(addr, 0); + biosmask = bios_normalize(sz, 1) - 1; + if ((biosaddr + biosmask) > 0x000fffff) + biosaddr = 0x000fffff - biosmask; + + rom_log("Load BIOS: %i bytes at %08X-%08X\n", biosmask + 1, biosaddr, biosaddr + biosmask); + + /* If not done yet, allocate a 128KB buffer for the BIOS ROM. */ + if (rom != NULL) { + rom_log("ROM allocated, freeing...\n"); + free(rom); + rom = NULL; + } + rom_log("Allocating ROM...\n"); + rom = (uint8_t *)malloc(biosmask + 1); + rom_log("Filling ROM with FF's...\n"); + memset(rom, 0xff, biosmask + 1); + + return rom; +} + + +/* These four are for loading the BIOS. */ +int +bios_load(wchar_t *fn1, wchar_t *fn2, uint32_t addr, int sz, int off, int flags) +{ + uint8_t ret = 0; + uint8_t *ptr = NULL; + int i, old_sz = sz; + + /* + f0000, 65536 = prepare 64k rom starting at f0000, load 64k bios at 0000 + fe000, 65536 = prepare 64k rom starting at f0000, load 8k bios at e000 + fe000, 49152 = prepare 48k rom starting at f4000, load 8k bios at a000 + fe000, 8192 = prepare 16k rom starting at fc000, load 8k bios at 2000 + */ + if (!bios_only) + ptr = (flags & FLAG_AUX) ? rom : rom_reset(addr, sz); + + if (!(flags & FLAG_AUX) && ((addr + sz) > 0x00100000)) + sz = 0x00100000 - addr; + +#ifdef ENABLE_ROM_LOG + if (!bios_only) + rom_log("%sing %i bytes of %sBIOS starting with ptr[%08X] (ptr = %08X)\n", (bios_only) ? "Check" : "Load", sz, (flags & FLAG_AUX) ? "auxiliary " : "", addr - biosaddr, ptr); +#endif + + if (flags & FLAG_INT) + ret = rom_load_interleaved(fn1, fn2, addr - biosaddr, sz, off, ptr); + else { + if (flags & FLAG_INV) + ret = rom_load_linear_inverted(fn1, addr - biosaddr, sz, off, ptr); + else + ret = rom_load_linear(fn1, addr - biosaddr, sz, off, ptr); + } + + if (!bios_only && (flags & FLAG_REP) && (old_sz >= 65536) && (sz < old_sz)) { + old_sz /= sz; + for (i = 0; i < (old_sz - 1); i++) { + rom_log("Copying ptr[%08X] to ptr[%08X]\n", addr - biosaddr, i * sz); + memcpy(&(ptr[i * sz]), &(ptr[addr - biosaddr]), sz); + } + } + + if (!bios_only && ret && !(flags & FLAG_AUX)) + mem_add_bios(); + + return ret; +} + + +int +bios_load_linear_combined(wchar_t *fn1, wchar_t *fn2, int sz, int off) +{ + uint8_t ret = 0; + + ret = bios_load_linear(fn1, 0x000f0000, 131072, 128); + ret &= bios_load_aux_linear(fn2, 0x000e0000, sz - 65536, 128); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +int +bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, wchar_t *fn3, wchar_t *fn4, wchar_t *fn5, int sz, int off) +{ + uint8_t ret = 0; + + ret = bios_load_linear(fn3, 0x000f0000, 262144, 128); + ret &= bios_load_aux_linear(fn1, 0x000d0000, 65536, 128); + ret &= bios_load_aux_linear(fn2, 0x000c0000, 65536, 128); + ret &= bios_load_aux_linear(fn4, 0x000e0000, sz - 196608, 128); + ret &= bios_load_aux_linear(fn5, 0x000ec000, 16384, 128); + + return ret; +} +#endif + + int rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags) { + rom_log("rom_init(%08X, %08X, %08X, %08X, %08X, %08X, %08X)\n", rom, fn, addr, sz, mask, off, flags); + /* Allocate a buffer for the image. */ rom->rom = malloc(sz); memset(rom->rom, 0xff, sz); @@ -272,6 +407,7 @@ rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint return(-1); } + rom->sz = sz; rom->mask = mask; mem_mapping_add(&rom->mapping, @@ -299,6 +435,7 @@ rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int return(-1); } + rom->sz = sz; rom->mask = mask; mem_mapping_add(&rom->mapping, @@ -309,660 +446,3 @@ rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int return(0); } - - -/* Load the ROM BIOS image(s) for the selected machine into memory. */ -int -rom_load_bios(int rom_id) -{ - FILE *f; - - loadfont(L"roms/video/mda/mda.rom", 0); - - /* If not done yet, allocate a 128KB buffer for the BIOS ROM. */ - if (rom == NULL) - rom = (uint8_t *)malloc(131072); - memset(rom, 0xff, 131072); - - /* Default to a 64K ROM BIOS image. */ - biosmask = 0xffff; - - /* Zap the BIOS ROM EXTENSION area. */ - memset(romext, 0xff, 0x8000); - mem_mapping_disable(&romext_mapping); - - switch (rom_id) { - case ROM_IBMPC: /* IBM PC */ - if (! rom_load_linear( - L"roms/machines/ibmpc/pc102782.bin", - 0x00e000, 8192, 0, rom)) break; - - /* Try to load the (full) BASIC ROM. */ - if (rom_load_linear( - L"roms/machines/ibmpc/ibm-basic-1.10.rom", - 0x006000, 32768, 0, rom)) return(1); - - /* Nope. Try to load the first BASIC ROM image. */ - if (! rom_load_linear( - L"roms/machines/ibmpc/basicc11.f6", - 0x006000, 8192, 0, rom)) return(1); /* nope */ - if (! rom_load_linear( - L"roms/machines/ibmpc/basicc11.f8", - 0x008000, 8192, 0, rom)) break; /* nope */ - if (! rom_load_linear( - L"roms/machines/ibmpc/basicc11.fa", - 0x00a000, 8192, 0, rom)) break; /* nope */ - if (! rom_load_linear( - L"roms/machines/ibmpc/basicc11.fc", - 0x00c000, 8192, 0, rom)) break; /* nope */ - return(1); - - case ROM_IBMXT: /* IBM PX-XT */ - if (rom_load_linear( - L"roms/machines/ibmxt/xt.rom", - 0x000000, 65536, 0, rom)) return(1); - - if (! rom_load_linear( - L"roms/machines/ibmxt/5000027.u19", - 0x000000, 32768, 0, rom)) break; - if (rom_load_linear( - L"roms/machines/ibmxt/1501512.u18", - 0x008000, 32768, 0, rom)) return(1); - break; - - case ROM_XI8088: - if (rom_load_linear_inverted( - L"roms/machines/xi8088/bios-xi8088.bin", - 0x000000, 131072, 0, rom)) { - biosmask = 0x1ffff; - xi8088_bios_128kb_set(1); - return(1); - } else { - if (rom_load_linear( - L"roms/machines/xi8088/bios-xi8088.bin", - 0x000000, 65536, 0, rom)) { - xi8088_bios_128kb_set(0); - return(1); - } - } - break; - - case ROM_IBMXT286: /* IBM PX-XT 286 */ - if (rom_load_interleaved( - L"roms/machines/ibmxt286/bios_5162_21apr86_u34_78x7460_27256.bin", - L"roms/machines/ibmxt286/bios_5162_21apr86_u35_78x7461_27256.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_IBMPCJR: /* IBM PCjr */ - if (rom_load_linear( - L"roms/machines/ibmpcjr/bios.rom", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_IBMAT: /* IBM PC-AT */ - if (rom_load_interleaved( - L"roms/machines/ibmat/62x0820.u27", - L"roms/machines/ibmat/62x0821.u47", - 0x000000, 65536, 0, rom)) return(1); - break; - -#ifdef WALTJE - case ROM_OPENAT: /* PC/AT clone with OpenBIOS */ - if (rom_load_linear( - L"roms/machines/open_at/bios.bin", - 0x000000, 65536, 0, rom)) return(1); - break; -#endif - - case ROM_GENXT: /* Generic PC-XT clone */ - if (rom_load_linear( - L"roms/machines/genxt/pcxt.rom", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_PC1512: /* Amstrad PC-1512 */ - if (! rom_load_interleaved( - L"roms/machines/pc1512/40044", - L"roms/machines/pc1512/40043", - 0x00c000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc1512/40078", L"rb"); - if (f == NULL) break; - (void)fclose(f); - return(1); - - case ROM_PC1640: /* Amstrad PC-1640 */ - if (! rom_load_interleaved( - L"roms/machines/pc1640/40044.v3", - L"roms/machines/pc1640/40043.v3", - 0x00c000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc1640/40100", L"rb"); - if (f == NULL) break; - (void)fclose(f); - return(1); - - case ROM_PC200: - if (! rom_load_interleaved( - L"roms/machines/pc200/pc20v2.1", - L"roms/machines/pc200/pc20v2.0", - 0x00c000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc200/40109", L"rb"); - if (f == NULL) break; - (void)fclose(f); - return(1); - - case ROM_TANDY: - if (rom_load_linear( - L"roms/machines/tandy/tandy1t1.020", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_TANDY1000HX: - if (! rom_load_linear( - L"roms/machines/tandy1000hx/v020000.u12", - 0x000000, 0x20000, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_TANDY1000SL2: - if (rom_load_interleaved( - L"roms/machines/tandy1000sl2/8079047.hu1", - L"roms/machines/tandy1000sl2/8079048.hu2", - 0x000000, 65536, 0x30000/2, rom)) return(1); - break; - - case ROM_PORTABLE: - if (rom_load_linear( - L"roms/machines/portable/compaq portable plus 100666-001 rev c u47.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_PORTABLEII: - if (! rom_load_interleaved( - L"roms/machines/portableii/109740-001.rom", - L"roms/machines/portableii/109739-001.rom", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); - -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - case ROM_PORTABLEIII: - case ROM_PORTABLEIII386: - if (rom_load_interleaved( - L"roms/machines/portableiii/109738-002.bin", - L"roms/machines/portableiii/109737-002.bin", - 0x000000, 65536, 0, rom)) return(1); - break; -#endif - - case ROM_DTKXT: - if (rom_load_linear( - L"roms/machines/dtk/dtk_erso_2.42_2764.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_OLIM24: - if (rom_load_interleaved( - L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_low.bin", - L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_high.bin", - 0x00c000, 16384, 0, rom)) return(1); - break; - - case ROM_PC2086: - if (! rom_load_interleaved( - L"roms/machines/pc2086/40179.ic129", - L"roms/machines/pc2086/40180.ic132", - 0x000000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc2086/40186.ic171", L"rb"); - if (f == NULL) break; - (void)fclose(f); - biosmask = 0x3fff; - return(1); - - case ROM_PC3086: - if (! rom_load_linear( - L"roms/machines/pc3086/fc00.bin", - 0x000000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc3086/c000.bin", L"rb"); - if (f == NULL) break; - (void)fclose(f); - biosmask = 0x3fff; - return(1); - - case ROM_CMDPC30: - if (! rom_load_interleaved( - L"roms/machines/cmdpc30/commodore pc 30 iii even.bin", - L"roms/machines/cmdpc30/commodore pc 30 iii odd.bin", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); - - case ROM_AMI386SX: - if (rom_load_linear( - L"roms/machines/ami386/ami386.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AMI386DX_OPTI495: /* uses the OPTi 82C495 chipset */ - if (rom_load_linear( - L"roms/machines/ami386dx/opt495sx.ami", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_MR386DX_OPTI495: /* uses the OPTi 82C495 chipset */ - if (rom_load_linear( - L"roms/machines/mr386dx/opt495sx.mr", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AWARD386SX_OPTI495: /* uses the OPTi 82C495 chipset */ - case ROM_AWARD386DX_OPTI495: /* uses the OPTi 82C495 chipset */ - case ROM_AWARD486_OPTI495: /* uses the OPTi 82C495 chipset */ - if (rom_load_linear( - L"roms/machines/award495/opt495s.awa", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AMI286: - if (rom_load_linear( - L"roms/machines/ami286/amic206.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AWARD286: - if (rom_load_linear( - L"roms/machines/award286/award.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_EUROPC: - if (rom_load_linear( - L"roms/machines/europc/50145", - 0x008000, 32768, 0, rom)) return(1); - break; - - case ROM_MEGAPC: - case ROM_MEGAPCDX: - if (rom_load_interleaved( - L"roms/machines/megapc/41651-bios lo.u18", - L"roms/machines/megapc/211253-bios hi.u19", - 0x000000, 65536, 0x08000, rom)) return(1); - break; - - case ROM_AMI486: - if (rom_load_linear( - L"roms/machines/ami486/ami486.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_WIN486: - if (rom_load_linear( - L"roms/machines/win486/ali1429g.amw", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_430VX: - if (! rom_load_linear( - L"roms/machines/430vx/55xwuq0e.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_REVENGE: - if (! rom_load_linear( - L"roms/machines/revenge/1009af2_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/revenge/1009af2_.bi1", - 0x000000, 0x00c000, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_ENDEAVOR: - if (! rom_load_linear( - L"roms/machines/endeavor/1006cb0_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/endeavor/1006cb0_.bi1", - 0x000000, 0x00d000, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS1_2011: - if (! rom_load_linear( - L"roms/machines/ibmps1es/f80000.bin", - 0x000000, 131072, 0x60000, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS1_2121: - case ROM_IBMPS1_2121_ISA: - if (! rom_load_linear( - L"roms/machines/ibmps1_2121/fc0000.bin", - 0x000000, 131072, 0x20000, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS1_2133: - if (! rom_load_linear( - L"roms/machines/ibmps1_2133/ps1_2133_52g2974_rom.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - case ROM_DESKPRO_386: - if (! rom_load_interleaved( - L"roms/machines/deskpro386/109592-005.u11.bin", - L"roms/machines/deskpro386/109591-005.u13.bin", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); -#endif - - case ROM_AMIXT: - if (rom_load_linear( - L"roms/machines/amixt/ami_8088_bios_31jan89.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - -#if defined(DEV_BRANCH) && defined(USE_LASERXT) - case ROM_LTXT: - if (rom_load_linear( - L"roms/machines/ltxt/27c64.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_LXT3: - if (rom_load_linear( - L"roms/machines/lxt3/27c64d.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; -#endif - - case ROM_GW286CT: - if (rom_load_linear( - L"roms/machines/gw286ct/2ctc001.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_SPC4200P: /* Samsung SPC-4200P */ - if (rom_load_linear( - L"roms/machines/spc4200p/u8.01", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_SPC4216P: - if (! rom_load_interleaved( - L"roms/machines/spc4216p/7101.u8", - L"roms/machines/spc4216p/ac64.u10", - 0x000000, 65536, 0, rom)) break; - return(1); - - case ROM_KMXC02: - if (rom_load_linear( - L"roms/machines/kmxc02/3ctm005.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_SUPER286TR: /* Hyundai Super-286TR */ - if (rom_load_linear( - L"roms/machines/super286tr/hyundai_award286.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_DTK386: /* uses NEAT chipset */ - if (rom_load_linear( - L"roms/machines/dtk386/3cto001.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_PXXT: - if (rom_load_linear( - L"roms/machines/pxxt/000p001.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_JUKOPC: - if (rom_load_linear( - L"roms/machines/jukopc/000o001.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_IBMPS2_M30_286: - if (! rom_load_linear( - L"roms/machines/ibmps2_m30_286/33f5381a.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS2_M70_TYPE3: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m70_type3/70-a_even.bin", - L"roms/machines/ibmps2_m70_type3/70-a_odd.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS2_M70_TYPE4: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m70_type4/70-b_even.bin", - L"roms/machines/ibmps2_m70_type4/70-b_odd.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_DTK486: - if (rom_load_linear( - L"roms/machines/dtk486/4siw005.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_R418: - if (! rom_load_linear( - L"roms/machines/r418/r418i.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - -#if 0 - case ROM_586MC1: - if (! rom_load_linear( - L"roms/machines/586mc1/is.34", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); -#endif - - case ROM_PLATO: - if (! rom_load_linear( - L"roms/machines/plato/1016ax1_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/plato/1016ax1_.bi1", - 0x000000, 0x00d000, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_MB500N: - if (! rom_load_linear( - L"roms/machines/mb500n/031396s.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_AP53: - if (! rom_load_linear( - L"roms/machines/ap53/ap53r2c0.rom", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P55T2S: - if (! rom_load_linear( - L"roms/machines/p55t2s/s6y08t.rom", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_PRESIDENT: - if (! rom_load_linear( - L"roms/machines/president/bios.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P54TP4XE: - if (! rom_load_linear( - L"roms/machines/p54tp4xe/t15i0302.awd", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_ACERM3A: - if (! rom_load_linear( - L"roms/machines/acerm3a/r01-b3.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_ACERV35N: - if (! rom_load_linear( - L"roms/machines/acerv35n/v35nd1s1.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P55VA: - if (! rom_load_linear( - L"roms/machines/p55va/va021297.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P55T2P4: - if (! rom_load_linear( - L"roms/machines/p55t2p4/0207_j2.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P55TVP4: - if (! rom_load_linear( - L"roms/machines/p55tvp4/tv5i0204.awd", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - -#if defined(DEV_BRANCH) && defined(USE_I686) - case ROM_440FX: /* working Tyan BIOS */ - if (! rom_load_linear( - L"roms/machines/440fx/ntmaw501.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_S1668: /* working Tyan BIOS */ - if (! rom_load_linear( - L"roms/machines/tpatx/s1668p.rom", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); -#endif - - case ROM_THOR: - if (! rom_load_linear( - L"roms/machines/thor/1006cn0_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/thor/1006cn0_.bi1", - 0x000000, 65536, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) - case ROM_MRTHOR: - if (! rom_load_linear( - L"roms/machines/mrthor/mr_atx.bio", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); -#endif - - case ROM_PB640: - if (! rom_load_linear( - L"roms/machines/pb640/1007CP0R.BIO", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/pb640/1007CP0R.BI1", - 0x000000, 0x00d000, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_ZAPPA: - if (! rom_load_linear( - L"roms/machines/zappa/1006bs0_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/zappa/1006bs0_.bi1", - 0x000000, 65536, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS2_M50: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m50/90x7423.zm14", - L"roms/machines/ibmps2_m50/90x7426.zm16", - 0x000000, 65536, 0, rom)) break; - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m50/90x7420.zm13", - L"roms/machines/ibmps2_m50/90x7429.zm18", - 0x010000, 65536, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS2_M55SX: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m55sx/33f8146.zm41", - L"roms/machines/ibmps2_m55sx/33f8145.zm40", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS2_M80: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m80/15f6637.bin", - L"roms/machines/ibmps2_m80/15f6639.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_T1000: - loadfont(L"roms/machines/t1000/t1000font.bin", 2); - if (!rom_load_linear( - L"roms/machines/t1000/t1000.rom", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); - - case ROM_T1200: - loadfont(L"roms/machines/t1200/t1000font.bin", 2); - if (!rom_load_linear( - L"roms/machines/t1200/t1200_019e.ic15.bin", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); - - case ROM_T3100E: - loadfont(L"roms/machines/t3100e/t3100e_font.bin", 5); - if (rom_load_linear( - L"roms/machines/t3100e/t3100e.rom", - 0x000000, 65536, 0, rom)) return(1); - break; - - default: - rom_log("ROM: don't know how to handle ROM set %d !\n", rom_id); - } - - return(0); -} diff --git a/src/rom.h b/src/rom.h index 095ddb1d3..38cd033b0 100644 --- a/src/rom.h +++ b/src/rom.h @@ -8,167 +8,39 @@ * * Definitions for the ROM image handler. * - * Version: @(#)rom.h 1.0.17 2018/05/10 + * Version: @(#)rom.h 1.0.23 2019/03/03 * * Author: Fred N. van Kempen, - * Copyright 2018 Fred N. van Kempen. + * Copyright 2018,2019 Fred N. van Kempen. */ #ifndef EMU_ROM_H # define EMU_ROM_H -#define PCJR (romset==ROM_IBMPCJR) -#if defined(DEV_BRANCH) && defined(USE_GREENB) -#define AMIBIOS (romset==ROM_AMI386SX || \ - romset==ROM_AMI486 || \ - romset==ROM_WIN486 || \ - romset==ROM_4GPV31) -#else -#define AMIBIOS (romset==ROM_AMI386SX || \ - romset==ROM_AMI486 || \ - romset==ROM_WIN486) -#endif +#define FLAG_INT 1 +#define FLAG_INV 2 +#define FLAG_AUX 4 +#define FLAG_REP 8 + + +#define bios_load_linear(a, b, c, d) bios_load(a, NULL, b, c, d, 0) +#define bios_load_linearr(a, b, c, d) bios_load(a, NULL, b, c, d, FLAG_REP) +#define bios_load_aux_linear(a, b, c, d) bios_load(a, NULL, b, c, d, FLAG_AUX) +#define bios_load_linear_inverted(a, b, c, d) bios_load(a, NULL, b, c, d, FLAG_INV) +#define bios_load_aux_linear_inverted(a, b, c, d) bios_load(a, NULL, b, c, d, FLAG_INV | FLAG_AUX) +#define bios_load_interleaved(a, b, c, d, e) bios_load(a, b, c, d, e, FLAG_INT) +#define bios_load_interleavedr(a, b, c, d, e) bios_load(a, b, c, d, e, FLAG_INT | FLAG_REP) +#define bios_load_aux_interleaved(a, b, c, d, e) bios_load(a, b, c, d, e, FLAG_INT | FLAG_AUX) typedef struct { uint8_t *rom; + int sz; uint32_t mask; mem_mapping_t mapping; } rom_t; -enum { - ROM_IBMPC = 0, /* 301 keyboard error, 131 cassette (!!!) error */ - ROM_AMIXT, /* XT Clone with AMI BIOS */ - ROM_DTKXT, - ROM_IBMXT, /* 301 keyboard error */ - ROM_GENXT, /* 'Generic XT BIOS' */ - ROM_JUKOPC, - ROM_PORTABLE, - ROM_PXXT, -#if defined(DEV_BRANCH) && defined(USE_LASERXT) - ROM_LTXT, - - ROM_LXT3, -#endif - - ROM_T1000, - ROM_T1200, - - ROM_XI8088, - - ROM_IBMPCJR, - ROM_TANDY, - ROM_TANDY1000HX, - ROM_EUROPC, - ROM_PC1512, - ROM_PC1640, - ROM_PC200, - ROM_PC2086, - ROM_PC3086, - ROM_OLIM24, - ROM_TANDY1000SL2, - - ROM_T3100E, - - ROM_AMI286, - ROM_AWARD286, - ROM_CMDPC30, - ROM_PORTABLEII, -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - ROM_PORTABLEIII, -#endif - ROM_GW286CT, - ROM_SUPER286TR, /* Hyundai Super-286TR/SCAT/Award */ - ROM_IBMAT, - ROM_IBMPS1_2011, - ROM_IBMPS2_M30_286, - ROM_IBMXT286, - ROM_SPC4200P, /* Samsung SPC-4200P/SCAT/Phoenix */ - ROM_SPC4216P, /* Samsung SPC-4216P/SCAT */ -#ifdef WALTJE - ROM_OPENAT, /* PC/AT clone with Open BIOS */ -#endif - - ROM_IBMPS2_M50, - - ROM_AMI386SX, - ROM_KMXC02, - ROM_MEGAPC, - ROM_AWARD386SX_OPTI495, -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - ROM_DESKPRO_386, -#endif - ROM_DTK386, - ROM_IBMPS1_2121, - ROM_IBMPS1_2121_ISA,/* IBM PS/1 Model 2121 with ISA expansion bus */ -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - ROM_PORTABLEIII386, -#endif - - ROM_IBMPS2_M55SX, - - ROM_AMI386DX_OPTI495, - ROM_MEGAPCDX, /* 386DX mdl - Note: documentation (in German) clearly says such a model exists */ - ROM_AWARD386DX_OPTI495, - ROM_MR386DX_OPTI495, - - ROM_IBMPS2_M80, - - ROM_AMI486, - ROM_WIN486, -#ifdef UNIMPLEMENTED_MACHINES - ROM_VLI486SV2G, /* ASUS VL/I-486SV2G/SiS 471/Award/SiS 85C471 */ /* 51 */ -#endif - ROM_AWARD486_OPTI495, - ROM_DTK486, /* DTK PKM-0038S E-2/SiS 471/Award/SiS 85C471 */ - ROM_IBMPS1_2133, - - ROM_IBMPS2_M70_TYPE3, - ROM_IBMPS2_M70_TYPE4, - - ROM_R418, /* Rise Computer R418/SiS 496/497/Award/SMC FDC37C665 */ - - ROM_REVENGE, /* Intel Premiere/PCI I/430LX/AMI/SMC FDC37C665 */ - - ROM_PLATO, /* Intel Premiere/PCI II/430NX/AMI/SMC FDC37C665 */ - - ROM_P54TP4XE, /* ASUS P/I-P55TP4XE/430FX/Award/SMC FDC37C665 */ - ROM_ENDEAVOR, /* Intel Advanced_EV/430FX/AMI/NS PC87306 */ - ROM_ZAPPA, /* Intel Advanced_ZP/430FX/AMI/NS PC87306 */ -#ifdef UNIMPLEMENTED_MACHINES - ROM_POWERMATE_V, /* NEC PowerMate V/430FX/Phoenix/SMC FDC37C66 5*/ -#endif - ROM_MB500N, /* PC Partner MB500N/430FX/Award/SMC FDC37C665 */ - ROM_PRESIDENT, /* President Award 430FX PCI/430FX/Award/Unknown SIO */ - - ROM_THOR, /* Intel Advanced_ATX/430FX/AMI/NS PC87306 */ -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) - ROM_MRTHOR, /* Intel Advanced_ATX/430FX/MR.BIOS/NS PC87306 */ -#endif - ROM_PB640, /* Packard Bell PB640/430FX/AMI/NS PC87306 */ - - ROM_ACERM3A, /* Acer M3A/430HX/Acer/SMC FDC37C932FR */ - ROM_ACERV35N, /* Acer V35N/430HX/Acer/SMC FDC37C932FR */ - ROM_AP53, /* AOpen AP53/430HX/AMI/SMC FDC37C665/669 */ - ROM_P55T2P4, /* ASUS P/I-P55T2P4/430HX/Award/Winbond W8387F*/ - ROM_P55T2S, /* ASUS P/I-P55T2S/430HX/AMI/NS PC87306 */ - - ROM_P55TVP4, /* ASUS P/I-P55TVP4/430HX/Award/Winbond W8387F*/ - ROM_430VX, /* Award 430VX PCI/430VX/Award/UMC UM8669F*/ - ROM_P55VA, /* Epox P55-VA/430VX/Award/SMC FDC37C932FR*/ - -#if defined(DEV_BRANCH) && defined(USE_I686) - ROM_440FX, /* Tyan Titan-Pro AT/440FX/Award BIOS/SMC FDC37C665 */ - ROM_S1668, /* Tyan Titan-Pro ATX/440FX/AMI/SMC FDC37C669 */ -#endif - - ROM_MAX -}; - - -extern int romspresent[ROM_MAX]; - extern uint8_t rom_read(uint32_t addr, void *p); extern uint16_t rom_readw(uint32_t addr, void *p); extern uint32_t rom_readl(uint32_t addr, void *p); @@ -182,6 +54,16 @@ extern int rom_load_linear(wchar_t *fn, uint32_t addr, int sz, extern int rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int off, uint8_t *ptr); +extern int bios_load(wchar_t *fn1, wchar_t *fn2, uint32_t addr, int sz, + int off, int flags); +extern int bios_load_linear_combined(wchar_t *fn1, wchar_t *fn2, + int sz, int off); +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +extern int bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, + wchar_t *fn3, wchar_t *fn4, wchar_t *fn5, + int sz, int off); +#endif + extern int rom_init(rom_t *rom, wchar_t *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); extern int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, @@ -189,7 +71,5 @@ extern int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, int size, int mask, int file_offset, uint32_t flags); -extern int rom_load_bios(int rom_id); - #endif /*EMU_ROM_H*/ diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index 8fc535dc3..c23e7f83d 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -8,7 +8,7 @@ * * Handling of the SCSI controllers. * - * Version: @(#)scsi.c 1.0.20 2018/06/02 + * Version: @(#)scsi.c 1.0.25 2018/10/31 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -25,39 +25,27 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../mem.h" -#include "../rom.h" -#include "../timer.h" #include "../device.h" #include "../disk/hdc.h" #include "../disk/hdd.h" #include "../plat.h" #include "scsi.h" +#include "scsi_device.h" #include "../cdrom/cdrom.h" #include "../disk/zip.h" #include "scsi_disk.h" -#include "scsi_device.h" #include "scsi_aha154x.h" #include "scsi_buslogic.h" #include "scsi_ncr5380.h" -#include "scsi_ncr53c810.h" +#include "scsi_ncr53c8xx.h" #ifdef WALTJE # include "scsi_wd33c93.h" #endif -#include "scsi_x54x.h" -scsi_device_t SCSIDevices[SCSI_ID_MAX]; -char scsi_fn[SCSI_NUM][512]; -uint16_t scsi_disk_location[SCSI_NUM]; - int scsi_card_current = 0; int scsi_card_last = 0; -uint32_t SCSI_BufferLength; -static volatile -mutex_t *scsiMutex; - typedef const struct { const char *name; @@ -67,48 +55,32 @@ typedef const struct { static SCSI_CARD scsi_cards[] = { - { "None", "none", NULL, }, - { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, }, - { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, }, - { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, }, - { "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, }, - { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device,}, - { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device,}, - { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, - { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, - { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, + { "None", "none", NULL, }, + { "[ISA] Adaptec AHA-154xA", "aha154xa", &aha154xa_device, }, + { "[ISA] Adaptec AHA-154xB", "aha154xb", &aha154xb_device, }, + { "[ISA] Adaptec AHA-154xC", "aha154xc", &aha154xc_device, }, + { "[ISA] Adaptec AHA-154xCF", "aha154xcf", &aha154xcf_device, }, + { "[ISA] BusLogic BT-542B", "bt542b", &buslogic_542b_1991_device, }, + { "[ISA] BusLogic BT-542BH", "bt542bh", &buslogic_device, }, + { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device, }, + { "[ISA] Longshine LCS-6821N", "lcs6821n", &scsi_lcs6821n_device, }, + { "[ISA] Rancho RT1000B", "rt1000b", &scsi_rt1000b_device, }, + { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, #ifdef WALTJE - { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, + { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, + { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, #endif - { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, - { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device,}, - { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, - { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device,}, - { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device,}, - { "", "", NULL, }, + { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, + { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device, }, + { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, + { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device, }, + //{ "[PCI] NCR 53C825A", "ncr53c825a", &ncr53c825a_pci_device, }, + { "[PCI] NCR 53C875", "ncr53c875", &ncr53c875_pci_device, }, + { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device, }, + { "", "", NULL, }, }; -#ifdef ENABLE_SCSI_LOG -int scsi_do_log = ENABLE_SCSI_LOG; -#endif - - -static void -scsi_log(const char *fmt, ...) -{ -#ifdef ENABLE_SCSI_LOG - va_list ap; - - if (scsi_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - int scsi_card_available(int card) { if (scsi_cards[card].device) @@ -158,78 +130,22 @@ int scsi_card_get_from_internal_name(char *s) } -void scsi_mutex(uint8_t start) -{ - if (start) - scsiMutex = thread_create_mutex(L"86Box.SCSIMutex"); - else - thread_close_mutex((mutex_t *) scsiMutex); -} - - void scsi_card_init(void) { int i; + scsi_device_t *dev; if (!scsi_cards[scsi_card_current].device) return; - scsi_log("Building SCSI hard disk map...\n"); - build_scsi_disk_map(); - scsi_log("Building SCSI CD-ROM map...\n"); - build_scsi_cdrom_map(); - scsi_log("Building SCSI ZIP map...\n"); - build_scsi_zip_map(); + for (i = 0; i < SCSI_ID_MAX; i++) { + dev = &(scsi_devices[i]); - for (i=0; itype = SCSI_NONE; } device_add(scsi_cards[scsi_card_current].device); scsi_card_last = scsi_card_current; } - - -/* Initialization function for the SCSI layer */ -void SCSIReset(uint8_t id) -{ - uint8_t cdrom_id = scsi_cdrom_drives[id]; - uint8_t zip_id = scsi_zip_drives[id]; - uint8_t hdc_id = scsi_disks[id]; - - if (hdc_id != 0xff) - SCSIDevices[id].LunType = SCSI_DISK; - else if (cdrom_id != 0xff) - SCSIDevices[id].LunType = SCSI_CDROM; - else if (zip_id != 0xff) - SCSIDevices[id].LunType = SCSI_ZIP; - else - SCSIDevices[id].LunType = SCSI_NONE; - - scsi_device_reset(id); - - if (SCSIDevices[id].CmdBuffer) - free(SCSIDevices[id].CmdBuffer); - SCSIDevices[id].CmdBuffer = NULL; -} - - -void -scsi_mutex_wait(uint8_t wait) -{ - if (wait) - thread_wait_mutex((mutex_t *) scsiMutex); - else - thread_release_mutex((mutex_t *) scsiMutex); -} diff --git a/src/scsi/scsi.h b/src/scsi/scsi.h index ab01692d5..011d2569a 100644 --- a/src/scsi/scsi.h +++ b/src/scsi/scsi.h @@ -8,7 +8,7 @@ * * SCSI controller handler header. * - * Version: @(#)scsi_h 1.0.17 2018/06/02 + * Version: @(#)scsi_h 1.0.19 2018/10/02 * * Authors: TheCollector1995, * Miran Grca, @@ -21,347 +21,16 @@ #ifndef EMU_SCSI_H #define EMU_SCSI_H - -#ifdef WALTJE -#define SCSI_TIME (50 * (1 << TIMER_SHIFT)) -#else -#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) -#endif - - -/* Configuration. */ -#define SCSI_ID_MAX 16 /* 16 on wide buses */ -#define SCSI_LUN_MAX 8 /* always 8 */ - - -/* SCSI commands. */ -#define GPCMD_TEST_UNIT_READY 0x00 -#define GPCMD_REZERO_UNIT 0x01 -#define GPCMD_REQUEST_SENSE 0x03 -#define GPCMD_FORMAT_UNIT 0x04 -#define GPCMD_IOMEGA_SENSE 0x06 -#define GPCMD_READ_6 0x08 -#define GPCMD_WRITE_6 0x0a -#define GPCMD_SEEK_6 0x0b -#define GPCMD_IOMEGA_SET_PROTECTION_MODE 0x0c -#define GPCMD_IOMEGA_EJECT 0x0d /* ATAPI only? */ -#define GPCMD_INQUIRY 0x12 -#define GPCMD_VERIFY_6 0x13 -#define GPCMD_MODE_SELECT_6 0x15 -#define GPCMD_SCSI_RESERVE 0x16 -#define GPCMD_SCSI_RELEASE 0x17 -#define GPCMD_MODE_SENSE_6 0x1a -#define GPCMD_START_STOP_UNIT 0x1b -#define GPCMD_SEND_DIAGNOSTIC 0x1d -#define GPCMD_PREVENT_REMOVAL 0x1e -#define GPCMD_READ_FORMAT_CAPACITIES 0x23 -#define GPCMD_READ_CDROM_CAPACITY 0x25 -#define GPCMD_READ_10 0x28 -#define GPCMD_WRITE_10 0x2a -#define GPCMD_SEEK_10 0x2b -#define GPCMD_WRITE_AND_VERIFY_10 0x2e -#define GPCMD_VERIFY_10 0x2f -#define GPCMD_READ_BUFFER 0x3c -#define GPCMD_WRITE_SAME_10 0x41 -#define GPCMD_READ_SUBCHANNEL 0x42 -#define GPCMD_READ_TOC_PMA_ATIP 0x43 -#define GPCMD_READ_HEADER 0x44 -#define GPCMD_PLAY_AUDIO_10 0x45 -#define GPCMD_GET_CONFIGURATION 0x46 -#define GPCMD_PLAY_AUDIO_MSF 0x47 -#define GPCMD_PLAY_AUDIO_TRACK_INDEX 0x48 -#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_READ_TRACK_INFORMATION 0x52 -#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_WRITE_12 0xaa -#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ -#define GPCMD_WRITE_AND_VERIFY_12 0xae -#define GPCMD_VERIFY_12 0xaf -#define GPCMD_PLAY_CD_OLD 0xb4 -#define GPCMD_READ_CD_OLD 0xb8 -#define GPCMD_READ_CD_MSF 0xb9 -#define GPCMD_SCAN 0xba -#define GPCMD_SET_SPEED 0xbb -#define GPCMD_PLAY_CD 0xbc -#define GPCMD_MECHANISM_STATUS 0xbd -#define GPCMD_READ_CD 0xbe -#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ -#define GPCMD_PAUSE_RESUME_ALT 0xc2 -#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */ -#define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ - -/* 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 - -/* Mode page codes for presence */ -#define GPMODEP_R_W_ERROR_PAGE 0x0000000000000002LL -#define GPMODEP_CDROM_PAGE 0x0000000000002000LL -#define GPMODEP_CDROM_AUDIO_PAGE 0x0000000000004000LL -#define GPMODEP_CAPABILITIES_PAGE 0x0000040000000000LL -#define GPMODEP_ALL_PAGES 0x8000000000000000LL - -/* SCSI Status Codes */ -#define SCSI_STATUS_OK 0 -#define SCSI_STATUS_CHECK_CONDITION 2 - -/* SCSI Sense Keys */ -#define SENSE_NONE 0 -#define SENSE_NOT_READY 2 -#define SENSE_ILLEGAL_REQUEST 5 -#define SENSE_UNIT_ATTENTION 6 - -/* SCSI Additional Sense Codes */ -#define ASC_AUDIO_PLAY_OPERATION 0x00 -#define ASC_NOT_READY 0x04 -#define ASC_ILLEGAL_OPCODE 0x20 -#define ASC_LBA_OUT_OF_RANGE 0x21 -#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 -#define ASC_INV_LUN 0x25 -#define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26 -#define ASC_WRITE_PROTECTED 0x27 -#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 -#define ASC_CAPACITY_DATA_CHANGED 0x2A -#define ASC_INCOMPATIBLE_FORMAT 0x30 -#define ASC_MEDIUM_NOT_PRESENT 0x3a -#define ASC_DATA_PHASE_ERROR 0x4b -#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 - -#define ASCQ_UNIT_IN_PROCESS_OF_BECOMING_READY 0x01 -#define ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02 -#define ASCQ_CAPACITY_DATA_CHANGED 0x09 -#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 /* 0x2C2 */ - -#define BUFFER_SIZE (256*1024) - -#define RW_DELAY (TIMER_USEC * 500) - -/* Some generally useful CD-ROM information */ -#define CD_MINS 75 /* max. minutes per CD */ -#define CD_SECS 60 /* seconds per minute */ -#define CD_FRAMES 75 /* frames per second */ -#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ -#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) -#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) - -/* Event notification classes for GET EVENT STATUS NOTIFICATION */ -#define GESN_NO_EVENTS 0 -#define GESN_OPERATIONAL_CHANGE 1 -#define GESN_POWER_MANAGEMENT 2 -#define GESN_EXTERNAL_REQUEST 3 -#define GESN_MEDIA 4 -#define GESN_MULTIPLE_HOSTS 5 -#define GESN_DEVICE_BUSY 6 - -/* Event codes for MEDIA event status notification */ -#define MEC_NO_CHANGE 0 -#define MEC_EJECT_REQUESTED 1 -#define MEC_NEW_MEDIA 2 -#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ -#define MEC_MEDIA_CHANGED 4 /* only for media changers */ -#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ -#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ -#define MS_TRAY_OPEN 1 -#define MS_MEDIA_PRESENT 2 - -/* - * The MMC values are not IDE specific and might need to be moved - * to a common header if they are also needed for the SCSI emulation - */ - -/* Profile list from MMC-6 revision 1 table 91 */ -#define MMC_PROFILE_NONE 0x0000 -#define MMC_PROFILE_CD_ROM 0x0008 -#define MMC_PROFILE_CD_R 0x0009 -#define MMC_PROFILE_CD_RW 0x000A -#define MMC_PROFILE_DVD_ROM 0x0010 -#define MMC_PROFILE_DVD_R_SR 0x0011 -#define MMC_PROFILE_DVD_RAM 0x0012 -#define MMC_PROFILE_DVD_RW_RO 0x0013 -#define MMC_PROFILE_DVD_RW_SR 0x0014 -#define MMC_PROFILE_DVD_R_DL_SR 0x0015 -#define MMC_PROFILE_DVD_R_DL_JR 0x0016 -#define MMC_PROFILE_DVD_RW_DL 0x0017 -#define MMC_PROFILE_DVD_DDR 0x0018 -#define MMC_PROFILE_DVD_PLUS_RW 0x001A -#define MMC_PROFILE_DVD_PLUS_R 0x001B -#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A -#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B -#define MMC_PROFILE_BD_ROM 0x0040 -#define MMC_PROFILE_BD_R_SRM 0x0041 -#define MMC_PROFILE_BD_R_RRM 0x0042 -#define MMC_PROFILE_BD_RE 0x0043 -#define MMC_PROFILE_HDDVD_ROM 0x0050 -#define MMC_PROFILE_HDDVD_R 0x0051 -#define MMC_PROFILE_HDDVD_RAM 0x0052 -#define MMC_PROFILE_HDDVD_RW 0x0053 -#define MMC_PROFILE_HDDVD_R_DL 0x0058 -#define MMC_PROFILE_HDDVD_RW_DL 0x005A -#define MMC_PROFILE_INVALID 0xFFFF - -#define SCSI_ONLY 32 -#define ATAPI_ONLY 16 -#define IMPLEMENTED 8 -#define NONDATA 4 -#define CHECK_READY 2 -#define ALLOW_UA 1 - - -extern uint8_t SCSICommandTable[0x100]; -extern uint8_t mode_sense_pages[0x40]; -extern int readcdmode; - -/* Mode sense/select stuff. */ -extern uint8_t mode_pages_in[256][256]; -extern uint8_t page_flags[256]; -extern uint8_t prefix_len; -extern uint8_t page_current; -#define PAGE_CHANGEABLE 1 -#define PAGE_CHANGED 2 - -struct _scsisense_ { - uint8_t SenseBuffer[18]; - uint8_t SenseLength; - uint8_t UnitAttention; - uint8_t SenseKey; - uint8_t Asc; - uint8_t Ascq; -} SCSISense; - -extern int cd_status; -extern int prev_status; - -enum { - SCSI_NONE = 0, - SCSI_DISK, - SCSI_CDROM, - SCSI_ZIP -}; - -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) - -#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) - -#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) - -typedef struct { - uint8_t *CmdBuffer; - int LunType; - int32_t BufferLength; - uint8_t Status; - uint8_t Phase; -} scsi_device_t; - - -extern scsi_device_t SCSIDevices[SCSI_ID_MAX]; - -extern void SCSIReset(uint8_t id); - -extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); -extern int cdrom_LBAtoMSF_accurate(void); - -extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save); -extern int mode_select_terminate(int force); -extern int mode_select_write(uint8_t val); - extern int scsi_card_current; -extern int scsi_card_available(int card); -extern char *scsi_card_getname(int card); +extern int scsi_card_available(int card); +extern char *scsi_card_getname(int card); #ifdef EMU_DEVICE_H -extern const device_t *scsi_card_getdevice(int card); +extern const device_t *scsi_card_getdevice(int card); #endif -extern int scsi_card_has_config(int card); -extern char *scsi_card_get_internal_name(int card); -extern int scsi_card_get_from_internal_name(char *s); -extern void scsi_mutex(uint8_t start); -extern void scsi_card_init(void); - - -#pragma pack(push,1) -typedef struct { - uint8_t hi; - uint8_t mid; - uint8_t lo; -} addr24; -#pragma pack(pop) - -#define ADDR_TO_U32(x) (((x).hi<<16)|((x).mid<<8)|((x).lo&0xFF)) -#define U32_TO_ADDR(a,x) do {(a).hi=(x)>>16;(a).mid=(x)>>8;(a).lo=(x)&0xFF;}while(0) - - -/* - * - * Scatter/Gather Segment List Definitions - * - * Adapter limits - */ -#define MAX_SG_DESCRIPTORS 32 /* Always make the array 32 elements long, if less are used, that's not an issue. */ - -#pragma pack(push,1) -typedef struct { - uint32_t Segment; - uint32_t SegmentPointer; -} SGE32; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - addr24 Segment; - addr24 SegmentPointer; -} SGE; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t pages[0x40][0x40]; -} mode_sense_pages_t; -#pragma pack(pop) - - -#define MODE_SELECT_PHASE_IDLE 0 -#define MODE_SELECT_PHASE_HEADER 1 -#define MODE_SELECT_PHASE_BLOCK_DESC 2 -#define MODE_SELECT_PHASE_PAGE_HEADER 3 -#define MODE_SELECT_PHASE_PAGE 4 +extern int scsi_card_has_config(int card); +extern char *scsi_card_get_internal_name(int card); +extern int scsi_card_get_from_internal_name(char *s); +extern void scsi_card_init(void); #endif /*EMU_SCSI_H*/ - -extern void scsi_mutex_wait(uint8_t wait); diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 59e48129c..a33d35f07 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -10,7 +10,7 @@ * made by Adaptec, Inc. These controllers were designed for * the ISA bus. * - * Version: @(#)scsi_aha154x.c 1.0.42 2018/06/12 + * Version: @(#)scsi_aha154x.c 1.0.44 2018/10/18 * * Authors: Fred N. van Kempen, * Original Buslogic version by SA1988 and Miran Grca. @@ -26,6 +26,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mca.h" #include "../mem.h" #include "../mca.h" @@ -34,15 +35,15 @@ #include "../nvr.h" #include "../dma.h" #include "../pic.h" -#include "../timer.h" #include "../plat.h" -#include "../cpu/cpu.h" +// #include "../cpu/cpu.h" #include "scsi.h" #include "scsi_aha154x.h" #include "scsi_x54x.h" enum { + AHA_154xA, AHA_154xB, AHA_154xC, AHA_154xCF, @@ -51,6 +52,7 @@ enum { }; + #define CMD_WRITE_EEPROM 0x22 /* UNDOC: Write EEPROM */ #define CMD_READ_EEPROM 0x23 /* UNDOC: Read EEPROM */ #define CMD_SHADOW_RAM 0x24 /* UNDOC: BIOS shadow ram */ @@ -82,23 +84,22 @@ typedef struct { #ifdef ENABLE_AHA154X_LOG int aha_do_log = ENABLE_AHA154X_LOG; -#endif static void aha_log(const char *fmt, ...) { -#ifdef ENABLE_AHA154X_LOG va_list ap; if (aha_do_log) { - pclog("In %s mode: ",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define aha_log(fmt, ...) +#endif /* @@ -291,7 +292,7 @@ aha_param_len(void *p) break; case CMD_WRITE_EEPROM: - return 3+32; + return 35; break; case CMD_READ_EEPROM: @@ -359,7 +360,7 @@ aha_cmds(void *p) case CMD_BIOS_MBINIT: /* BIOS Mailbox Initialization */ /* Sent by CF BIOS. */ - dev->Mbx24bit = 1; + dev->flags |= X54X_MBX_24BIT; mbi = (MailboxInit_t *)dev->CmdBuf; @@ -579,6 +580,15 @@ aha_mca_write(int port, uint8_t val, void *priv) } +static uint8_t +aha_mca_feedb(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + return (dev->pos_regs[2] & 0x01); +} + + /* Initialize the board's ROM BIOS. */ static void aha_setbios(x54x_t *dev) @@ -718,16 +728,12 @@ aha_setnvr(x54x_t *dev) memset(dev->nvr, 0x00, NVR_SIZE); f = nvr_fopen(dev->nvr_path, L"rb"); - if (f) - { + if (f) { fread(dev->nvr, 1, NVR_SIZE, f); fclose(f); f = NULL; - } - else - { + } else aha_initnvr(dev); - } } @@ -754,10 +760,7 @@ aha_init(const device_t *info) dev->HostID = 7; /* default HA ID */ dev->setup_info_len = sizeof(aha_setup_t); dev->max_id = 7; - dev->int_geom_writable = 0; - dev->cdrom_boot = 0; - dev->bit32 = 0; - dev->lba_bios = 0; + dev->flags = 0; dev->ven_callback = aha_callback; dev->ven_cmd_is_fast = aha_cmd_is_fast; @@ -770,6 +773,17 @@ aha_init(const device_t *info) /* Perform per-board initialization. */ switch(dev->type) { + case AHA_154xA: + strcpy(dev->name, "AHA-154xA"); + dev->fw_rev = "A003"; /* The 3.07 microcode says A006. */ + dev->bios_path = L"roms/scsi/adaptec/aha1540a307.bin"; /*Only for port 0x330*/ + /* This is configurable from the configuration for the 154xB, the rest of the controllers read it from the EEPROM. */ + dev->HostID = device_get_config_int("hostid"); + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + case AHA_154xB: strcpy(dev->name, "AHA-154xB"); switch(dev->Base) { @@ -815,7 +829,7 @@ aha_init(const device_t *info) dev->rom_shramsz = 128; /* size of shadow RAM */ dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ - dev->cdrom_boot = 1; + dev->flags |= X54X_CDROM_BOOT; dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ @@ -842,12 +856,12 @@ aha_init(const device_t *info) dev->bios_path = L"roms/scsi/adaptec/aha1640.bin"; dev->fw_rev = "BB01"; - dev->lba_bios = 1; + dev->flags |= X54X_LBA_BIOS; /* Enable MCA. */ dev->pos_regs[0] = 0x1F; /* MCA board ID */ dev->pos_regs[1] = 0x0F; - mca_add(aha_mca_read, aha_mca_write, dev); + mca_add(aha_mca_read, aha_mca_write, aha_mca_feedb, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ break; } @@ -1108,8 +1122,17 @@ static const device_config_t aha_154x_config[] = { }; -const device_t aha1540b_device = { - "Adaptec AHA-1540B", +const device_t aha154xa_device = { + "Adaptec AHA-154xA", + DEVICE_ISA | DEVICE_AT, + AHA_154xA, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + aha_154xb_config +}; + +const device_t aha154xb_device = { + "Adaptec AHA-154xB", DEVICE_ISA | DEVICE_AT, AHA_154xB, aha_init, x54x_close, NULL, @@ -1117,8 +1140,8 @@ const device_t aha1540b_device = { aha_154xb_config }; -const device_t aha1542c_device = { - "Adaptec AHA-1542C", +const device_t aha154xc_device = { + "Adaptec AHA-154xC", DEVICE_ISA | DEVICE_AT, AHA_154xC, aha_init, x54x_close, NULL, @@ -1126,8 +1149,8 @@ const device_t aha1542c_device = { aha_154x_config }; -const device_t aha1542cf_device = { - "Adaptec AHA-1542CF", +const device_t aha154xcf_device = { + "Adaptec AHA-154xCF", DEVICE_ISA | DEVICE_AT, AHA_154xCF, aha_init, x54x_close, NULL, diff --git a/src/scsi/scsi_aha154x.h b/src/scsi/scsi_aha154x.h index 73eb10b89..e7b3d62c0 100644 --- a/src/scsi/scsi_aha154x.h +++ b/src/scsi/scsi_aha154x.h @@ -1,10 +1,10 @@ #ifndef SCSI_AHA154X_H # define SCSI_AHA154X_H - -extern const device_t aha1540b_device; -extern const device_t aha1542c_device; -extern const device_t aha1542cf_device; +extern const device_t aha154xa_device; +extern const device_t aha154xb_device; +extern const device_t aha154xc_device; +extern const device_t aha154xcf_device; extern const device_t aha1640_device; extern void aha_device_reset(void *p); diff --git a/src/scsi/scsi_bus.c b/src/scsi/scsi_bus.c deleted file mode 100644 index 930c4daff..000000000 --- a/src/scsi/scsi_bus.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * The generic SCSI bus operations handler. - * - * Version: @(#)scsi_bus.c 1.0.7 2018/06/18 - * - * NOTES: For now ported from PCem with some modifications - * but at least it's a start. - * - * Authors: TheCollector1995, - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "../86box.h" -#include "scsi.h" -#include "scsi_device.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 & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) - -uint32_t SCSI_BufferLength; -#ifdef ENABLE_SCSI_BUS_LOG -int scsi_bus_do_log = ENABLE_SCSI_BUS_LOG; -#endif - - -static void -scsi_bus_log(const char *fmt, ...) -{ -#ifdef ENABLE_SCSI_BUS_LOG - va_list ap; - - if (scsi_bus_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - -/* get the length of a SCSI command based on its command byte type */ -static int get_cmd_len(int cbyte) -{ - int len; - int group; - - group = (cbyte>>5) & 7; - - if (group == 0) len = 6; - if (group == 1 || group == 2) len = 10; - if (group == 5) len = 12; - -// scsi_bus_log("Command group %d, length %d\n", group, len); - - return(len); -} - - -static int -get_dev_id(uint8_t data) -{ - int c; - - for (c = 0; c < SCSI_ID_MAX; c++) { - if (data & (1 << c)) return(c); - } - - return(-1); -} - - -int -scsi_bus_update(scsi_bus_t *bus, int bus_assert) -{ - scsi_device_t *dev; - - if (bus_assert & BUS_ARB) - bus->state = STATE_IDLE; - - switch (bus->state) { - case STATE_IDLE: - scsi_bus_log("State Idle\n"); - 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->dev_id = get_dev_id(sel_data); - - if ((bus->dev_id != -1) && scsi_device_present(bus->dev_id)) { - bus->bus_out |= BUS_BSY; - bus->state = STATE_PHASESEL; - } - //scsi_bus_log("Device id %i\n", bus->dev_id); - break; - } - break; - - case STATE_PHASESEL: - scsi_bus_log("State Phase Sel\n"); - if (! (bus_assert & BUS_SEL)) { - if (! (bus_assert & BUS_ATN)) { - if ((bus->dev_id != -1) && - scsi_device_present(bus->dev_id)) { - bus->state = STATE_COMMAND; - bus->bus_out = BUS_BSY | BUS_REQ; - bus->command_pos = 0; - SET_BUS_STATE(bus, SCSI_PHASE_COMMAND); - } 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)) { - scsi_bus_log("State Command\n"); - bus->command[bus->command_pos++] = BUS_GETDATA(bus_assert); - - bus->clear_req = 3; - bus->new_state = bus->bus_out & SCSI_PHASE_MESSAGE_IN; - bus->bus_out &= ~BUS_REQ; - - if (get_cmd_len(bus->command[0]) == bus->command_pos) { - bus->data_pos = 0; - - dev = &SCSIDevices[bus->dev_id]; - - scsi_bus_log("Command 0x%02X\n", bus->command[0]); - - dev->BufferLength = -1; - - scsi_device_command_phase0(bus->dev_id, bus->command); - - scsi_bus_log("(ID %02X): Command %02X: Buffer Length %i, SCSI Phase %02X\n", bus->dev_id, bus->command[0], dev->BufferLength, dev->Phase); - - if ((dev->Phase == SCSI_PHASE_DATA_IN) || - (dev->Phase == SCSI_PHASE_DATA_OUT)) { - scsi_bus_log("dev->CmdBuffer = %08X\n", dev->CmdBuffer); - dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength); - scsi_bus_log("dev->CmdBuffer = %08X\n", dev->CmdBuffer); - } - - if (dev->Phase == SCSI_PHASE_DATA_OUT) { - /* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */ - scsi_bus_log("Next state is data out\n"); - - bus->state = STATE_COMMANDWAIT; - bus->clear_req = 0; - } else { - /* Other command - execute immediately. */ - bus->new_state = dev->Phase; - if (dev->Phase == SCSI_PHASE_DATA_IN) { - scsi_device_command_phase1(bus->dev_id); - } - - bus->change_state_delay = 4; - } - } - } - break; - - case STATE_COMMANDWAIT: - bus->new_state = SCSI_PHASE_DATA_OUT; - bus->change_state_delay = 4; - bus->clear_req = 4; - break; - - case STATE_DATAIN: - if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { - scsi_bus_log("State Data In\n"); - - /* This seems to be read, so we first execute the command, then we return the bytes to the host. */ - dev = &SCSIDevices[bus->dev_id]; - - if (bus->data_pos >= SCSIDevices[bus->dev_id].BufferLength) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - bus->bus_out &= ~BUS_REQ; - bus->new_state = SCSI_PHASE_STATUS; - bus->change_state_delay = 4; - bus->new_req_delay = 8; - } else { - uint8_t val = dev->CmdBuffer[bus->data_pos++]; - - bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ; - bus->clear_req = 3; - bus->bus_out &= ~BUS_REQ; - bus->new_state = SCSI_PHASE_DATA_IN; - } - } - break; - - case STATE_DATAOUT: - if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { - scsi_bus_log("State Data Out\n"); - dev = &SCSIDevices[bus->dev_id]; - - /* This is write, so first get the data from the host, then execute the last phase of the command. */ - dev->CmdBuffer[bus->data_pos++] = BUS_GETDATA(bus_assert); - - if (bus->data_pos >= SCSIDevices[bus->dev_id].BufferLength) { - /* scsi_bus_log("%04X bytes written (%02X %02X)\n", bus->data_pos, bus->command[0], bus->command[1]); */ - scsi_bus_log("Actually executing write command\n"); - scsi_device_command_phase1(bus->dev_id); - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - bus->bus_out &= ~BUS_REQ; - bus->new_state = SCSI_PHASE_STATUS; - bus->change_state_delay = 4; - bus->new_req_delay = 8; - } else { - bus->bus_out |= BUS_REQ; - } - } - break; - - case STATE_STATUS: - scsi_bus_log("State Status\n"); - - if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { - /* scsi_bus_log("Preparing for message in\n"); */ - bus->bus_out &= ~BUS_REQ; - bus->new_state = SCSI_PHASE_MESSAGE_IN; - bus->change_state_delay = 4; - bus->new_req_delay = 8; - } - break; - - case STATE_MESSAGEIN: - scsi_bus_log("State Message In\n"); - - if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { - bus->bus_out &= ~BUS_REQ; - bus->new_state = BUS_IDLE; - bus->change_state_delay = 4; - } - 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; - - if (bus->clear_req) { - bus->clear_req--; - if (!bus->clear_req) { - scsi_bus_log("Clear REQ\n"); - - SET_BUS_STATE(bus, bus->new_state); - bus->bus_out |= BUS_REQ; - } - } - - if (bus->change_state_delay) { - bus->change_state_delay--; - if (!bus->change_state_delay) { - uint8_t val; - - scsi_bus_log("Change state delay\n"); - - SET_BUS_STATE(bus, bus->new_state); - - switch (bus->bus_out & SCSI_PHASE_MESSAGE_IN) { - case SCSI_PHASE_DATA_IN: - dev = &SCSIDevices[bus->dev_id]; - - scsi_bus_log("Phase data in\n"); - bus->state = STATE_DATAIN; - val = dev->CmdBuffer[bus->data_pos++]; - bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP; - break; - - case SCSI_PHASE_DATA_OUT: - scsi_bus_log("Phase data out\n"); - if (bus->new_state & BUS_IDLE) { - bus->state = STATE_IDLE; - bus->bus_out &= ~BUS_BSY; - } else { - bus->state = STATE_DATAOUT; - } - break; - - case SCSI_PHASE_STATUS: - dev = &SCSIDevices[bus->dev_id]; - - scsi_bus_log("Phase status\n"); - bus->state = STATE_STATUS; - bus->bus_out |= BUS_REQ; - bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(dev->Status) | BUS_DBP; - /* scsi_bus_log("SCSI Status (command %02X): %02X (%08X)\n", bus->command[0], dev->Status, bus->bus_out); */ - break; - - case SCSI_PHASE_MESSAGE_IN: - scsi_bus_log("Phase message in\n"); - /* scsi_bus_log("Message in\n"); */ - 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) { - bus->bus_out |= BUS_REQ; - } - } - - return(bus->bus_out); -} - - -int -scsi_bus_match(scsi_bus_t *bus, int bus_assert) -{ - return((bus_assert & (BUS_CD | BUS_IO | BUS_MSG)) == - (bus->bus_out & (BUS_CD | BUS_IO | BUS_MSG))); -} diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index bc5eb421c..15a4dc7d4 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -11,7 +11,7 @@ * 1 - BT-545S ISA; * 2 - BT-958D PCI * - * Version: @(#)scsi_buslogic.c 1.0.39 2018/06/11 + * Version: @(#)scsi_buslogic.c 1.0.45 2019/02/11 * * Authors: TheCollector1995, * Miran Grca, @@ -29,6 +29,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mca.h" #include "../mem.h" #include "../mca.h" @@ -38,7 +39,6 @@ #include "../dma.h" #include "../pic.h" #include "../pci.h" -#include "../timer.h" #include "../plat.h" #include "scsi.h" #include "scsi_buslogic.h" @@ -229,6 +229,7 @@ typedef struct { enum { + CHIP_BUSLOGIC_ISA_542_1991, CHIP_BUSLOGIC_ISA_542, CHIP_BUSLOGIC_ISA, CHIP_BUSLOGIC_MCA, @@ -240,13 +241,11 @@ enum { #ifdef ENABLE_BUSLOGIC_LOG int buslogic_do_log = ENABLE_BUSLOGIC_LOG; -#endif static void buslogic_log(const char *fmt, ...) { -#ifdef ENABLE_BUSLOGIC_LOG va_list ap; if (buslogic_do_log) { @@ -254,8 +253,10 @@ buslogic_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define buslogic_log(fmt, ...) +#endif static wchar_t * @@ -263,6 +264,8 @@ BuslogicGetNVRFileName(buslogic_data_t *bl) { switch(bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: + return L"bt542b.nvr"; case CHIP_BUSLOGIC_ISA_542: return L"bt542bh.nvr"; case CHIP_BUSLOGIC_ISA: @@ -298,6 +301,9 @@ BuslogicAutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) HALR->structured.autoSCSIData.aHostAdaptertype[0] = ' '; HALR->structured.autoSCSIData.aHostAdaptertype[5] = ' '; switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542B", 4); + break; case CHIP_BUSLOGIC_ISA_542: memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542BH", 5); break; @@ -463,7 +469,7 @@ buslogic_get_host_id(void *p) HALocalRAM *HALR = &bl->LocalRAM; - if (bl->chip == CHIP_BUSLOGIC_ISA_542) + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991)) return dev->HostID; else return HALR->structured.autoSCSIData.uSCSIId; @@ -480,7 +486,7 @@ buslogic_get_irq(void *p) HALocalRAM *HALR = &bl->LocalRAM; - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_PCI)) + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_PCI)) return dev->Irq; else return bl_irq[HALR->structured.autoSCSIData.uIrqChannel]; @@ -499,7 +505,7 @@ buslogic_get_dma(void *p) if (bl->chip == CHIP_BUSLOGIC_PCI) return (dev->Base ? 7 : 0); - else if (bl->chip == CHIP_BUSLOGIC_ISA_542) + else if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991)) return dev->DmaChannel; else return bl_dma[HALR->structured.autoSCSIData.uDMAChannel]; @@ -556,6 +562,7 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir) int DataLength = ESCSICmd->DataLength; uint32_t Address; uint32_t TransferLength; + scsi_device_t *dev = &scsi_devices[TargetID]; if (ESCSICmd->DataDirection == 0x03) { /* Non-data command. */ @@ -567,16 +574,16 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir) /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without checking its length, so do this procedure for both read/write commands. */ - if ((DataLength > 0) && (SCSIDevices[TargetID].BufferLength > 0)) { + if ((DataLength > 0) && (dev->buffer_length > 0)) { Address = DataPointer; - TransferLength = MIN(DataLength, SCSIDevices[TargetID].BufferLength); + TransferLength = MIN(DataLength, dev->buffer_length); if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) { buslogic_log("BusLogic BIOS DMA: Reading %i bytes from %08X\n", TransferLength, Address); - DMAPageRead(Address, (uint8_t *)SCSIDevices[TargetID].CmdBuffer, TransferLength); + DMAPageRead(Address, (uint8_t *)dev->sc->temp_buffer, TransferLength); } else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) { buslogic_log("BusLogic BIOS DMA: Writing %i bytes at %08X\n", TransferLength, Address); - DMAPageWrite(Address, (uint8_t *)SCSIDevices[TargetID].CmdBuffer, TransferLength); + DMAPageWrite(Address, (uint8_t *)dev->sc->temp_buffer, TransferLength); } } } @@ -589,8 +596,11 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u uint32_t i; uint8_t temp_cdb[12]; int target_cdb_len = 12; +#ifdef ENABLE_BUSLOGIC_LOG uint8_t target_id = 0; +#endif int phase; + scsi_device_t *sd = &scsi_devices[ESCSICmd->TargetId]; DataInBuf[0] = DataInBuf[1] = 0; @@ -602,12 +612,13 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u buslogic_log("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); - SCSIDevices[ESCSICmd->TargetId].Status = SCSI_STATUS_OK; + sd->status = SCSI_STATUS_OK; - if (!scsi_device_present(ESCSICmd->TargetId)) { + if (!scsi_device_present(sd)) { buslogic_log("SCSI Target ID %i has no device attached\n", ESCSICmd->TargetId); DataInBuf[2] = CCB_SELECTION_TIMEOUT; DataInBuf[3] = SCSI_STATUS_OK; + return; } else { buslogic_log("SCSI Target ID %i detected and working\n", ESCSICmd->TargetId); @@ -619,11 +630,9 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u } } - x54x_buf_alloc(ESCSICmd->TargetId, ESCSICmd->DataLength); - target_cdb_len = 12; - if (!scsi_device_valid(ESCSICmd->TargetId)) fatal("SCSI target on ID %02i has disappeared\n", ESCSICmd->TargetId); + if (!scsi_device_valid(sd)) fatal("SCSI target on ID %02i has disappeared\n", ESCSICmd->TargetId); buslogic_log("SCSI target command being executed on: SCSI ID %i, SCSI LUN %i, Target %i\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit, target_id); @@ -639,26 +648,22 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u memcpy(temp_cdb, ESCSICmd->CDB, target_cdb_len); } - SCSIDevices[ESCSICmd->TargetId].BufferLength = ESCSICmd->DataLength; - scsi_device_command_phase0(ESCSICmd->TargetId, temp_cdb); + sd->buffer_length = ESCSICmd->DataLength; - phase = SCSIDevices[ESCSICmd->TargetId].Phase; + scsi_device_command_phase0(sd, temp_cdb); + + phase = sd->phase; if (phase != SCSI_PHASE_STATUS) { - if (phase == SCSI_PHASE_DATA_IN) - scsi_device_command_phase1(ESCSICmd->TargetId); BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, (phase == SCSI_PHASE_DATA_OUT)); - if (phase == SCSI_PHASE_DATA_OUT) - scsi_device_command_phase1(ESCSICmd->TargetId); + scsi_device_command_phase1(sd); } - x54x_buf_free(ESCSICmd->TargetId); - buslogic_log("BIOS Request complete\n"); - if (SCSIDevices[ESCSICmd->TargetId].Status == SCSI_STATUS_OK) { + if (sd->status == SCSI_STATUS_OK) { DataInBuf[2] = CCB_COMPLETE; DataInBuf[3] = SCSI_STATUS_OK; - } else if (SCSIDevices[ESCSICmd->TargetId].Status == SCSI_STATUS_CHECK_CONDITION) { + } else if (scsi_devices[ESCSICmd->TargetId].status == SCSI_STATUS_CHECK_CONDITION) { DataInBuf[2] = CCB_COMPLETE; DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; } @@ -697,15 +702,15 @@ buslogic_cmds(void *p) case 0x23: memset(dev->DataBuf, 0, 8); for (i = 8; i < 15; i++) { - dev->DataBuf[i-8] = 0; - if (scsi_device_present(i) && (i != buslogic_get_host_id(dev))) - dev->DataBuf[i-8] |= 1; + dev->DataBuf[i - 8] = 0; + if (scsi_device_present(&scsi_devices[i]) && (i != buslogic_get_host_id(dev))) + dev->DataBuf[i - 8] |= 1; } dev->DataReplyLeft = 8; break; case 0x24: - for (i=0; i<15; i++) { - if (scsi_device_present(i) && (i != buslogic_get_host_id(dev))) + for (i = 0; i < 15; i++) { + if (scsi_device_present(&scsi_devices[i]) && (i != buslogic_get_host_id(dev))) TargetsPresentMask |= (1 << i); } dev->DataBuf[0] = TargetsPresentMask & 0xFF; @@ -719,7 +724,7 @@ buslogic_cmds(void *p) dev->IrqEnabled = 1; return 1; case 0x81: - dev->Mbx24bit = 0; + dev->flags &= ~X54X_MBX_24BIT; MailboxInitE = (MailboxInitExtended_t *)dev->CmdBuf; @@ -813,6 +818,7 @@ buslogic_cmds(void *p) memset(ReplyIESI, 0, sizeof(ReplyInquireExtendedSetupInformation)); switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: case CHIP_BUSLOGIC_ISA_542: case CHIP_BUSLOGIC_ISA: case CHIP_BUSLOGIC_VLB: @@ -830,7 +836,7 @@ buslogic_cmds(void *p) ReplyIESI->cMailbox = dev->MailboxCount; ReplyIESI->uMailboxAddressBase = dev->MailboxOutAddr; ReplyIESI->fHostWideSCSI = 1; /* This should be set for the BT-542B as well. */ - if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_MCA)) + if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_ISA_542_1991) && (bl->chip != CHIP_BUSLOGIC_MCA)) ReplyIESI->fLevelSensitiveInterrupt = bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; if (bl->chip == CHIP_BUSLOGIC_PCI) ReplyIESI->fHostUltraSCSI = 1; @@ -865,7 +871,7 @@ buslogic_cmds(void *p) break; } case 0x92: - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_MCA)) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; @@ -911,7 +917,7 @@ buslogic_cmds(void *p) } break; case 0x94: - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_MCA)) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; @@ -1031,6 +1037,7 @@ buslogic_setup_data(void *p) bl_setup->uCharacterD = 'D'; /* BusLogic model. */ switch(bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: case CHIP_BUSLOGIC_ISA_542: case CHIP_BUSLOGIC_ISA: bl_setup->uHostBusType = 'A'; @@ -1064,7 +1071,7 @@ buslogic_interrupt_type(void *p) x54x_t *dev = (x54x_t *)p; buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_MCA)) return 0; else return !!bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; @@ -1110,7 +1117,9 @@ static uint8_t BuslogicPCIRead(int func, int addr, void *p) { x54x_t *dev = (x54x_t *)p; +#ifdef ENABLE_BUSLOGIC_LOG buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; +#endif buslogic_log("BT-958D: Reading register %02X\n", addr & 0xff); @@ -1148,9 +1157,10 @@ BuslogicPCIRead(int func, int addr, void *p) case 0x13: return buslogic_pci_bar[0].addr_regs[3]; case 0x14: - return (buslogic_pci_bar[1].addr_regs[0] & 0xe0); /*Memory space*/ + // return (buslogic_pci_bar[1].addr_regs[0] & 0xe0); /*Memory space*/ + return 0x00; case 0x15: - return buslogic_pci_bar[1].addr_regs[1]; + return buslogic_pci_bar[1].addr_regs[1] & 0xc0; case 0x16: return buslogic_pci_bar[1].addr_regs[2]; case 0x17: @@ -1248,7 +1258,10 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) /* Then let's set the PCI regs. */ buslogic_pci_bar[1].addr_regs[addr & 3] = val; /* Then let's calculate the new I/O base. */ - bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffffe0; + // bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffffe0; + /* Give it a 4 kB alignment as that's this emulator's granularity. */ + buslogic_pci_bar[1].addr &= 0xffffc000; + bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffc000; /* Log the new base. */ buslogic_log("BusLogic PCI: New MMIO base is %04X\n" , bl->MMIOBase); /* We're done, so get out of the here. */ @@ -1475,6 +1488,15 @@ buslogic_mca_write(int port, uint8_t val, void *priv) } +static uint8_t +buslogic_mca_feedb(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + return (dev->pos_regs[2] & 0x01); +} + + void BuslogicDeviceReset(void *p) { @@ -1525,10 +1547,7 @@ buslogic_init(const device_t *info) dev->HostID = 7; /* default HA ID */ dev->setup_info_len = sizeof(buslogic_setup_t); dev->max_id = 7; - dev->int_geom_writable = 1; - dev->cdrom_boot = 0; - dev->bit32 = 0; - dev->lba_bios = 0; + dev->flags = X54X_INT_GEOM_WRITABLE; bl->chip = info->local; bl->PCIBase = 0; @@ -1561,6 +1580,17 @@ buslogic_init(const device_t *info) switch(bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: + strcpy(dev->name, "BT-542B"); + bios_rom_name = L"roms/scsi/buslogic/BT-542B_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "AA221"; + dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ + break; case CHIP_BUSLOGIC_ISA_542: strcpy(dev->name, "BT-542BH"); bios_rom_name = L"roms/scsi/buslogic/BT-542BH_BIOS.rom"; @@ -1570,6 +1600,7 @@ buslogic_init(const device_t *info) has_scam_rom = 0; dev->fw_rev = "AA335"; dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_ISA: default: @@ -1583,6 +1614,7 @@ buslogic_init(const device_t *info) has_scam_rom = 0; dev->fw_rev = "AA421E"; dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_MCA: strcpy(dev->name, "BT-640A"); @@ -1592,11 +1624,12 @@ buslogic_init(const device_t *info) has_autoscsi_rom = 0; has_scam_rom = 0; dev->fw_rev = "BA150"; - dev->bit32 = 1; + dev->flags |= X54X_32BIT; dev->pos_regs[0] = 0x08; /* MCA board ID */ dev->pos_regs[1] = 0x07; - mca_add(buslogic_mca_read, buslogic_mca_write, dev); + mca_add(buslogic_mca_read, buslogic_mca_write, buslogic_mca_feedb, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_VLB: strcpy(dev->name, "BT-445S"); @@ -1605,11 +1638,14 @@ buslogic_init(const device_t *info) bios_rom_mask = 0x3fff; has_autoscsi_rom = 1; autoscsi_rom_name = L"roms/scsi/buslogic/BT-445S_AutoSCSI.rom"; - autoscsi_rom_size = 0x4000; - has_scam_rom = 0; - dev->fw_rev = "AA421E"; - dev->bit32 = 1; + autoscsi_rom_size = 0x8000; + has_scam_rom = 1; + scam_rom_name = L"roms/scsi/buslogic/BT-445S_SCAM.rom"; + scam_rom_size = 0x0200; + dev->fw_rev = "AA507B"; + dev->flags |= X54X_32BIT; dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_PCI: strcpy(dev->name, "BT-958D"); @@ -1623,8 +1659,7 @@ buslogic_init(const device_t *info) scam_rom_name = L"roms/scsi/buslogic/BT-958D_SCAM.rom"; scam_rom_size = 0x0200; dev->fw_rev = "AA507B"; - dev->cdrom_boot = 1; - dev->bit32 = 1; + dev->flags |= (X54X_CDROM_BOOT | X54X_32BIT); dev->ha_bps = 20000000.0; /* ultra SCSI */ dev->max_id = 15; /* wide SCSI */ break; @@ -1695,7 +1730,7 @@ buslogic_init(const device_t *info) x54x_device_reset(dev); - if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_MCA)) { + if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_ISA_542_1991) && (bl->chip != CHIP_BUSLOGIC_MCA)) { BuslogicInitializeLocalRAM(bl); BuslogicInitializeAutoSCSIRam(dev); } @@ -1809,6 +1844,14 @@ static const device_config_t BT958D_Config[] = { } }; +const device_t buslogic_542b_1991_device = { + "Buslogic BT-542B ISA", + DEVICE_ISA | DEVICE_AT, + CHIP_BUSLOGIC_ISA_542_1991, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT_ISA_Config +}; const device_t buslogic_device = { "Buslogic BT-542BH ISA", diff --git a/src/scsi/scsi_buslogic.h b/src/scsi/scsi_buslogic.h index 83ce417d9..87f79d522 100644 --- a/src/scsi/scsi_buslogic.h +++ b/src/scsi/scsi_buslogic.h @@ -20,6 +20,7 @@ # define SCSI_BUSLOGIC_H +extern const device_t buslogic_542b_1991_device; extern const device_t buslogic_device; extern const device_t buslogic_545s_device; extern const device_t buslogic_640a_device; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c new file mode 100644 index 000000000..abfd8a6ef --- /dev/null +++ b/src/scsi/scsi_cdrom.c @@ -0,0 +1,2608 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)scsi_cdrom.c 1.0.73 2019/12/13 + * + * Author: Miran Grca, + * + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../timer.h" +#include "../device.h" +#include "../piix.h" +#include "../scsi/scsi_device.h" +#include "../nvr.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../sound/sound.h" +#include "../plat.h" +#include "../ui.h" +#include "../cdrom/cdrom.h" +#include "scsi_cdrom.h" + + +#pragma pack(push,1) +typedef struct +{ + uint8_t opcode; + uint8_t polled; + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; +} gesn_cdb_t; + +typedef struct +{ + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; +} gesn_event_header_t; +#pragma pack(pop) + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +const uint8_t scsi_cdrom_command_flags[0x100] = +{ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, /* 0x02 */ + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + 0, 0, 0, 0, /* 0x04-0x07 */ + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, 0, /* 0x09-0x0A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ + 0, 0, 0, 0, 0, 0, /* 0x0C-0x11 */ + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, /* 0x14 */ + IMPLEMENTED, /* 0x15 */ + 0, 0, 0, 0, /* 0x16-0x19 */ + IMPLEMENTED, /* 0x1A */ + IMPLEMENTED | CHECK_READY, /* 0x1B */ + 0, 0, /* 0x1C-0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, 0, 0, /* 0x1F-0x24 */ + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, /* 0x26-0x27 */ + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, 0, /* 0x29-0x2A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ + 0, 0, 0, /* 0x2C-0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F */ + 0, 0, /* 0x40-0x41 */ + IMPLEMENTED | CHECK_READY, /* 0x42 */ + IMPLEMENTED | CHECK_READY, /* 0x43 - Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS + NOTE: The ATAPI reference says otherwise, but I think this is a question of + interpreting things right - the UNIT ATTENTION condition we have here + is a tradition from not ready to ready, by definition the drive + eventually becomes ready, make the condition go away. */ + IMPLEMENTED | CHECK_READY, /* 0x44 */ + IMPLEMENTED | CHECK_READY, /* 0x45 */ + IMPLEMENTED | ALLOW_UA, /* 0x46 */ + IMPLEMENTED | CHECK_READY, /* 0x47 */ + IMPLEMENTED | CHECK_READY, /* 0x48 */ + IMPLEMENTED | CHECK_READY, /* 0x49 */ + IMPLEMENTED | ALLOW_UA, /* 0x4A */ + IMPLEMENTED | CHECK_READY, /* 0x4B */ + 0, 0, /* 0x4C-0x4D */ + IMPLEMENTED | CHECK_READY, /* 0x4E */ + 0, 0, /* 0x4F-0x50 */ + IMPLEMENTED | CHECK_READY, /* 0x51 */ + IMPLEMENTED | CHECK_READY, /* 0x52 */ + 0, 0, /* 0x53-0x54 */ + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, /* 0x56-0x59 */ + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, /* 0x5B-0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9F */ + 0, 0, 0, 0, 0, /* 0xA0-0xA4 */ + IMPLEMENTED | CHECK_READY, /* 0xA5 */ + 0, 0, /* 0xA6-0xA7 */ + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + IMPLEMENTED | CHECK_READY, /* 0xA9 */ + 0, 0, 0, /* 0xAA-0xAC */ + IMPLEMENTED | CHECK_READY, /* 0xAD */ + 0, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, /* 0xB0-0xB3 */ + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB4 */ + 0, 0, 0, /* 0xB5-0xB7 */ + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB8 */ + IMPLEMENTED | CHECK_READY, /* 0xB9 */ + IMPLEMENTED | CHECK_READY, /* 0xBA */ + IMPLEMENTED, /* 0xBB */ + IMPLEMENTED | CHECK_READY, /* 0xBC */ + IMPLEMENTED, /* 0xBD */ + IMPLEMENTED | CHECK_READY, /* 0xBE */ + IMPLEMENTED | CHECK_READY, /* 0xBF */ + 0, 0, /* 0xC0-0xC1 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC3-0xCC */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCD */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCE-0xD9 */ + IMPLEMENTED | SCSI_ONLY, /* 0xDA */ + 0, 0, 0, 0, 0, /* 0xDB-0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0-0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF0-0xFF */ +}; + +static uint64_t scsi_cdrom_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | + GPMODEP_CDROM_PAGE | + GPMODEP_CDROM_AUDIO_PAGE | + GPMODEP_CAPABILITIES_PAGE | + GPMODEP_ALL_PAGES); + +static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; + +static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; + +static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0xFF, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0x8E, 0xE, 0xFF, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +} }; + +static gesn_cdb_t *gesn_cdb; +static gesn_event_header_t *gesn_event_header; + + +static void scsi_cdrom_command_complete(scsi_cdrom_t *dev); + +static void scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev); + +static void scsi_cdrom_init(scsi_cdrom_t *dev); + + +#ifdef ENABLE_SCSI_CDROM_LOG +int scsi_cdrom_do_log = ENABLE_SCSI_CDROM_LOG; + + +static void +scsi_cdrom_log(const char *format, ...) +{ + va_list ap; + + if (scsi_cdrom_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +} +#else +#define scsi_cdrom_log(format, ...) +#endif + + +static void +scsi_cdrom_set_callback(scsi_cdrom_t *dev) +{ + if (dev && dev->drv && (dev->drv->bus_type != CDROM_BUS_SCSI)) + ide_set_callback(dev->drv->ide_channel >> 1, dev->callback); +} + + +static void +scsi_cdrom_init(scsi_cdrom_t *dev) +{ + if (!dev) + return; + + /* Do a reset (which will also rezero it). */ + scsi_cdrom_reset((scsi_common_t *) dev); + + /* Configure the drive. */ + dev->requested_blocks = 1; + + dev->drv->bus_mode = 0; + if (dev->drv->bus_type >= CDROM_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus_type < CDROM_BUS_SCSI) + dev->drv->bus_mode |= 1; + scsi_cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); + + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + dev->status = READY_STAT | DSC_STAT; + dev->pos = 0; + dev->packet_status = PHASE_NONE; + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; + dev->drv->cur_speed = dev->drv->speed; + scsi_cdrom_mode_sense_load(dev); +} + + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +static int +scsi_cdrom_current_mode(scsi_cdrom_t *dev) +{ + if (dev->drv->bus_type == CDROM_BUS_SCSI) + return 2; + else if (dev->drv->bus_type == CDROM_BUS_ATAPI) { + scsi_cdrom_log("CD-ROM %i: ATAPI drive, setting to %s\n", dev->id, + (dev->features & 1) ? "DMA" : "PIO", + dev->id); + return (dev->features & 1) ? 2 : 1; + } + + return 0; +} + + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int +scsi_cdrom_atapi_phase_to_scsi(scsi_cdrom_t *dev) +{ + if (dev->status & 8) { + switch (dev->phase & 3) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } else { + if ((dev->phase & 3) == 3) + return 3; + else + return 4; + } + + return 0; +} + + +static uint32_t +scsi_cdrom_get_channel(void *p, int channel) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + if (!dev) + return channel + 1; + + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; +} + + +static uint32_t +scsi_cdrom_get_volume(void *p, int channel) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + if (!dev) + return 255; + + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; +} + + +static void +scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + + memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default_scsi, sizeof(mode_sense_pages_t)); + else + memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default, sizeof(mode_sense_pages_t)); + + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) { + fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); + } +} + + +static void +scsi_cdrom_mode_sense_save(scsi_cdrom_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) { + fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); + } +} + + +/*SCSI Mode Sense 6/10*/ +static uint8_t +scsi_cdrom_mode_sense_read(scsi_cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + return dev->ms_pages_saved.pages[page][pos]; + break; + case 1: + return scsi_cdrom_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + if (dev->drv->bus_type == CDROM_BUS_SCSI) + return scsi_cdrom_mode_sense_pages_default_scsi.pages[page][pos]; + else + return scsi_cdrom_mode_sense_pages_default.pages[page][pos]; + break; + } + + return 0; +} + + +static uint32_t +scsi_cdrom_mode_sense(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) +{ + uint8_t page_control = (page >> 6) & 3; + int i = 0, j = 0; + + uint8_t msplen; + + page &= 0x3f; + + if (block_descriptor_len) { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = 0; /* Number of blocks (0 = all). */ + buf[pos++] = 0; + buf[pos++] = 0; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ + buf[pos++] = 8; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((page == GPMODE_ALL_PAGES) || (page == i)) { + if (scsi_cdrom_mode_sense_page_flags & (1LL << ((uint64_t) (page & 0x3f)))) { + buf[pos++] = scsi_cdrom_mode_sense_read(dev, page_control, i, 0); + msplen = scsi_cdrom_mode_sense_read(dev, page_control, i, 1); + buf[pos++] = msplen; + scsi_cdrom_log("CD-ROM %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + for (j = 0; j < msplen; j++) { + if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { + if (j & 1) + buf[pos++] = ((dev->drv->speed * 176) & 0xff); + else + buf[pos++] = ((dev->drv->speed * 176) >> 8); + } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && (j <= 13)) { + if (j & 1) + buf[pos++] = ((dev->drv->cur_speed * 176) & 0xff); + else + buf[pos++] = ((dev->drv->cur_speed * 176) >> 8); + } else + buf[pos++] = scsi_cdrom_mode_sense_read(dev, page_control, i, 2 + j); + } + } + } + } + + return pos; +} + + +static void +scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, int block_len) +{ + int32_t bt, min_len = 0; + + dev->max_transfer_len = dev->request_length; + + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (dev->current_cdb[0]) { + case 0x08: + case 0x28: + case 0xa8: + case 0xb9: + case 0xbe: + /* Make sure total length is not bigger than sum of the lengths of + all the requested blocks. */ + bt = (dev->requested_blocks * block_len); + if (len > bt) + len = bt; + + min_len = block_len; + + if (len <= block_len) { + /* Total length is less or equal to block length. */ + if (dev->max_transfer_len < block_len) { + /* Transfer a minimum of (block size) bytes. */ + dev->max_transfer_len = block_len; + dev->packet_len = block_len; + break; + } + } + /*FALLTHROUGH*/ + default: + dev->packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) + dev->max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (!dev->max_transfer_len) + dev->max_transfer_len = 65534; + + if ((len <= dev->max_transfer_len) && (len >= min_len)) + dev->request_length = dev->max_transfer_len = len; + else if (len > dev->max_transfer_len) + dev->request_length = dev->max_transfer_len; + + return; +} + + +static double +scsi_cdrom_bus_speed(scsi_cdrom_t *dev) +{ + double ret = -1.0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + dev->callback = -1.0; /* Speed depends on SCSI controller */ + return 0.0; + } else { + if (dev && dev->drv) + ret = ide_atapi_get_period(dev->drv->ide_channel); + if (ret == -1.0) { + dev->callback = -1.0; + return 0.0; + } else + return ret * 1000000.0; + } +} + + +static void +scsi_cdrom_command_common(scsi_cdrom_t *dev) +{ + double bytes_per_second, period; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 0; + + scsi_cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->drv->cur_speed); + + if (dev->packet_status == PHASE_COMPLETE) + dev->callback = 0; + else { + switch(dev->current_cdb[0]) { + case GPCMD_REZERO_UNIT: + case 0x0b: + case 0x2b: + /* Seek time is in us. */ + period = cdrom_seek_time(dev->drv); + scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", + dev->id, (uint64_t) period); + dev->callback += period; + scsi_cdrom_set_callback(dev); + return; + case 0x08: + case 0x28: + case 0xa8: + /* Seek time is in us. */ + period = cdrom_seek_time(dev->drv); + scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", + dev->id, (uint64_t) period); + dev->callback += period; + /*FALLTHROUGH*/ + case 0x25: + case 0x42: + case 0x43: + case 0x44: + case 0x51: + case 0x52: + case 0xad: + case 0xb8: + case 0xb9: + case 0xbe: + if (dev->current_cdb[0] == 0x42) + dev->callback += 40.0; + /* Account for seek time. */ + bytes_per_second = 176.0 * 1024.0; + bytes_per_second *= (double) dev->drv->cur_speed; + break; + default: + bytes_per_second = scsi_cdrom_bus_speed(dev); + if (bytes_per_second == 0.0) { + dev->callback = -1; /* Speed depends on SCSI controller */ + return; + } + break; + } + + period = 1000000.0 / bytes_per_second; + scsi_cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (uint64_t) period); + period = period * (double) (dev->packet_len); + scsi_cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (uint64_t) period); + dev->callback += period; + } + scsi_cdrom_set_callback(dev); +} + + +static void +scsi_cdrom_command_complete(scsi_cdrom_t *dev) +{ + ui_sb_update_icon(SB_CDROM | dev->id, 0); + dev->packet_status = PHASE_COMPLETE; + scsi_cdrom_command_common(dev); +} + + +static void +scsi_cdrom_command_read(scsi_cdrom_t *dev) +{ + dev->packet_status = PHASE_DATA_IN; + scsi_cdrom_command_common(dev); +} + + +static void +scsi_cdrom_command_read_dma(scsi_cdrom_t *dev) +{ + dev->packet_status = PHASE_DATA_IN_DMA; + scsi_cdrom_command_common(dev); +} + + +static void +scsi_cdrom_command_write(scsi_cdrom_t *dev) +{ + dev->packet_status = PHASE_DATA_OUT; + scsi_cdrom_command_common(dev); +} + + +static void scsi_cdrom_command_write_dma(scsi_cdrom_t *dev) +{ + dev->packet_status = PHASE_DATA_OUT_DMA; + scsi_cdrom_command_common(dev); +} + + +/* id = Current CD-ROM device ID; + len = Total transfer length; + block_len = Length of a single block (it matters because media access commands on ATAPI); + alloc_len = Allocated transfer length; + direction = Transfer direction (0 = read from host, 1 = write to host). */ +static void scsi_cdrom_data_command_finish(scsi_cdrom_t *dev, int len, int block_len, int alloc_len, int direction) +{ + scsi_cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + dev->pos = 0; + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if ((len == 0) || (scsi_cdrom_current_mode(dev) == 0)) { + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->packet_len = 0; + + scsi_cdrom_command_complete(dev); + } else { + if (scsi_cdrom_current_mode(dev) == 2) { + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->packet_len = alloc_len; + + if (direction == 0) + scsi_cdrom_command_read_dma(dev); + else + scsi_cdrom_command_write_dma(dev); + } else { + scsi_cdrom_update_request_length(dev, len, block_len); + if (direction == 0) + scsi_cdrom_command_read(dev); + else + scsi_cdrom_command_write(dev); + } + } + + scsi_cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); +} + + +static void +scsi_cdrom_sense_clear(scsi_cdrom_t *dev, int command) +{ + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = 0; +} + + +static void +scsi_cdrom_set_phase(scsi_cdrom_t *dev, uint8_t phase) +{ + uint8_t scsi_id = dev->drv->scsi_device_id; + + if (dev->drv->bus_type != CDROM_BUS_SCSI) + return; + + scsi_devices[scsi_id].phase = phase; +} + + +static void +scsi_cdrom_cmd_error(scsi_cdrom_t *dev) +{ + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = ((scsi_cdrom_sense_key & 0xf) << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + ui_sb_update_icon(SB_CDROM | dev->id, 0); + scsi_cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq); +} + + +static void +scsi_cdrom_unit_attention(scsi_cdrom_t *dev) +{ + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + ui_sb_update_icon(SB_CDROM | dev->id, 0); + scsi_cdrom_log("CD-ROM %i: UNIT ATTENTION\n", dev->id); +} + + +static void +scsi_cdrom_buf_alloc(scsi_cdrom_t *dev, uint32_t len) +{ + scsi_cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); + if (!dev->buffer) + dev->buffer = (uint8_t *) malloc(len); +} + + +static void +scsi_cdrom_buf_free(scsi_cdrom_t *dev) +{ + if (dev->buffer) { + scsi_cdrom_log("CD-ROM %i: Freeing buffer...\n", dev->id); + free(dev->buffer); + dev->buffer = NULL; + } +} + + +static void +scsi_cdrom_bus_master_error(scsi_common_t *sc) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + + scsi_cdrom_buf_free(dev); + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_not_ready(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_NOT_READY; + scsi_cdrom_asc = ASC_MEDIUM_NOT_PRESENT; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_invalid_lun(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_INV_LUN; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_ILLEGAL_OPCODE; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_lba_out_of_range(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_LBA_OUT_OF_RANGE; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_invalid_field(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); + dev->status = 0x53; +} + + +static void +scsi_cdrom_invalid_field_pl(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); + dev->status = 0x53; +} + + +static void +scsi_cdrom_illegal_mode(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_incompatible_format(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_INCOMPATIBLE_FORMAT; + scsi_cdrom_ascq = 2; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_data_phase_error(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_DATA_PHASE_ERROR; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static int +scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *len) +{ + int ret = 0, data_pos = 0; + int i = 0, temp_len = 0; + uint32_t cdsize = 0; + + if (dev->drv->cd_status == CD_STATUS_EMPTY) { + scsi_cdrom_not_ready(dev); + return 0; + } + + cdsize = dev->drv->cdrom_capacity; + + if (dev->sector_pos >= cdsize) { + scsi_cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, + dev->sector_pos, cdsize); + scsi_cdrom_lba_out_of_range(dev); + return -1; + } + +/* FIXME: Temporarily disabled this because the Triones ATAPI DMA driver seems to + always request a 4-sector read but sets the DMA bus master to transfer less + data than that. */ +#if 0 + if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { + scsi_cdrom_log("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", dev->id, + (dev->sector_pos + dev->sector_len - 1), cdsize); + scsi_cdrom_lba_out_of_range(dev); + return -1; + } +#endif + + dev->old_len = 0; + *len = 0; + + for (i = 0; i < dev->requested_blocks; i++) { + ret = cdrom_readsector_raw(dev->drv, dev->buffer + data_pos, + dev->sector_pos + i, msf, type, flags, &temp_len); + + data_pos += temp_len; + dev->old_len += temp_len; + + *len += temp_len; + + if (!ret) { + scsi_cdrom_illegal_mode(dev); + return 0; + } + } + + return 1; +} + + +static int +scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch) +{ + int ret = 0, msf = 0; + int type = 0, flags = 0; + + if (dev->current_cdb[0] == GPCMD_READ_CD_MSF) + msf = 1; + + if ((dev->current_cdb[0] == GPCMD_READ_CD_MSF) || (dev->current_cdb[0] == GPCMD_READ_CD)) { + type = (dev->current_cdb[1] >> 2) & 7; + flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); + } else { + type = 8; + flags = 0x10; + } + + if (!dev->sector_len) { + scsi_cdrom_command_complete(dev); + return -1; + } + + scsi_cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); + + ret = scsi_cdrom_read_data(dev, msf, type, flags, len); + + scsi_cdrom_log("Read %i bytes of blocks...\n", *len); + + if (ret == -1) + return 0; + else if (!ret || ((dev->old_len != *len) && !first_batch)) { + if ((dev->old_len != *len) && !first_batch) + scsi_cdrom_illegal_mode(dev); + + return 0; + } + + dev->sector_pos += dev->requested_blocks; + dev->drv->seek_pos = dev->sector_pos; + dev->sector_len -= dev->requested_blocks; + return 1; +} + + +/*SCSI Read DVD Structure*/ +static int +scsi_cdrom_read_dvd_structure(scsi_cdrom_t *dev, int format, const uint8_t *packet, uint8_t *buf) +{ + int layer = packet[6]; + uint64_t total_sectors = 0; + + switch (format) { + case 0x00: /* Physical format information */ + if (dev->drv->cd_status == CD_STATUS_EMPTY) { + scsi_cdrom_not_ready(dev); + return 0; + } + + total_sectors = (uint64_t) dev->drv->cdrom_capacity; + + if (layer != 0) { + scsi_cdrom_invalid_field(dev); + return 0; + } + + total_sectors >>= 2; + if (total_sectors == 0) { + /* return -ASC_MEDIUM_NOT_PRESENT; */ + scsi_cdrom_not_ready(dev); + return 0; + } + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ + buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ + buf[13] = (total_sectors >> 16) & 0xff; + buf[14] = (total_sectors >> 8) & 0xff; + buf[15] = total_sectors & 0xff; + + buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ + buf[17] = (total_sectors >> 16) & 0xff; + buf[18] = (total_sectors >> 8) & 0xff; + buf[19] = total_sectors & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 +2 ) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((4 + 2) >> 8) & 0xff; + buf[1] = (4 + 2) & 0xff; + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + scsi_cdrom_invalid_field(dev); + return 0; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 + 2) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + buf[6] = ((2048 + 4) >> 8) & 0xff; + buf[7] = (2048 + 4) & 0xff; + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + buf[10] = ((4 + 4) >> 8) & 0xff; + buf[11] = (4 + 4) & 0xff; + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + buf[14] = ((188 + 4) >> 8) & 0xff; + buf[15] = (188 + 4) & 0xff; + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + buf[18] = ((2048 + 4) >> 8) & 0xff; + buf[19] = (2048 + 4) & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[6] = ((16 + 2) >> 8) & 0xff; + buf[7] = (16 + 2) & 0xff; + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + scsi_cdrom_invalid_field(dev); + return 0; + } +} + + +static void +scsi_cdrom_insert(void *p) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + if (!dev) + return; + + dev->unit_attention = 1; + /* Turn off the medium changed status. */ + dev->drv->cd_status &= ~CD_STATUS_MEDIUM_CHANGED; + scsi_cdrom_log("CD-ROM %i: Media insert\n", dev->id); +} + + +static int +scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) +{ + int ready = 0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { + scsi_cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", + dev->id, ((dev->request_length >> 5) & 7)); + scsi_cdrom_invalid_lun(dev); + return 0; + } + } + + if (!(scsi_cdrom_command_flags[cdb[0]] & IMPLEMENTED)) { + scsi_cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], + (dev->drv->bus_type == CDROM_BUS_SCSI) ? "SCSI" : "ATAPI"); + + scsi_cdrom_illegal_opcode(dev); + return 0; + } + + if ((dev->drv->bus_type < CDROM_BUS_SCSI) && (scsi_cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { + scsi_cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); + scsi_cdrom_illegal_opcode(dev); + return 0; + } + + if ((dev->drv->bus_type == CDROM_BUS_SCSI) && (scsi_cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { + scsi_cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); + scsi_cdrom_illegal_opcode(dev); + return 0; + } + + if ((dev->drv->cd_status == CD_STATUS_PLAYING) || (dev->drv->cd_status == CD_STATUS_PAUSED)) { + ready = 1; + goto skip_ready_check; + } + + if (dev->drv->cd_status & CD_STATUS_MEDIUM_CHANGED) + scsi_cdrom_insert((void *) dev); + + ready = (dev->drv->cd_status != CD_STATUS_EMPTY); + +skip_ready_check: + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + if (!ready && dev->unit_attention) + dev->unit_attention = 0; + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (dev->unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) { + /* scsi_cdrom_log("CD-ROM %i: Unit attention now 2\n", dev->id); */ + dev->unit_attention++; + scsi_cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", + dev->id, cdb[0]); + scsi_cdrom_unit_attention(dev); + return 0; + } + } else if (dev->unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* scsi_cdrom_log("CD-ROM %i: Unit attention now 0\n", dev->id); */ + dev->unit_attention = 0; + } + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + scsi_cdrom_sense_clear(dev, cdb[0]); + + /* Next it's time for NOT READY. */ + if (!ready) + dev->media_status = MEC_MEDIA_REMOVAL; + else + dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + + if ((scsi_cdrom_command_flags[cdb[0]] & CHECK_READY) && !ready) { + scsi_cdrom_log("CD-ROM %i: Not ready (%02X)\n", dev->id, cdb[0]); + scsi_cdrom_not_ready(dev); + return 0; + } + + scsi_cdrom_log("CD-ROM %i: Continuing with command %02X\n", dev->id, cdb[0]); + + return 1; +} + + +static void +scsi_cdrom_rezero(scsi_cdrom_t *dev) +{ + dev->sector_pos = dev->sector_len = 0; + cdrom_seek(dev->drv, 0); +} + + +void +scsi_cdrom_reset(scsi_common_t *sc) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + + if (!dev) + return; + + scsi_cdrom_rezero(dev); + dev->status = 0; + dev->callback = 0.0; + scsi_cdrom_set_callback(dev); + dev->phase = 1; + dev->request_length = 0xEB14; + dev->packet_status = PHASE_NONE; + dev->unit_attention = 0xff; +} + + +static void +scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + memcpy(buffer, dev->sense, alloc_length); + } + + buffer[0] = 0x70; + + if ((scsi_cdrom_sense_key > 0) && (dev->drv->cd_status == CD_STATUS_PLAYING_COMPLETED)) { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } else if ((scsi_cdrom_sense_key == 0) && ((dev->drv->cd_status == CD_STATUS_PAUSED) || + ((dev->drv->cd_status >= CD_STATUS_PLAYING) && (dev->drv->cd_status != CD_STATUS_STOPPED)))) { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=(dev->drv->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } else if (dev->unit_attention && (scsi_cdrom_sense_key == 0)) { + buffer[2]=SENSE_UNIT_ATTENTION; + buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[13]=0; + } + + scsi_cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + + if (buffer[2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + dev->unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + scsi_cdrom_sense_clear(dev, GPCMD_REQUEST_SENSE); +} + + +void +scsi_cdrom_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + + if (dev->drv->cd_status & CD_STATUS_MEDIUM_CHANGED) + scsi_cdrom_insert((void *) dev); + + if ((dev->drv->cd_status == CD_STATUS_EMPTY) && dev->unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + dev->unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + scsi_cdrom_request_sense(dev, buffer, alloc_length); +} + + +static void +scsi_cdrom_set_buf_len(scsi_cdrom_t *dev, int32_t *BufLen, int32_t *src_len) +{ + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + scsi_cdrom_log("CD-ROM %i: Actual transfer length: %i\n", dev->id, *BufLen); + } +} + + +static void +scsi_cdrom_stop(scsi_common_t *sc) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + + cdrom_stop(dev->drv); +} + + +void +scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + int len, max_len, used_len, alloc_length, msf; + int pos = 0, i= 0, size_idx, idx = 0; + uint32_t feature; + unsigned preamble_len; + int toc_format, block_desc = 0; + int ret, format = 0; + int real_pos, track = 0; + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + int32_t blen = 0, *BufLen; + uint8_t *b; + uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; + dev->status &= ~ERR_STAT; + } else { + BufLen = &blen; + dev->error = 0; + } + + dev->packet_len = 0; + dev->request_pos = 0; + + device_identify[7] = dev->id + 0x30; + + device_identify_ex[7] = dev->id + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + memcpy(dev->current_cdb, cdb, 12); + + if (cdb[0] != 0) { + scsi_cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", + dev->id, cdb[0], scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq, dev->unit_attention); + scsi_cdrom_log("CD-ROM %i: Request length: %04X\n", dev->id, dev->request_length); + + scsi_cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + msf = cdb[1] & 2; + dev->sector_len = 0; + + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (scsi_cdrom_pre_execution_check(dev, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_TEST_UNIT_READY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_REZERO_UNIT: + scsi_cdrom_stop(sc); + dev->sector_pos = dev->sector_len = 0; + dev->drv->seek_diff = dev->drv->seek_pos; + cdrom_seek(dev->drv, 0); + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + + if (!max_len) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + break; + } + + scsi_cdrom_buf_alloc(dev, 256); + scsi_cdrom_set_buf_len(dev, BufLen, &max_len); + scsi_cdrom_request_sense(dev, dev->buffer, max_len); + scsi_cdrom_data_command_finish(dev, 18, 18, cdb[4], 0); + break; + + case GPCMD_SET_SPEED: + case GPCMD_SET_SPEED_ALT: + dev->drv->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; + if (dev->drv->cur_speed < 1) + dev->drv->cur_speed = 1; + else if (dev->drv->cur_speed > dev->drv->speed) + dev->drv->cur_speed = dev->drv->speed; + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_MECHANISM_STATUS: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + scsi_cdrom_buf_alloc(dev, 8); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + memset(dev->buffer, 0, 8); + dev->buffer[5] = 1; + + scsi_cdrom_data_command_finish(dev, 8, 8, len, 0); + break; + + case GPCMD_READ_TOC_PMA_ATIP: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + scsi_cdrom_buf_alloc(dev, 65536); + + toc_format = cdb[2] & 0xf; + + if (toc_format == 0) + toc_format = (cdb[9] >> 6) & 3; + + if (!dev->drv->ops) { + scsi_cdrom_not_ready(dev); + return; + } + + if (toc_format < 3) + len = cdrom_read_toc(dev->drv, dev->buffer, toc_format, cdb[6], msf, max_len); + else { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + /* scsi_cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", dev->id, + toc_format, ide->cylinder, dev->buffer[1]); */ + return; + + case GPCMD_READ_CD_OLD: + /* IMPORTANT: Convert the command to new read CD + for pass through purposes. */ + dev->current_cdb[0] = 0xbe; + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + case GPCMD_READ_CD: + case GPCMD_READ_CD_MSF: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + alloc_length = 2048; + + switch(cdb[0]) { + case GPCMD_READ_6: + dev->sector_len = cdb[4]; + if (dev->sector_len == 0) + dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + msf = 0; + break; + case GPCMD_READ_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_pos); + msf = 0; + break; + case GPCMD_READ_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + scsi_cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_pos); + msf = 0; + break; + case GPCMD_READ_CD_MSF: + alloc_length = 2856; + dev->sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); + dev->sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); + + dev->sector_len -= dev->sector_pos; + dev->sector_len++; + msf = 1; + break; + case GPCMD_READ_CD_OLD: + case GPCMD_READ_CD: + alloc_length = 2856; + dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + msf = 0; + break; + } + + if (!dev->sector_len) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + /* scsi_cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + scsi_cdrom_buf_alloc(dev, dev->packet_len); + + dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); + + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1); + if (ret <= 0) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + scsi_cdrom_buf_free(dev); + return; + } + + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + scsi_cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, + alloc_length, 0); + + if (dev->packet_status != PHASE_COMPLETE) + ui_sb_update_icon(SB_CDROM | dev->id, 1); + else + ui_sb_update_icon(SB_CDROM | dev->id, 0); + return; + + case GPCMD_READ_HEADER: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = ((cdb[7] << 8) | cdb[8]); + scsi_cdrom_buf_alloc(dev, 8); + + dev->sector_len = 1; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4]<<8) | cdb[5]; + if (msf) + real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); + else + real_pos = dev->sector_pos; + dev->buffer[0] = 1; /*2048 bytes user data*/ + dev->buffer[1] = dev->buffer[2] = dev->buffer[3] = 0; + dev->buffer[4] = (real_pos >> 24); + dev->buffer[5] = ((real_pos >> 16) & 0xff); + dev->buffer[6] = ((real_pos >> 8) & 0xff); + dev->buffer[7] = real_pos & 0xff; + + len = 8; + len = MIN(len, alloc_length); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdb[4]; + scsi_cdrom_buf_alloc(dev, 256); + } else { + len = (cdb[8] | (cdb[7] << 8)); + scsi_cdrom_buf_alloc(dev, 65536); + } + + if (!(scsi_cdrom_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + memset(dev->buffer, 0, len); + alloc_length = len; + + /* This determines the media type ID to return - this is + a SCSI/ATAPI-specific thing, so it makes the most sense + to keep this here. + Also, the max_len variable is reused as this command + does otherwise not use it, to avoid having to declare + another variable. */ + if (dev->drv->cd_status == CD_STATUS_EMPTY) + max_len = 70; /* No media inserted. */ + else if (dev->drv->cdrom_capacity > 405000) + max_len = 65; /* DVD. */ + else if (dev->drv->cd_status == CD_STATUS_DATA_ONLY) + max_len = 1; /* Data CD. */ + else + max_len = 3; /* Audio or mixed-mode CD. */ + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = scsi_cdrom_mode_sense(dev, dev->buffer, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + dev->buffer[0] = len - 1; + dev->buffer[1] = max_len; + if (block_desc) + dev->buffer[3] = 8; + } else { + len = scsi_cdrom_mode_sense(dev, dev->buffer, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + dev->buffer[0] = (len - 2) >> 8; + dev->buffer[1] = (len - 2) & 255; + dev->buffer[2] = max_len; + if (block_desc) { + dev->buffer[6] = 0; + dev->buffer[7] = 8; + } + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + + scsi_cdrom_data_command_finish(dev, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) { + len = cdb[4]; + scsi_cdrom_buf_alloc(dev, 256); + } else { + len = (cdb[7] << 8) | cdb[8]; + scsi_cdrom_buf_alloc(dev, 65536); + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + dev->total_length = len; + dev->do_page_save = cdb[1] & 1; + + scsi_cdrom_data_command_finish(dev, len, len, len, 1); + return; + + case GPCMD_GET_CONFIGURATION: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + /* XXX: could result in alignment problems in some architectures */ + feature = (cdb[2] << 8) | cdb[3]; + max_len = (cdb[7] << 8) | cdb[8]; + + /* only feature 0 is supported */ + if ((cdb[2] != 0) || (cdb[3] > 2)) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + scsi_cdrom_buf_alloc(dev, 65536); + memset(dev->buffer, 0, max_len); + + alloc_length = 0; + b = dev->buffer; + + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (dev->drv->cd_status != CD_STATUS_EMPTY) { + len = dev->drv->cdrom_capacity; + if (len > CD_MAX_SECTORS) { + b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_DVD_ROM & 0xff; + ret = 1; + } else { + b[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_CD_ROM & 0xff; + ret = 0; + } + } else + ret = 2; + + alloc_length = 8; + b += 8; + + if ((feature == 0) || ((cdb[1] & 3) < 2)) { + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + alloc_length += 4; + b += 4; + + for (i = 0; i < 2; i++) { + b[0] = (profiles[i] >> 8) & 0xff; + b[1] = profiles[i] & 0xff; + + if (ret == i) + b[2] |= 1; + + alloc_length += 4; + b += 4; + } + } + if ((feature == 1) || ((cdb[1] & 3) < 2)) { + b[1] = 1; + b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + b[7] = 1; + else + b[7] = 2; + b[8] = 1; + + alloc_length += 12; + b += 12; + } + if ((feature == 2) || ((cdb[1] & 3) < 2)) { + b[1] = 2; + b[2] = (1 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 4; + + b[4] = 2; + + alloc_length += 8; + b += 8; + } + + dev->buffer[0] = ((alloc_length - 4) >> 24) & 0xff; + dev->buffer[1] = ((alloc_length - 4) >> 16) & 0xff; + dev->buffer[2] = ((alloc_length - 4) >> 8) & 0xff; + dev->buffer[3] = (alloc_length - 4) & 0xff; + + alloc_length = MIN(alloc_length, max_len); + + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); + + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + scsi_cdrom_buf_alloc(dev, 8 + sizeof(gesn_event_header_t)); + + gesn_cdb = (void *) cdb; + gesn_event_header = (void *) dev->buffer; + + /* 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. */ + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + /* + * 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; + + dev->buffer[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ + dev->buffer[5] = 1; /* Power Status (1 = Active) */ + dev->buffer[6] = 0; + dev->buffer[7] = 0; + used_len = 8; + } else { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + + memcpy(dev->buffer, gesn_event_header, 4); + + scsi_cdrom_set_buf_len(dev, BufLen, &used_len); + + scsi_cdrom_data_command_finish(dev, used_len, used_len, used_len, 0); + break; + + case GPCMD_READ_DISC_INFORMATION: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + scsi_cdrom_buf_alloc(dev, 65536); + + memset(dev->buffer, 0, 34); + memset(dev->buffer, 1, 9); + dev->buffer[0] = 0; + dev->buffer[1] = 32; + dev->buffer[2] = 0xe; /* last session complete, disc finalized */ + dev->buffer[7] = 0x20; /* unrestricted use */ + dev->buffer[8] = 0x00; /* CD-ROM */ + + len=34; + len = MIN(len, max_len); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_READ_TRACK_INFORMATION: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + scsi_cdrom_buf_alloc(dev, 65536); + + track = ((uint32_t) cdb[2]) << 24; + track |= ((uint32_t) cdb[3]) << 16; + track |= ((uint32_t) cdb[4]) << 8; + track |= (uint32_t) cdb[5]; + + if (((cdb[1] & 0x03) != 1) || (track != 1)) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + len = 36; + + memset(dev->buffer, 0, 36); + dev->buffer[0] = 0; + dev->buffer[1] = 34; + dev->buffer[2] = 1; /* track number (LSB) */ + dev->buffer[3] = 1; /* session number (LSB) */ + dev->buffer[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ + dev->buffer[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ + dev->buffer[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ + + dev->buffer[24] = ((dev->drv->cdrom_capacity - 1) >> 24) & 0xff; /* track size */ + dev->buffer[25] = ((dev->drv->cdrom_capacity - 1) >> 16) & 0xff; /* track size */ + dev->buffer[26] = ((dev->drv->cdrom_capacity - 1) >> 8) & 0xff; /* track size */ + dev->buffer[27] = (dev->drv->cdrom_capacity - 1) & 0xff; /* track size */ + + if (len > max_len) { + len = max_len; + dev->buffer[0] = ((max_len - 2) >> 8) & 0xff; + dev->buffer[1] = (max_len - 2) & 0xff; + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PLAY_AUDIO_10: + case GPCMD_PLAY_AUDIO_12: + case GPCMD_PLAY_AUDIO_MSF: + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: + case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: + len = 0; + + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_PLAY_AUDIO_10: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_12: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + break; + 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. */ + msf = 1; + pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + msf = 2; + if ((cdb[5] != 1) || (cdb[8] != 1)) { + scsi_cdrom_illegal_mode(dev); + break; + } + pos = cdb[4]; + len = cdb[7]; + break; + case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: + msf = 0x100 | cdb[6]; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: + msf = 0x100 | cdb[10]; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + break; + } + + if ((dev->drv->host_drive < 1) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) { + scsi_cdrom_illegal_mode(dev); + break; + } + + ret = cdrom_audio_play(dev->drv, pos, len, msf); + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + break; + + case GPCMD_READ_SUBCHANNEL: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + msf = (cdb[1] >> 1) & 1; + + scsi_cdrom_buf_alloc(dev, 32); + + scsi_cdrom_log("CD-ROM %i: Getting page %i (%s)\n", dev->id, cdb[3], msf ? "MSF" : "LBA"); + + if (cdb[3] > 3) { + /* scsi_cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", dev->id, + cdb[3]); */ + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + if (!(cdb[2] & 0x40)) + alloc_length = 4; + else switch(cdb[3]) { + case 0: + /* SCSI-2: Q-type subchannel, ATAPI: reserved */ + alloc_length = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 48 : 4; + break; + case 1: + alloc_length = 16; + break; + default: + alloc_length = 24; + break; + } + + len = alloc_length; + + memset(dev->buffer, 0, 24); + pos = 0; + dev->buffer[pos++] = 0; + dev->buffer[pos++] = 0; /*Audio status*/ + dev->buffer[pos++] = 0; dev->buffer[pos++] = 0; /*Subchannel length*/ + /* Mode 0 = Q subchannel mode, first 16 bytes are indentical to mode 1 (current position), + the rest are stuff like ISRC etc., which can be all zeroes. */ + if (cdb[3] <= 3) { + dev->buffer[pos++] = cdb[3]; /*Format code*/ + + if (alloc_length != 4) { + dev->buffer[1] = cdrom_get_current_subchannel(dev->drv, &dev->buffer[4], msf); + dev->buffer[2] = alloc_length - 4; + } + + switch(dev->drv->cd_status) { + case CD_STATUS_PLAYING: + dev->buffer[1] = 0x11; + break; + case CD_STATUS_PAUSED: + dev->buffer[1] = 0x12; + break; + case CD_STATUS_DATA_ONLY: + dev->buffer[1] = 0x15; + break; + default: + dev->buffer[1] = 0x13; + break; + } + + scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[1]); + } + + len = MIN(len, max_len); + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_READ_DVD_STRUCTURE: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + + scsi_cdrom_buf_alloc(dev, alloc_length); + + if ((cdb[7] < 0xc0) && (dev->drv->cdrom_capacity <= CD_MAX_SECTORS)) { + scsi_cdrom_incompatible_format(dev); + scsi_cdrom_buf_free(dev); + return; + } + + memset(dev->buffer, 0, alloc_length); + + if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { + if (cdb[1] == 0) { + ret = scsi_cdrom_read_dvd_structure(dev, format, cdb, dev->buffer); + if (ret) { + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, + alloc_length, 0); + } else + scsi_cdrom_buf_free(dev); + return; + } + } else { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + break; + + case GPCMD_START_STOP_UNIT: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + scsi_cdrom_stop(sc); + break; + case 1: /* Start the disc and read the TOC. */ + /* This makes no sense under emulation as this would do + absolutely nothing, so just break. */ + break; + case 2: /* Eject the disc if possible. */ + scsi_cdrom_stop(sc); + cdrom_eject(dev->id); + break; + case 3: /* Load the disc (close tray). */ + cdrom_reload(dev->id); + break; + } + + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_INQUIRY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + scsi_cdrom_buf_alloc(dev, 65536); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + dev->buffer[idx++] = 05; + dev->buffer[idx++] = cdb[2]; + dev->buffer[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + dev->buffer[idx++] = 0x00; + dev->buffer[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + scsi_cdrom_data_phase_error(dev); + scsi_cdrom_buf_free(dev); + return; + } + + dev->buffer[idx++] = 0x02; + dev->buffer[idx++] = 0x00; + dev->buffer[idx++] = 0x00; + dev->buffer[idx++] = 20; + ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + dev->buffer[idx++] = 0x02; + dev->buffer[idx++] = 0x01; + dev->buffer[idx++] = 0x00; + dev->buffer[idx++] = 68; + ide_padstr8(dev->buffer + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(dev->buffer + idx, 40, device_identify_ex); /* Product */ + + idx += 40; + ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + scsi_cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(dev->buffer, 0, 8); + dev->buffer[0] = 5; /*CD-ROM*/ + dev->buffer[1] = 0x80; /*Removable*/ + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + dev->buffer[2] = 0x02; + dev->buffer[3] = 0x02; + } + else { + dev->buffer[2] = 0x00; + dev->buffer[3] = 0x21; + } + + dev->buffer[4] = 31; + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + dev->buffer[6] = 1; /* 16-bit transfers supported */ + dev->buffer[7] = 0x20; /* Wide bus supported */ + } + + ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ + ide_padstr8(dev->buffer + 32, 4, EMU_VERSION); /* Revision */ + + idx = 36; + + if (max_len == 96) { + dev->buffer[4] = 91; + idx = 96; + } + } + +atapi_out: + dev->buffer[size_idx] = idx - preamble_len; + len=idx; + + len = MIN(len, max_len); + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_PAUSE_RESUME_ALT: + case GPCMD_PAUSE_RESUME: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + cdrom_audio_pause_resume(dev->drv, cdb[8] & 0x01); + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + dev->drv->seek_diff = ABS((int) (pos - dev->drv->seek_pos)); + cdrom_seek(dev->drv, pos); + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_READ_CDROM_CAPACITY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + scsi_cdrom_buf_alloc(dev, 8); + + /* IMPORTANT: What's returned is the last LBA block. */ + memset(dev->buffer, 0, 8); + dev->buffer[0] = ((dev->drv->cdrom_capacity - 1) >> 24) & 0xff; + dev->buffer[1] = ((dev->drv->cdrom_capacity - 1) >> 16) & 0xff; + dev->buffer[2] = ((dev->drv->cdrom_capacity - 1) >> 8) & 0xff; + dev->buffer[3] = (dev->drv->cdrom_capacity - 1) & 0xff; + dev->buffer[6] = 8; + len = 8; + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_STOP_PLAY_SCAN: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + if (dev->drv->cd_status <= CD_STATUS_DATA_ONLY) { + scsi_cdrom_illegal_mode(dev); + break; + } + + scsi_cdrom_stop(sc); + scsi_cdrom_command_complete(dev); + break; + + default: + scsi_cdrom_illegal_opcode(dev); + break; + } + + /* scsi_cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ + + if (scsi_cdrom_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) + scsi_cdrom_buf_free(dev); +} + + +static void +scsi_cdrom_command_stop(scsi_common_t *sc) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + + scsi_cdrom_command_complete(dev); + scsi_cdrom_buf_free(dev); +} + + +/* The command second phase function, needed for Mode Select. */ +static uint8_t +scsi_cdrom_phase_data_out(scsi_common_t *sc) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + uint16_t block_desc_len, pos; + uint16_t i = 0; + + uint8_t error = 0; + uint8_t page, page_len, hdr_len, val, old_val, ch; + + switch(dev->current_cdb[0]) { + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = dev->buffer[2]; + block_desc_len <<= 8; + block_desc_len |= dev->buffer[3]; + } else { + block_desc_len = dev->buffer[6]; + block_desc_len <<= 8; + block_desc_len |= dev->buffer[7]; + } + } else + block_desc_len = 0; + + pos = hdr_len + block_desc_len; + + while(1) { + if (pos >= dev->current_cdb[4]) { + scsi_cdrom_log("CD-ROM %i: Buffer has only block descriptor\n", dev->id); + break; + } + + page = dev->buffer[pos] & 0x3F; + page_len = dev->buffer[pos + 1]; + + pos += 2; + + if (!(scsi_cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { + scsi_cdrom_log("CD-ROM %i: Unimplemented page %02X\n", dev->id, page); + error |= 1; + } else { + for (i = 0; i < page_len; i++) { + ch = scsi_cdrom_mode_sense_pages_changeable.pages[page][i + 2]; + val = dev->buffer[pos + i]; + old_val = dev->ms_pages_saved.pages[page][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else { + scsi_cdrom_log("CD-ROM %i: Unchangeable value on position %02X on page %02X\n", dev->id, i + 2, page); + error |= 1; + } + } + } + } + + pos += page_len; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + val = scsi_cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; + else + val = scsi_cdrom_mode_sense_pages_default.pages[page][0] & 0x80; + + if (dev->do_page_save && val) + scsi_cdrom_mode_sense_save(dev); + + if (pos >= dev->total_length) + break; + } + + if (error) { + scsi_cdrom_invalid_field_pl(dev); + scsi_cdrom_buf_free(dev); + return 0; + } + break; + } + + scsi_cdrom_command_stop((scsi_common_t *) dev); + return 1; +} + + +static void +scsi_cdrom_close(void *p) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + if (dev) + free(dev); +} + + +static int +scsi_cdrom_get_max(int ide_has_dma, int type) +{ + int ret; + + switch(type) { + case TYPE_PIO: + ret = ide_has_dma ? 4 : 0; + break; + case TYPE_SDMA: + ret = ide_has_dma ? 2 : -1; + break; + case TYPE_MDMA: + ret = ide_has_dma ? 2 : -1; + break; + case TYPE_UDMA: + ret = ide_has_dma ? 2 : -1; + break; + default: + ret = -1; + break; + } + + return ret; +} + + +static int +scsi_cdrom_get_timings(int ide_has_dma, int type) +{ + int ret; + + switch(type) { + case TIMINGS_DMA: + ret = ide_has_dma ? 120 : 0; + break; + case TIMINGS_PIO: + ret = ide_has_dma ? 120 : 0; + break; + case TIMINGS_PIO_FC: + ret = 0; + break; + default: + ret = 0; + break; + } + + return ret; +} + + +/** + * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command + */ +static void +scsi_cdrom_identify(ide_t *ide, int ide_has_dma) +{ +#if 0 + scsi_cdrom_t *dev; + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + + dev = (scsi_cdrom_t *) ide->p; + + device_identify[7] = dev->id + 0x30; + scsi_cdrom_log("ATAPI Identify: %s\n", device_identify); +#endif + + 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 */ +#if 0 + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 23), "4.20 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:273 ", 40); /* Model */ +#endif + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (ide_has_dma) { + ide->buffer[71] = 30; + ide->buffer[72] = 30; + } +} + + +void +scsi_cdrom_drive_reset(int c) +{ + cdrom_t *drv = &cdrom[c]; + scsi_cdrom_t *dev; + scsi_device_t *sd; + ide_t *id; + + /* Make sure to ignore any SCSI CD-ROM drive that has an out of range ID. */ + if ((drv->bus_type == CDROM_BUS_SCSI) && (drv->scsi_device_id > SCSI_ID_MAX)) + return; + + /* Make sure to ignore any ATAPI CD-ROM drive that has an out of range IDE channel. */ + if ((drv->bus_type == CDROM_BUS_ATAPI) && (drv->ide_channel > 7)) + return; + + if (!drv->priv) { + drv->priv = (scsi_cdrom_t *) malloc(sizeof(scsi_cdrom_t)); + memset(drv->priv, 0, sizeof(scsi_cdrom_t)); + } + + dev = (scsi_cdrom_t *) drv->priv; + + dev->id = c; + dev->drv = drv; + drv->insert = scsi_cdrom_insert; + drv->get_volume = scsi_cdrom_get_volume; + drv->get_channel = scsi_cdrom_get_channel; + drv->close = scsi_cdrom_close; + + scsi_cdrom_init(dev); + + if (drv->bus_type == CDROM_BUS_SCSI) { + /* SCSI CD-ROM, attach to the SCSI bus. */ + sd = &scsi_devices[drv->scsi_device_id]; + + sd->sc = (scsi_common_t *) dev; + sd->command = scsi_cdrom_command; + sd->request_sense = scsi_cdrom_request_sense_for_scsi; + sd->reset = scsi_cdrom_reset; + sd->phase_data_out = scsi_cdrom_phase_data_out; + sd->command_stop = scsi_cdrom_command_stop; + sd->type = SCSI_REMOVABLE_CDROM; + + scsi_cdrom_log("SCSI CD-ROM drive %i attached to SCSI ID %i\n", c, cdrom[c].scsi_device_id); + } else if (drv->bus_type == CDROM_BUS_ATAPI) { + /* ATAPI CD-ROM, attach to the IDE bus. */ + id = ide_get_drive(drv->ide_channel); + /* If the IDE channel is initialized, we attach to it, + otherwise, we do nothing - it's going to be a drive + that's not attached to anything. */ + if (id) { + id->sc = (scsi_common_t *) dev; + id->get_max = scsi_cdrom_get_max; + id->get_timings = scsi_cdrom_get_timings; + id->identify = scsi_cdrom_identify; + id->stop = scsi_cdrom_stop; + id->packet_command = scsi_cdrom_command; + id->device_reset = scsi_cdrom_reset; + id->phase_data_out = scsi_cdrom_phase_data_out; + id->command_stop = scsi_cdrom_command_stop; + id->bus_master_error = scsi_cdrom_bus_master_error; + id->interrupt_drq = 0; + + ide_atapi_attach(id); + } + + scsi_cdrom_log("ATAPI CD-ROM drive %i attached to IDE channel %i\n", c, cdrom[c].ide_channel); + } +} diff --git a/src/scsi/scsi_cdrom.h b/src/scsi/scsi_cdrom.h new file mode 100644 index 000000000..1c8be1382 --- /dev/null +++ b/src/scsi/scsi_cdrom.h @@ -0,0 +1,69 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)scsi_cdrom.h 1.0.2 2019/11/19 + * + * Author: Miran Grca, + * + * Copyright 2018,2019 Miran Grca. + */ +#ifndef EMU_SCSI_CDROM_H +#define EMU_SCSI_CDROM_H + + +#define CDROM_TIME 10.0 + + +#ifdef SCSI_DEVICE_H +typedef struct { + /* Common block. */ + mode_sense_pages_t ms_pages_saved; + + cdrom_t *drv; + + uint8_t *buffer, + atapi_cdb[16], + current_cdb[16], + sense[256]; + + uint8_t status, phase, + error, id, + features, pad0, + pad1, pad2; + + uint16_t request_length, max_transfer_len; + + int requested_blocks, packet_status, + total_length, do_page_save, + unit_attention, request_pos, + old_len, media_status; + + uint32_t sector_pos, sector_len, + packet_len, pos; + + double callback; +} scsi_cdrom_t; +#endif + + +extern scsi_cdrom_t *scsi_cdrom[CDROM_NUM]; + +#define scsi_cdrom_sense_error dev->sense[0] +#define scsi_cdrom_sense_key dev->sense[2] +#define scsi_cdrom_asc dev->sense[12] +#define scsi_cdrom_ascq dev->sense[13] +#define scsi_cdrom_drive cdrom_drives[id].host_drive + + +extern void scsi_cdrom_reset(scsi_common_t *sc); + + +#endif /*EMU_SCSI_CDROM_H*/ diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index f5567cb74..c0fe14694 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -8,7 +8,7 @@ * * The generic SCSI device command handler. * - * Version: @(#)scsi_device.c 1.0.17 2018/06/02 + * Version: @(#)scsi_device.c 1.0.23 2018/10/31 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -25,325 +25,148 @@ #include "../disk/hdd.h" #include "scsi.h" #include "scsi_device.h" -#include "../cdrom/cdrom.h" -#include "../disk/zip.h" -#include "scsi_disk.h" +scsi_device_t scsi_devices[SCSI_ID_MAX]; + uint8_t scsi_null_device_sense[18] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0,0,0,0,0 }; static uint8_t -scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb) +scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb) { - switch(lun_type) { - case SCSI_DISK: - scsi_disk_command(scsi_disk[id], cdb); - return scsi_disk_err_stat_to_scsi(scsi_disk[id]); - case SCSI_CDROM: - cdrom_command(cdrom[id], cdb); - return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); - case SCSI_ZIP: - zip_command(zip[id], cdb); - return zip_ZIP_PHASE_to_scsi(zip[id]); - default: + if (dev->command) { + dev->command(dev->sc, cdb); + + if (dev->sc->status & ERR_STAT) return SCSI_STATUS_CHECK_CONDITION; - } + else + return SCSI_STATUS_OK; + } else + return SCSI_STATUS_CHECK_CONDITION; } -static void scsi_device_target_phase_callback(int lun_type, uint8_t id) +double +scsi_device_get_callback(scsi_device_t *dev) { - switch(lun_type) { - case SCSI_DISK: - scsi_disk_callback(scsi_disk[id]); - break; - case SCSI_CDROM: - cdrom_phase_callback(cdrom[id]); - break; - case SCSI_ZIP: - zip_phase_callback(zip[id]); - break; - } - return; + if (dev->sc) + return dev->sc->callback; + else + return -1.0; } -static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id) +uint8_t * +scsi_device_sense(scsi_device_t *dev) { - switch(lun_type) { - case SCSI_DISK: - return scsi_disk_err_stat_to_scsi(scsi_disk[id]); - case SCSI_CDROM: - return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); - case SCSI_ZIP: - return zip_ZIP_PHASE_to_scsi(zip[id]); - default: - return SCSI_STATUS_CHECK_CONDITION; - } + if (dev->sc) + return dev->sc->sense; + else + return scsi_null_device_sense; } -int64_t scsi_device_get_callback(uint8_t scsi_id) +void +scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - return scsi_disk[id]->callback; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - return cdrom[id]->callback; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - return zip[id]->callback; - break; - default: - return -1LL; - break; - } + if (dev->request_sense) + dev->request_sense(dev->sc, buffer, alloc_length); + else + memcpy(buffer, scsi_null_device_sense, alloc_length); } -uint8_t *scsi_device_sense(uint8_t scsi_id) +void +scsi_device_reset(scsi_device_t *dev) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - return scsi_disk[id]->sense; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - return cdrom[id]->sense; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - return zip[id]->sense; - break; - default: - return scsi_null_device_sense; - break; - } + if (dev->reset) + dev->reset(dev->sc); } -void scsi_device_request_sense(uint8_t scsi_id, uint8_t *buffer, uint8_t alloc_length) +int +scsi_device_present(scsi_device_t *dev) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - scsi_disk_request_sense_for_scsi(scsi_disk[id], buffer, alloc_length); - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - cdrom_request_sense_for_scsi(cdrom[id], buffer, alloc_length); - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - zip_request_sense_for_scsi(zip[id], buffer, alloc_length); - break; - default: - memcpy(buffer, scsi_null_device_sense, alloc_length); - break; - } + if (dev->type == SCSI_NONE) + return 0; + else + return 1; } -void scsi_device_reset(uint8_t scsi_id) +int +scsi_device_valid(scsi_device_t *dev) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - scsi_disk_reset(scsi_disk[id]); - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - cdrom_reset(cdrom[id]); - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - zip_reset(zip[id]); - break; - } + if (dev->sc) + return 1; + else + return 0; } -void scsi_device_type_data(uint8_t scsi_id, uint8_t *type, uint8_t *rmb) -{ - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - switch (lun_type) - { - case SCSI_DISK: - *type = *rmb = 0x00; - break; - case SCSI_CDROM: - *type = 0x05; - *rmb = 0x80; - break; - case SCSI_ZIP: - *type = 0x00; - *rmb = 0x80; - break; - default: - *type = *rmb = 0xff; - break; - } -} - - -int scsi_device_read_capacity(uint8_t scsi_id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - return scsi_disk_read_capacity(scsi_disk[id], cdb, buffer, len); - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - return cdrom_read_capacity(cdrom[id], cdb, buffer, len); - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - return zip_read_capacity(zip[id], cdb, buffer, len); - default: - return 0; - } -} - - -int scsi_device_present(uint8_t scsi_id) -{ - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - switch (lun_type) - { - case SCSI_NONE: - return 0; - default: - return 1; - } -} - - -int scsi_device_valid(uint8_t scsi_id) -{ - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - break; - default: - id = 0; - break; - } - - return (id == 0xFF) ? 0 : 1; -} - - -int scsi_device_cdb_length(uint8_t scsi_id) +int +scsi_device_cdb_length(scsi_device_t *dev) { /* Right now, it's 12 for all devices. */ return 12; } -void scsi_device_command_phase0(uint8_t scsi_id, uint8_t *cdb) +void +scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb) { - uint8_t id = 0; - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - switch (lun_type) { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - break; - default: - id = 0; - SCSIDevices[scsi_id].Phase = SCSI_PHASE_STATUS; - SCSIDevices[scsi_id].Status = SCSI_STATUS_CHECK_CONDITION; - return; + if (!dev->sc) { + dev->phase = SCSI_PHASE_STATUS; + dev->status = SCSI_STATUS_CHECK_CONDITION; + return; } /* Finally, execute the SCSI command immediately and get the transfer length. */ - SCSIDevices[scsi_id].Phase = SCSI_PHASE_COMMAND; - SCSIDevices[scsi_id].Status = scsi_device_target_command(lun_type, id, cdb); - - if (SCSIDevices[scsi_id].Phase == SCSI_PHASE_STATUS) { - /* Command completed (either OK or error) - call the phase callback to complete the command. */ - scsi_device_target_phase_callback(lun_type, id); - } - /* If the phase is DATA IN or DATA OUT, finish this here. */ + dev->phase = SCSI_PHASE_COMMAND; + dev->status = scsi_device_target_command(dev, cdb); } -void scsi_device_command_phase1(uint8_t scsi_id) -{ - uint8_t id = 0; - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - switch (lun_type) { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - break; - default: - id = 0; - return; +void +scsi_device_command_stop(scsi_device_t *dev) +{ + if (dev->command_stop) { + dev->command_stop(dev->sc); + dev->status = SCSI_STATUS_OK; } +} + + +void +scsi_device_command_phase1(scsi_device_t *dev) +{ + if (!dev->sc) + return; /* Call the second phase. */ - scsi_device_target_phase_callback(lun_type, id); - SCSIDevices[scsi_id].Status = scsi_device_target_err_stat_to_scsi(lun_type, id); - /* Command second phase complete - call the callback to complete the command. */ - scsi_device_target_phase_callback(lun_type, id); + if (dev->phase == SCSI_PHASE_DATA_OUT) { + if (dev->phase_data_out) + dev->phase_data_out(dev->sc); + } else + scsi_device_command_stop(dev); + + if (dev->sc->status & ERR_STAT) + dev->status = SCSI_STATUS_CHECK_CONDITION; + else + dev->status = SCSI_STATUS_OK; } -int32_t *scsi_device_get_buf_len(uint8_t scsi_id) + +void +scsi_device_close_all(void) { - return &SCSIDevices[scsi_id].BufferLength; + int i; + scsi_device_t *dev; + + for (i = 0; i < SCSI_ID_MAX; i++) { + dev = &(scsi_devices[i]); + if (dev->command_stop && dev->sc) + dev->command_stop(dev->sc); + } } diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index d0da9a19b..5527dae0e 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -8,48 +8,367 @@ * * Definitions for the generic SCSI device command handler. * - * Version: @(#)scsi_device.h 1.0.8 2018/06/12 + * Version: @(#)scsi_device.h 1.0.17 2019/09/26 * * Authors: Miran Grca, * Fred N. van Kempen, + * + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef SCSI_DEVICE_H # define SCSI_DEVICE_H -typedef struct -{ - int state; - int new_state; - int clear_req; - uint32_t bus_in, bus_out; - int dev_id; - int command_pos; - uint8_t command[20]; - int data_pos; +/* Configuration. */ +#define SCSI_ID_MAX 16 /* 16 on wide buses */ +#define SCSI_LUN_MAX 8 /* always 8 */ + +#ifdef WALTJE +#define SCSI_TIME 50.0 +#else +#define SCSI_TIME 500.0 +#endif + + +/* Bits of 'status' */ +#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 */ + +/* SCSI commands. */ +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_REZERO_UNIT 0x01 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_IOMEGA_SENSE 0x06 +#define GPCMD_READ_6 0x08 +#define GPCMD_WRITE_6 0x0a +#define GPCMD_SEEK_6 0x0b +#define GPCMD_IOMEGA_SET_PROTECTION_MODE 0x0c +#define GPCMD_IOMEGA_EJECT 0x0d /* ATAPI only? */ +#define GPCMD_INQUIRY 0x12 +#define GPCMD_VERIFY_6 0x13 +#define GPCMD_MODE_SELECT_6 0x15 +#define GPCMD_SCSI_RESERVE 0x16 +#define GPCMD_SCSI_RELEASE 0x17 +#define GPCMD_MODE_SENSE_6 0x1a +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_SEND_DIAGNOSTIC 0x1d +#define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_CDROM_CAPACITY 0x25 +#define GPCMD_READ_10 0x28 +#define GPCMD_WRITE_10 0x2a +#define GPCMD_SEEK_10 0x2b +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_READ_BUFFER 0x3c +#define GPCMD_WRITE_SAME_10 0x41 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TRACK_INDEX 0x48 +#define GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10 0x49 +#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_READ_TRACK_INFORMATION 0x52 +#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_PLAY_AUDIO_TRACK_RELATIVE_12 0xa9 +#define GPCMD_WRITE_12 0xaa +#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_WRITE_AND_VERIFY_12 0xae +#define GPCMD_VERIFY_12 0xaf +#define GPCMD_PLAY_CD_OLD 0xb4 +#define GPCMD_READ_CD_OLD 0xb8 +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_SCAN 0xba +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_READ_CD 0xbe +#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ +#define GPCMD_PAUSE_RESUME_ALT 0xc2 +#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */ +#define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_DISCONNECT_PAGE 0x02 /* Disconnect/reconnect page */ +#define GPMODE_FORMAT_DEVICE_PAGE 0x03 +#define GPMODE_RIGID_DISK_PAGE 0x04 /* Rigid disk geometry page */ +#define GPMODE_FLEXIBLE_DISK_PAGE 0x05 +#define GPMODE_CACHING_PAGE 0x08 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_IOMEGA_PAGE 0x2f +#define GPMODE_UNK_VENDOR_PAGE 0x30 +#define GPMODE_ALL_PAGES 0x3f + +/* Mode page codes for presence */ +#define GPMODEP_R_W_ERROR_PAGE 0x0000000000000002LL +#define GPMODEP_DISCONNECT_PAGE 0x0000000000000004LL +#define GPMODEP_FORMAT_DEVICE_PAGE 0x0000000000000008LL +#define GPMODEP_RIGID_DISK_PAGE 0x0000000000000010LL +#define GPMODEP_FLEXIBLE_DISK_PAGE 0x0000000000000020LL +#define GPMODEP_CACHING_PAGE 0x0000000000000100LL +#define GPMODEP_CDROM_PAGE 0x0000000000002000LL +#define GPMODEP_CDROM_AUDIO_PAGE 0x0000000000004000LL +#define GPMODEP_CAPABILITIES_PAGE 0x0000040000000000LL +#define GPMODEP_IOMEGA_PAGE 0x0000800000000000LL +#define GPMODEP_UNK_VENDOR_PAGE 0x0001000000000000LL +#define GPMODEP_ALL_PAGES 0x8000000000000000LL + +/* SCSI Status Codes */ +#define SCSI_STATUS_OK 0 +#define SCSI_STATUS_CHECK_CONDITION 2 + +/* SCSI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* SCSI Additional Sense Codes */ +#define ASC_NONE 0x00 +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_NOT_READY 0x04 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LBA_OUT_OF_RANGE 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_INV_LUN 0x25 +#define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26 +#define ASC_WRITE_PROTECTED 0x27 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_CAPACITY_DATA_CHANGED 0x2A +#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 + +#define ASCQ_NONE 0x00 +#define ASCQ_UNIT_IN_PROCESS_OF_BECOMING_READY 0x01 +#define ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02 +#define ASCQ_CAPACITY_DATA_CHANGED 0x09 +#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 /* 0x2C2 */ + +#define BUFFER_SIZE (256*1024) + +#define RW_DELAY (TIMER_USEC * 500) + +/* Some generally useful CD-ROM information */ +#define CD_MINS 75 /* max. minutes per CD */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) - int change_state_delay; - int new_req_delay; -} scsi_bus_t; +/* 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 -extern uint8_t *scsi_device_sense(uint8_t id); -extern void scsi_device_type_data(uint8_t id, uint8_t *type, uint8_t *rmb); -extern int64_t scsi_device_get_callback(uint8_t scsi_id); -extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t *buffer, +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +/* + * The MMC values are not IDE specific and might need to be moved + * to a common header if they are also needed for the SCSI emulation + */ + +/* Profile list from MMC-6 revision 1 table 91 */ +#define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_CD_ROM 0x0008 +#define MMC_PROFILE_CD_R 0x0009 +#define MMC_PROFILE_CD_RW 0x000A +#define MMC_PROFILE_DVD_ROM 0x0010 +#define MMC_PROFILE_DVD_R_SR 0x0011 +#define MMC_PROFILE_DVD_RAM 0x0012 +#define MMC_PROFILE_DVD_RW_RO 0x0013 +#define MMC_PROFILE_DVD_RW_SR 0x0014 +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 +#define MMC_PROFILE_DVD_RW_DL 0x0017 +#define MMC_PROFILE_DVD_DDR 0x0018 +#define MMC_PROFILE_DVD_PLUS_RW 0x001A +#define MMC_PROFILE_DVD_PLUS_R 0x001B +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B +#define MMC_PROFILE_BD_ROM 0x0040 +#define MMC_PROFILE_BD_R_SRM 0x0041 +#define MMC_PROFILE_BD_R_RRM 0x0042 +#define MMC_PROFILE_BD_RE 0x0043 +#define MMC_PROFILE_HDDVD_ROM 0x0050 +#define MMC_PROFILE_HDDVD_R 0x0051 +#define MMC_PROFILE_HDDVD_RAM 0x0052 +#define MMC_PROFILE_HDDVD_RW 0x0053 +#define MMC_PROFILE_HDDVD_R_DL 0x0058 +#define MMC_PROFILE_HDDVD_RW_DL 0x005A +#define MMC_PROFILE_INVALID 0xFFFF + +#define SCSI_ONLY 32 +#define ATAPI_ONLY 16 +#define IMPLEMENTED 8 +#define NONDATA 4 +#define CHECK_READY 2 +#define ALLOW_UA 1 + +#define MSFtoLBA(m,s,f) ((((m * 60) + s) * 75) + f) + +#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) + +#define PHASE_IDLE 0x00 +#define PHASE_COMMAND 0x01 +#define PHASE_DATA_IN 0x02 +#define PHASE_DATA_OUT 0x03 +#define PHASE_DATA_IN_DMA 0x04 +#define PHASE_DATA_OUT_DMA 0x05 +#define PHASE_COMPLETE 0x06 +#define PHASE_ERROR 0x80 +#define PHASE_NONE 0xff + +#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 MODE_SELECT_PHASE_IDLE 0 +#define MODE_SELECT_PHASE_HEADER 1 +#define MODE_SELECT_PHASE_BLOCK_DESC 2 +#define MODE_SELECT_PHASE_PAGE_HEADER 3 +#define MODE_SELECT_PHASE_PAGE 4 + +typedef struct { + uint8_t pages[0x40][0x40]; +} mode_sense_pages_t; + +/* This is so we can access the common elements to all SCSI device structs + without knowing the device type. */ +typedef struct scsi_common_s { + mode_sense_pages_t ms_pages_saved; + + void *p; + + uint8_t *temp_buffer, + atapi_cdb[16], /* This is atapi_cdb in ATAPI-supporting devices, + and pad in SCSI-only devices. */ + current_cdb[16], + sense[256]; + + uint8_t status, phase, + error, id, + features, pad, + pad0, pad1; + + uint16_t request_length, max_transfer_len; + + int requested_blocks, packet_status, + total_length, do_page_save, + unit_attention, request_pos, + old_len, media_status; + + uint32_t sector_pos, sector_len, + packet_len, pos; + + double callback; +} scsi_common_t; + +typedef struct { + int32_t buffer_length; + + uint8_t status, phase; + uint16_t type; + + scsi_common_t *sc; + + void (*command)(scsi_common_t *sc, uint8_t *cdb); + void (*request_sense)(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length); + void (*reset)(scsi_common_t *sc); + uint8_t (*phase_data_out)(scsi_common_t *sc); + void (*command_stop)(scsi_common_t *sc); +} scsi_device_t; + +/* These are based on the INQUIRY values. */ +#define SCSI_NONE 0x0060 +#define SCSI_FIXED_DISK 0x0000 +#define SCSI_REMOVABLE_DISK 0x8000 +#define SCSI_REMOVABLE_CDROM 0x8005 + +extern scsi_device_t scsi_devices[SCSI_ID_MAX]; + + +extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); +extern int cdrom_LBAtoMSF_accurate(void); + +extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save); +extern int mode_select_terminate(int force); +extern int mode_select_write(uint8_t val); + +extern uint8_t *scsi_device_sense(scsi_device_t *dev); +extern double scsi_device_get_callback(scsi_device_t *dev); +extern void scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length); -extern void scsi_device_reset(uint8_t scsi_id); -extern int scsi_device_read_capacity(uint8_t id, uint8_t *cdb, - uint8_t *buffer, uint32_t *len); -extern int scsi_device_present(uint8_t id); -extern int scsi_device_valid(uint8_t id); -extern int scsi_device_cdb_length(uint8_t id); -extern void scsi_device_command(uint8_t id, int cdb_len, uint8_t *cdb); -extern void scsi_device_command_phase0(uint8_t scsi_id, uint8_t *cdb); -extern void scsi_device_command_phase1(uint8_t scsi_id); -extern int32_t *scsi_device_get_buf_len(uint8_t scsi_id); - -extern int scsi_bus_update(scsi_bus_t *bus, int bus_assert); -extern int scsi_bus_read(scsi_bus_t *bus); -extern int scsi_bus_match(scsi_bus_t *bus, int bus_assert); +extern void scsi_device_reset(scsi_device_t *dev); +extern int scsi_device_present(scsi_device_t *dev); +extern int scsi_device_valid(scsi_device_t *dev); +extern int scsi_device_cdb_length(scsi_device_t *dev); +extern void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb); +extern void scsi_device_command_phase1(scsi_device_t *dev); +extern void scsi_device_command_stop(scsi_device_t *dev); +extern void scsi_device_close_all(void); #endif /*SCSI_DEVICE_H*/ diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 22d7f117b..91256b4dc 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -6,7 +6,7 @@ * * Emulation of SCSI fixed disks. * - * Version: @(#)scsi_disk.c 1.0.20 2018/05/28 + * Version: @(#)scsi_disk.c 1.0.30 2018/11/02 * * Author: Miran Grca, * @@ -26,42 +26,19 @@ #include "../piix.h" #include "../disk/hdd.h" #include "../disk/hdc.h" +#include "scsi_device.h" #include "../disk/hdc_ide.h" #include "../plat.h" #include "../ui.h" -#include "scsi.h" -#include "../cdrom/cdrom.h" #include "scsi_disk.h" -/* Bits of 'status' */ -#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 MAX_BLOCKS_AT_ONCE 340 - #define scsi_disk_sense_error dev->sense[0] #define scsi_disk_sense_key dev->sense[2] #define scsi_disk_asc dev->sense[12] #define scsi_disk_ascq dev->sense[13] -scsi_disk_t *scsi_disk[HDD_NUM]; - -uint8_t scsi_disks[16] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - - /* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ const uint8_t scsi_disk_command_flags[0x100] = { IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ @@ -126,31 +103,32 @@ const uint8_t scsi_disk_command_flags[0x100] = { }; -uint64_t scsi_disk_mode_sense_page_flags = (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F); +uint64_t scsi_disk_mode_sense_page_flags = (GPMODEP_FORMAT_DEVICE_PAGE | + GPMODEP_RIGID_DISK_PAGE | + GPMODEP_UNK_VENDOR_PAGE | + GPMODEP_ALL_PAGES); /* This should be done in a better way but for time being, it's been done this way so it's not as huge and more readable. */ static const mode_sense_pages_t scsi_disk_mode_sense_pages_default = -{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, - [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } +{ { [GPMODE_FORMAT_DEVICE_PAGE] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [GPMODE_RIGID_DISK_PAGE ] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 200, 0xff, 0xff, 0xff, 0, 0, 0, 0x15, 0x18, 0, 0 }, + [GPMODE_UNK_VENDOR_PAGE ] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } } }; static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = -{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, - [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } +{ { [GPMODE_FORMAT_DEVICE_PAGE] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [GPMODE_RIGID_DISK_PAGE ] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [GPMODE_UNK_VENDOR_PAGE ] = { 0xB0, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } } }; #ifdef ENABLE_SCSI_DISK_LOG int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG; -#endif static void scsi_disk_log(const char *fmt, ...) { -#ifdef ENABLE_SCSI_DISK_LOG va_list ap; if (scsi_disk_do_log) { @@ -158,61 +136,10 @@ scsi_disk_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define scsi_disk_log(fmt, ...) #endif -} - - -/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int -scsi_disk_err_stat_to_scsi(scsi_disk_t *dev) -{ - if (dev->status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; -} - - -int -find_hdd_for_scsi_id(uint8_t scsi_id) -{ - uint8_t i = 0; - - for (i = 0; i < HDD_NUM; i++) { - if (wcslen(hdd[i].fn) == 0) - continue; - if ((hdd[i].spt == 0) || (hdd[i].hpc == 0) || (hdd[i].tracks == 0)) - continue; - if ((hdd[i].bus == HDD_BUS_SCSI) && (hdd[i].scsi_id == scsi_id)) - return i; - } - return 0xff; -} - - -void -scsi_loadhd(int scsi_id, int id) -{ - if (! hdd_image_load(id)) - scsi_disks[scsi_id] = 0xff; -} - - -void -build_scsi_disk_map(void) -{ - uint8_t i = 0; - - memset(scsi_disks, 0xff, 16); - - for (i = 0; i < 16; i++) { - scsi_disks[i] = find_hdd_for_scsi_id(i); - if (scsi_disks[i] != 0xff) { - if (wcslen(hdd[scsi_disks[i]].fn) > 0) - scsi_loadhd(i, scsi_disks[i]); - } - } -} void @@ -220,16 +147,12 @@ scsi_disk_mode_sense_load(scsi_disk_t *dev) { FILE *f; wchar_t file_name[512]; - int i; + memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (scsi_disk_mode_sense_pages_default.pages[i][1] != 0) { - memcpy(dev->ms_pages_saved.pages[i], scsi_disk_mode_sense_pages_default.pages[i], - scsi_disk_mode_sense_pages_default.pages[i][1] + 2); - } - } - swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); + memcpy(&dev->ms_pages_saved, &scsi_disk_mode_sense_pages_default, sizeof(mode_sense_pages_t)); + memset(file_name, 0, 512 * sizeof(wchar_t)); + swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); f = plat_fopen(nvr_path(file_name), L"rb"); if (f) { fread(dev->ms_pages_saved.pages[0x30], 1, 0x18, f); @@ -243,6 +166,7 @@ scsi_disk_mode_sense_save(scsi_disk_t *dev) { FILE *f; wchar_t file_name[512]; + memset(file_name, 0, 512 * sizeof(wchar_t)); swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); f = plat_fopen(nvr_path(file_name), L"wb"); @@ -253,39 +177,62 @@ scsi_disk_mode_sense_save(scsi_disk_t *dev) } -int -scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - int size = 0; - - size = hdd_image_get_last_sector(dev->id); - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 2; /* 512 = 0x0200 */ - *len = 8; - - return 1; -} - - /*SCSI Mode Sense 6/10*/ uint8_t scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) { - switch (page_control) { + if (page_control == 1) + return scsi_disk_mode_sense_pages_changeable.pages[page][pos]; + + if (page == GPMODE_RIGID_DISK_PAGE) switch (page_control) { + /* Rigid disk geometry page. */ + case 0: + case 2: + case 3: + switch(pos) { + case 0: + case 1: + default: + return scsi_disk_mode_sense_pages_default.pages[page][pos]; + case 2: + case 6: + case 9: + return (dev->drv->tracks >> 16) & 0xff; + case 3: + case 7: + case 10: + return (dev->drv->tracks >> 8) & 0xff; + case 4: + case 8: + case 11: + return dev->drv->tracks & 0xff; + case 5: + return dev->drv->hpc & 0xff; + } + break; + } else if (page == GPMODE_FORMAT_DEVICE_PAGE) switch (page_control) { + /* Format device page. */ + case 0: + case 2: + case 3: + switch(pos) { + case 0: + case 1: + default: + return scsi_disk_mode_sense_pages_default.pages[page][pos]; + /* Actual sectors + the 1 "alternate sector" we report. */ + case 10: + return ((dev->drv->spt + 1) >> 8) & 0xff; + case 11: + return (dev->drv->spt + 1) & 0xff; + } + break; + } else switch (page_control) { case 0: case 3: return dev->ms_pages_saved.pages[page][pos]; - break; - case 1: - return scsi_disk_mode_sense_pages_changeable.pages[page][pos]; - break; case 2: return scsi_disk_mode_sense_pages_default.pages[page][pos]; - break; } return 0; @@ -293,14 +240,14 @@ scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint32_t -scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) { - uint8_t msplen, page_control = (type >> 6) & 3; + uint8_t msplen, page_control = (page >> 6) & 3; int i = 0, j = 0; int size = 0; - type &= 0x3f; + page &= 0x3f; size = hdd_image_get_last_sector(dev->id); @@ -316,8 +263,8 @@ scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, } for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (scsi_disk_mode_sense_page_flags & (1LL << dev->current_page_code)) { + if ((page == GPMODE_ALL_PAGES) || (page == i)) { + if (scsi_disk_mode_sense_page_flags & (1LL << (uint64_t) page)) { buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 0); msplen = scsi_disk_mode_sense_read(dev, page_control, i, 1); buf[pos++] = msplen; @@ -337,18 +284,18 @@ scsi_disk_command_common(scsi_disk_t *dev) { dev->status = BUSY_STAT; dev->phase = 1; - if (dev->packet_status == CDROM_PHASE_COMPLETE) { - scsi_disk_callback(dev); - dev->callback = 0LL; - } else - dev->callback = -1LL; /* Speed depends on SCSI controller */ + if (dev->packet_status == PHASE_COMPLETE) + dev->callback = 0.0; + else + dev->callback = -1.0; /* Speed depends on SCSI controller */ } static void scsi_disk_command_complete(scsi_disk_t *dev) { - dev->packet_status = CDROM_PHASE_COMPLETE; + ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); + dev->packet_status = PHASE_COMPLETE; scsi_disk_command_common(dev); } @@ -356,7 +303,7 @@ scsi_disk_command_complete(scsi_disk_t *dev) static void scsi_disk_command_read_dma(scsi_disk_t *dev) { - dev->packet_status = CDROM_PHASE_DATA_IN_DMA; + dev->packet_status = PHASE_DATA_IN_DMA; scsi_disk_command_common(dev); } @@ -364,7 +311,7 @@ scsi_disk_command_read_dma(scsi_disk_t *dev) static void scsi_disk_command_write_dma(scsi_disk_t *dev) { - dev->packet_status = CDROM_PHASE_DATA_OUT_DMA; + dev->packet_status = PHASE_DATA_OUT_DMA; scsi_disk_command_common(dev); } @@ -404,7 +351,7 @@ scsi_disk_set_phase(scsi_disk_t *dev, uint8_t phase) if (dev->drv->bus != HDD_BUS_SCSI) return; - SCSIDevices[scsi_id].Phase = phase; + scsi_devices[scsi_id].phase = phase; } @@ -415,8 +362,9 @@ scsi_disk_cmd_error(scsi_disk_t *dev) dev->error = ((scsi_disk_sense_key & 0xf) << 4) | ABRT_ERR; dev->status = READY_STAT | ERR_STAT; dev->phase = 3; - dev->packet_status = 0x80; - dev->callback = 50 * SCSI_TIME; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * SCSI_TIME; + ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); scsi_disk_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); } @@ -530,13 +478,15 @@ scsi_disk_rezero(scsi_disk_t *dev) } -void -scsi_disk_reset(scsi_disk_t *dev) +static void +scsi_disk_reset(scsi_common_t *sc) { + scsi_disk_t *dev = (scsi_disk_t *) sc; + scsi_disk_rezero(dev); dev->status = 0; - dev->callback = 0; - dev->packet_status = 0xff; + dev->callback = 0.0; + dev->packet_status = PHASE_NONE; } @@ -565,29 +515,63 @@ scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length, } -void -scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length) +static void +scsi_disk_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { + scsi_disk_t *dev = (scsi_disk_t *) sc; + scsi_disk_request_sense(dev, buffer, alloc_length, 0); } -void -scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) +static void +scsi_disk_set_buf_len(scsi_disk_t *dev, int32_t *BufLen, int32_t *src_len) { - uint8_t *hdbufferb; + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + scsi_disk_log("SCSI HD %i: Actual transfer length: %i\n", dev->id, *BufLen); +} + + +static void +scsi_disk_buf_alloc(scsi_disk_t *dev, uint32_t len) +{ + scsi_disk_log("SCSI HD %i: Allocated buffer length: %i\n", dev->id, len); + if (!dev->temp_buffer) + dev->temp_buffer = (uint8_t *) malloc(len); +} + + +static void +scsi_disk_buf_free(scsi_disk_t *dev) +{ + if (dev->temp_buffer) { + scsi_disk_log("SCSI HD %i: Freeing buffer...\n", dev->id); + free(dev->temp_buffer); + dev->temp_buffer = NULL; + } +} + + +static void +scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) +{ + scsi_disk_t *dev = (scsi_disk_t *) sc; int32_t *BufLen; - uint32_t len; - int max_len, pos = 0; - unsigned idx = 0; + int32_t len, max_len, alloc_length; + int pos = 0; + int idx = 0; unsigned size_idx, preamble_len; - uint32_t alloc_length, last_sector = 0; + uint32_t last_sector = 0; char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; int block_desc = 0; - hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer; - BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength; + BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; last_sector = hdd_image_get_last_sector(dev->id); @@ -646,25 +630,38 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) case GPCMD_REQUEST_SENSE: /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE should forget about the not ready, and report unit attention straight away. */ - if ((*BufLen == -1) || (cdb[4] < *BufLen)) - *BufLen = cdb[4]; + len = cdb[4]; + + if (!len) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; + break; + } + + scsi_disk_buf_alloc(dev, 256); + scsi_disk_set_buf_len(dev, BufLen, &len); if (*BufLen < cdb[4]) cdb[4] = *BufLen; len = (cdb[1] & 1) ? 8 : 18; + scsi_disk_request_sense(dev, dev->temp_buffer, *BufLen, cdb[1] & 1); scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); scsi_disk_data_command_finish(dev, len, len, cdb[4], 0); break; case GPCMD_MECHANISM_STATUS: - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - if ((*BufLen == -1) || (len < *BufLen)) - *BufLen = len; - scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + len = (cdb[8] << 8) | cdb[9]; + + scsi_disk_buf_alloc(dev, 8); + scsi_disk_set_buf_len(dev, BufLen, &len); + + memset(dev->temp_buffer, 0, 8); + dev->temp_buffer[5] = 1; + scsi_disk_data_command_finish(dev, 8, 8, len, 0); break; @@ -674,6 +671,8 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) switch(cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; + if (dev->sector_len == 0) + dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); break; case GPCMD_READ_10: @@ -686,7 +685,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) break; } - if ((dev->sector_pos > last_sector) || ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + if ((dev->sector_pos > last_sector)/* || ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/) { scsi_disk_lba_out_of_range(dev); return; } @@ -694,8 +693,8 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) if ((!dev->sector_len) || (*BufLen == 0)) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev); - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->callback = 20 * SCSI_TIME; + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; break; } @@ -703,16 +702,26 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) dev->requested_blocks = max_len; alloc_length = dev->packet_len = max_len << 9; - - if ((*BufLen == -1) || (alloc_length < *BufLen)) - *BufLen = alloc_length; - + scsi_disk_buf_alloc(dev, dev->packet_len); + scsi_disk_set_buf_len(dev, BufLen, &alloc_length); scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + if ((dev->requested_blocks > 0) && (*BufLen > 0)) { + if (dev->packet_len > (uint32_t) *BufLen) + hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer); + else + hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer); + } + if (dev->requested_blocks > 1) scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 0); else scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); + + if (dev->packet_status != PHASE_COMPLETE) + ui_sb_update_icon(SB_HDD | dev->drv->bus, 1); + else + ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); return; case GPCMD_VERIFY_6: @@ -733,6 +742,8 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) case GPCMD_VERIFY_6: case GPCMD_WRITE_6: dev->sector_len = cdb[4]; + if (dev->sector_len == 0) + dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); break; @@ -751,8 +762,8 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) break; } - if ((dev->sector_pos > last_sector) || - ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + if ((dev->sector_pos > last_sector)/* || + ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/) { scsi_disk_lba_out_of_range(dev); return; } @@ -760,8 +771,8 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) if ((!dev->sector_len) || (*BufLen == 0)) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->callback = 20 * SCSI_TIME; + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; break; } @@ -769,19 +780,26 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) dev->requested_blocks = max_len; alloc_length = dev->packet_len = max_len << 9; + scsi_disk_buf_alloc(dev, dev->packet_len); - if ((*BufLen == -1) || (alloc_length < *BufLen)) - *BufLen = alloc_length; - + scsi_disk_set_buf_len(dev, BufLen, &alloc_length); scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); if (dev->requested_blocks > 1) scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1); else scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1); + + if (dev->packet_status != PHASE_COMPLETE) + ui_sb_update_icon(SB_HDD | dev->drv->bus, 1); + else + ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); return; case GPCMD_WRITE_SAME_10: + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + if ((cdb[1] & 6) == 6) { scsi_disk_invalid_field(dev); return; @@ -789,10 +807,9 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); - if ((dev->sector_pos > last_sector) || - ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + if ((dev->sector_pos > last_sector)/* || + ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/) { scsi_disk_lba_out_of_range(dev); return; } @@ -800,25 +817,25 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) if ((!dev->sector_len) || (*BufLen == 0)) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->callback = 20 * SCSI_TIME; + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; break; } + scsi_disk_buf_alloc(dev, alloc_length); + scsi_disk_set_buf_len(dev, BufLen, &alloc_length); + max_len = 1; - dev->requested_blocks = max_len; - - alloc_length = dev->packet_len = max_len << 9; - - if ((*BufLen == -1) || (alloc_length < *BufLen)) - *BufLen = alloc_length; + dev->requested_blocks = 1; scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); - if (dev->requested_blocks > 1) - scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1); + scsi_disk_data_command_finish(dev, 512, 512, alloc_length, 1); + + if (dev->packet_status != PHASE_COMPLETE) + ui_sb_update_icon(SB_HDD | dev->drv->bus, 1); else - scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1); + ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); return; case GPCMD_MODE_SENSE_6: @@ -827,18 +844,17 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - if (cdb[0] == GPCMD_MODE_SENSE_6) + if (cdb[0] == GPCMD_MODE_SENSE_6) { len = cdb[4]; - else + scsi_disk_buf_alloc(dev, 256); + } else { len = (cdb[8] | (cdb[7] << 8)); + scsi_disk_buf_alloc(dev, 65536); + } - dev->current_page_code = cdb[2] & 0x3F; - + memset(dev->temp_buffer, 0, len); alloc_length = len; - dev->temp_buffer = (uint8_t *) malloc(65536); - memset(dev->temp_buffer, 0, 65536); - if (cdb[0] == GPCMD_MODE_SENSE_6) { len = scsi_disk_mode_sense(dev, dev->temp_buffer, 4, cdb[2], block_desc); if (len > alloc_length) @@ -851,8 +867,8 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) len = scsi_disk_mode_sense(dev, dev->temp_buffer, 8, cdb[2], block_desc); if (len > alloc_length) len = alloc_length; - dev->temp_buffer[0]=(len - 2) >> 8; - dev->temp_buffer[1]=(len - 2) & 255; + dev->temp_buffer[0] = (len - 2) >> 8; + dev->temp_buffer[1] = (len - 2) & 255; dev->temp_buffer[2] = 0; if (block_desc) { dev->temp_buffer[6] = 0; @@ -865,9 +881,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) else if (len < alloc_length) alloc_length = len; - if ((*BufLen == -1) || (alloc_length < *BufLen)) - *BufLen = alloc_length; - + scsi_disk_set_buf_len(dev, BufLen, &alloc_length); scsi_disk_log("SCSI HDD %i: Reading mode page: %02X...\n", dev->id, cdb[2]); scsi_disk_data_command_finish(dev, len, len, alloc_length, 0); @@ -877,17 +891,17 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) case GPCMD_MODE_SELECT_10: scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); - if (cdb[0] == GPCMD_MODE_SELECT_6) + if (cdb[0] == GPCMD_MODE_SELECT_6) { len = cdb[4]; - else + scsi_disk_buf_alloc(dev, 256); + } else { len = (cdb[7] << 8) | cdb[8]; + scsi_disk_buf_alloc(dev, 65536); + } - if ((*BufLen == -1) || (len < *BufLen)) - *BufLen = len; - + scsi_disk_set_buf_len(dev, BufLen, &len); dev->total_length = len; dev->do_page_save = cdb[1] & 1; - scsi_disk_data_command_finish(dev, len, len, len, 1); return; @@ -899,12 +913,12 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) if ((!max_len) || (*BufLen == 0)) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); /* scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); */ - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->callback = 20 * SCSI_TIME; + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; break; } - dev->temp_buffer = malloc(1024); + scsi_disk_buf_alloc(dev, 65536); if (cdb[1] & 1) { preamble_len = 4; @@ -923,8 +937,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) break; case 0x83: if (idx + 24 > max_len) { - free(dev->temp_buffer); - dev->temp_buffer = NULL; + scsi_disk_buf_free(dev); scsi_disk_data_phase_error(dev); return; } @@ -951,9 +964,8 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) break; default: scsi_disk_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - free(dev->temp_buffer); - dev->temp_buffer = NULL; scsi_disk_invalid_field(dev); + scsi_disk_buf_free(dev); return; } } else { @@ -984,13 +996,10 @@ atapi_out: dev->temp_buffer[size_idx] = idx - preamble_len; len=idx; - scsi_disk_log("scsi_disk_command(): Inquiry (%08X, %08X)\n", hdbufferb, dev->temp_buffer); - if (len > max_len) len = max_len; - if ((*BufLen == -1) || (len < *BufLen)) - *BufLen = len; + scsi_disk_set_buf_len(dev, BufLen, &len); if (len > *BufLen) len = *BufLen; @@ -1021,15 +1030,18 @@ atapi_out: break; case GPCMD_READ_CDROM_CAPACITY: - dev->temp_buffer = (uint8_t *) malloc(8); + scsi_disk_buf_alloc(dev, 8); - if (scsi_disk_read_capacity(dev, dev->current_cdb, dev->temp_buffer, &len) == 0) { - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - return; - } + max_len = hdd_image_get_last_sector(dev->id); + memset(dev->temp_buffer, 0, 8); + dev->temp_buffer[0] = (max_len >> 24) & 0xff; + dev->temp_buffer[1] = (max_len >> 16) & 0xff; + dev->temp_buffer[2] = (max_len >> 8) & 0xff; + dev->temp_buffer[3] = max_len & 0xff; + dev->temp_buffer[6] = 2; + len = 8; - if ((*BufLen == -1) || (len < *BufLen)) - *BufLen = len; + scsi_disk_set_buf_len(dev, BufLen, &len); scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); scsi_disk_data_command_finish(dev, len, len, len, 0); @@ -1045,64 +1057,21 @@ atapi_out: static void -scsi_disk_phase_data_in(scsi_disk_t *dev) +scsi_disk_command_stop(scsi_common_t *sc) { - uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer; - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength; + scsi_disk_t *dev = (scsi_disk_t *) sc; - if (!*BufLen) { - scsi_disk_log("scsi_disk_phase_data_in(): Buffer length is 0\n"); - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - - return; - } - - switch (dev->current_cdb[0]) { - case GPCMD_REQUEST_SENSE: - scsi_disk_log("SCSI HDD %i: %08X, %08X\n", dev->id, hdbufferb, *BufLen); - scsi_disk_request_sense(dev, hdbufferb, *BufLen, dev->current_cdb[1] & 1); - break; - case GPCMD_MECHANISM_STATUS: - memset(hdbufferb, 0, *BufLen); - hdbufferb[5] = 1; - break; - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - if ((dev->requested_blocks > 0) && (*BufLen > 0)) { - if (dev->packet_len > *BufLen) - hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb); - else - hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb); - } - break; - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - case GPCMD_INQUIRY: - case GPCMD_READ_CDROM_CAPACITY: - scsi_disk_log("scsi_disk_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, dev->temp_buffer); - memcpy(hdbufferb, dev->temp_buffer, *BufLen); - free(dev->temp_buffer); - dev->temp_buffer = NULL; - scsi_disk_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], - hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); - break; - default: - fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]); - break; - } - - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + scsi_disk_buf_free(dev); } -static void -scsi_disk_phase_data_out(scsi_disk_t *dev) +static uint8_t +scsi_disk_phase_data_out(scsi_common_t *sc) { - uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer; + scsi_disk_t *dev = (scsi_disk_t *) sc; int i; - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength; + int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; uint32_t last_sector = hdd_image_get_last_sector(dev->id); uint32_t c, h, s, last_to_write = 0; uint16_t block_desc_len, pos; @@ -1112,7 +1081,7 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) if (!*BufLen) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - return; + return 1; } switch (dev->current_cdb[0]) { @@ -1126,10 +1095,10 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: if ((dev->requested_blocks > 0) && (*BufLen > 0)) { - if (dev->packet_len > *BufLen) - hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb); + if (dev->packet_len > (uint32_t) *BufLen) + hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer); else - hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb); + hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer); } break; case GPCMD_WRITE_SAME_10: @@ -1138,26 +1107,26 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) else last_to_write = dev->sector_pos + dev->sector_len - 1; - for (i = dev->sector_pos; i <= last_to_write; i++) { + for (i = dev->sector_pos; i <= (int) last_to_write; i++) { if (dev->current_cdb[1] & 2) { - hdbufferb[0] = (i >> 24) & 0xff; - hdbufferb[1] = (i >> 16) & 0xff; - hdbufferb[2] = (i >> 8) & 0xff; - hdbufferb[3] = i & 0xff; + dev->temp_buffer[0] = (i >> 24) & 0xff; + dev->temp_buffer[1] = (i >> 16) & 0xff; + dev->temp_buffer[2] = (i >> 8) & 0xff; + dev->temp_buffer[3] = i & 0xff; } else if (dev->current_cdb[1] & 4) { s = (i % dev->drv->spt); h = ((i - s) / dev->drv->spt) % dev->drv->hpc; c = ((i - s) / dev->drv->spt) / dev->drv->hpc; - hdbufferb[0] = (c >> 16) & 0xff; - hdbufferb[1] = (c >> 8) & 0xff; - hdbufferb[2] = c & 0xff; - hdbufferb[3] = h & 0xff; - hdbufferb[4] = (s >> 24) & 0xff; - hdbufferb[5] = (s >> 16) & 0xff; - hdbufferb[6] = (s >> 8) & 0xff; - hdbufferb[7] = s & 0xff; + dev->temp_buffer[0] = (c >> 16) & 0xff; + dev->temp_buffer[1] = (c >> 8) & 0xff; + dev->temp_buffer[2] = c & 0xff; + dev->temp_buffer[3] = h & 0xff; + dev->temp_buffer[4] = (s >> 24) & 0xff; + dev->temp_buffer[5] = (s >> 16) & 0xff; + dev->temp_buffer[6] = (s >> 8) & 0xff; + dev->temp_buffer[7] = s & 0xff; } - hdd_image_write(dev->id, i, 1, hdbufferb); + hdd_image_write(dev->id, i, 1, dev->temp_buffer); } break; case GPCMD_MODE_SELECT_6: @@ -1168,20 +1137,25 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) hdr_len = 4; if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = hdbufferb[2]; + block_desc_len = dev->temp_buffer[2]; block_desc_len <<= 8; - block_desc_len |= hdbufferb[3]; + block_desc_len |= dev->temp_buffer[3]; } else { - block_desc_len = hdbufferb[6]; + block_desc_len = dev->temp_buffer[6]; block_desc_len <<= 8; - block_desc_len |= hdbufferb[7]; + block_desc_len |= dev->temp_buffer[7]; } pos = hdr_len + block_desc_len; while(1) { - page = hdbufferb[pos] & 0x3F; - page_len = hdbufferb[pos + 1]; + if (pos >= dev->current_cdb[4]) { + scsi_disk_log("SCSI HD %i: Buffer has only block descriptor\n", dev->id); + break; + } + + page = dev->temp_buffer[pos] & 0x3F; + page_len = dev->temp_buffer[pos + 1]; pos += 2; @@ -1190,7 +1164,7 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) else { for (i = 0; i < page_len; i++) { ch = scsi_disk_mode_sense_pages_changeable.pages[page][i + 2]; - val = hdbufferb[pos + i]; + val = dev->temp_buffer[pos + i]; old_val = dev->ms_pages_saved.pages[page][i + 2]; if (val != old_val) { if (ch) @@ -1211,63 +1185,18 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) break; } - if (error) + if (error) { + scsi_disk_buf_free(dev); scsi_disk_invalid_field_pl(dev); + } break; default: fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]); break; } - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); -} - - -/* If the result is 1, issue an IRQ, otherwise not. */ -void -scsi_disk_callback(scsi_disk_t *dev) -{ - switch(dev->packet_status) { - case CDROM_PHASE_IDLE: - scsi_disk_log("SCSI HD %i: PHASE_IDLE\n", dev->id); - dev->phase = 1; - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - return; - case CDROM_PHASE_COMPLETE: - scsi_disk_log("SCSI HD %i: PHASE_COMPLETE\n", dev->id); - dev->status = READY_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; - return; - case CDROM_PHASE_DATA_OUT_DMA: - scsi_disk_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", dev->id); - scsi_disk_phase_data_out(dev); - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->status = READY_STAT; - dev->phase = 3; - return; - case CDROM_PHASE_DATA_IN_DMA: - scsi_disk_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", dev->id); - scsi_disk_phase_data_in(dev); - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->status = READY_STAT; - dev->phase = 3; - return; - case CDROM_PHASE_ERROR: - scsi_disk_log("SCSI HD %i: PHASE_ERROR\n", dev->id); - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - return; - } -} - - -/* Peform a master init on the entire module. */ -void -scsi_disk_global_init(void) -{ - /* Clear the global data. */ - memset(scsi_disk, 0x00, sizeof(scsi_disk)); + scsi_disk_command_stop((scsi_common_t *) dev); + return 1; } @@ -1275,20 +1204,49 @@ void scsi_disk_hard_reset(void) { int c; + scsi_disk_t *dev; + scsi_device_t *sd; for (c = 0; c < HDD_NUM; c++) { if (hdd[c].bus == HDD_BUS_SCSI) { scsi_disk_log("SCSI disk hard_reset drive=%d\n", c); - if (!scsi_disk[c]) { - scsi_disk[c] = (scsi_disk_t *) malloc(sizeof(scsi_disk_t)); - memset(scsi_disk[c], 0, sizeof(scsi_disk_t)); + /* Make sure to ignore any SCSI disk that has an out of range ID. */ + if (hdd[c].scsi_id > SCSI_ID_MAX) + continue; + + /* Make sure to ignore any SCSI disk whose image file name is empty. */ + if (wcslen(hdd[c].fn) == 0) + continue; + + /* Make sure to ignore any SCSI disk whose image fails to load. */ + if (! hdd_image_load(c)) + continue; + + if (!hdd[c].priv) { + hdd[c].priv = (scsi_disk_t *) malloc(sizeof(scsi_disk_t)); + memset(hdd[c].priv, 0, sizeof(scsi_disk_t)); } - scsi_disk[c]->id = c; - scsi_disk[c]->drv = &hdd[c]; + dev = (scsi_disk_t *) hdd[c].priv; - scsi_disk_mode_sense_load(scsi_disk[c]); + /* SCSI disk, attach to the SCSI bus. */ + sd = &scsi_devices[hdd[c].scsi_id]; + + sd->sc = (scsi_common_t *) dev; + sd->command = scsi_disk_command; + sd->request_sense = scsi_disk_request_sense_for_scsi; + sd->reset = scsi_disk_reset; + sd->phase_data_out = scsi_disk_phase_data_out; + sd->command_stop = scsi_disk_command_stop; + sd->type = SCSI_FIXED_DISK; + + dev->id = c; + dev->drv = &hdd[c]; + + scsi_disk_mode_sense_load(dev); + + scsi_disk_log("SCSI disk %i attached to SCSI ID %i\n", c, hdd[c].scsi_id); } } } @@ -1301,13 +1259,15 @@ scsi_disk_close(void) int c; for (c = 0; c < HDD_NUM; c++) { - dev = scsi_disk[c]; - - if (dev) { + if (hdd[c].bus == HDD_BUS_SCSI) { hdd_image_close(c); - free(scsi_disk[c]); - scsi_disk[c] = NULL; + dev = hdd[c].priv; + + if (dev) { + free(dev); + hdd[c].priv = NULL; + } } } } diff --git a/src/scsi/scsi_disk.h b/src/scsi/scsi_disk.h index 36898f266..54c872e2b 100644 --- a/src/scsi/scsi_disk.h +++ b/src/scsi/scsi_disk.h @@ -6,7 +6,7 @@ * * Emulation of SCSI fixed and removable disks. * - * Version: @(#)scsi_disk.h 1.0.5 2018/06/02 + * Version: @(#)scsi_disk.h 1.0.7 2018/10/26 * * Author: Miran Grca, * Copyright 2017,2018 Miran Grca. @@ -18,43 +18,33 @@ typedef struct { hard_disk_t *drv; - /* Stuff for SCSI hard disks. */ - uint8_t status, phase, - error, id, + uint8_t *temp_buffer, + pad[16], /* This is atapi_cdb in ATAPI-supporting devices, + and pad in SCSI-only devices. */ current_cdb[16], sense[256]; - uint16_t request_length; + uint8_t status, phase, + error, id, + pad0, pad1, + pad2, pad3; - int requested_blocks, block_total, - packet_status, callback, - block_descriptor_len, - total_length, do_page_save; + uint16_t request_length, pad4; + + int requested_blocks, packet_status, + total_length, do_page_save, + unit_attention, pad5, + pad6, pad7; uint32_t sector_pos, sector_len, - packet_len; + packet_len, pos; - uint64_t current_page_code; - - uint8_t *temp_buffer; + double callback; } scsi_disk_t; extern scsi_disk_t *scsi_disk[HDD_NUM]; -extern uint8_t scsi_disks[16]; -extern void scsi_loadhd(int scsi_id, int id); -extern void scsi_disk_global_init(void); extern void scsi_disk_hard_reset(void); extern void scsi_disk_close(void); - -extern int scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); -extern int scsi_disk_err_stat_to_scsi(scsi_disk_t *dev); -extern int scsi_disk_phase_to_scsi(scsi_disk_t *dev); -extern int find_hdd_for_scsi_id(uint8_t scsi_id); -extern void build_scsi_disk_map(void); -extern void scsi_disk_reset(scsi_disk_t *dev); -extern void scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length); -extern void scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb); -extern void scsi_disk_callback(scsi_disk_t *dev); diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index a5107bfb6..a2991cce8 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -9,15 +9,15 @@ * Implementation of the NCR 5380 series of SCSI Host Adapters * made by NCR. These controllers were designed for the ISA bus. * - * Version: @(#)scsi_ncr5380.c 1.0.16 2018/07/19 + * Version: @(#)scsi_ncr5380.c 1.0.25 2019/10/16 * * Authors: Sarah Walker, * TheCollector1995, * Fred N. van Kempen, * - * Copyright 2017,2018 Sarah Walker. - * Copyright 2017,2018 TheCollector1995. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Sarah Walker. + * Copyright 2017-2019 TheCollector1995. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -28,8 +28,8 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../dma.h" #include "../pic.h" #include "../mca.h" @@ -37,7 +37,6 @@ #include "../rom.h" #include "../device.h" #include "../nvr.h" -#include "../timer.h" #include "../plat.h" #include "scsi.h" #include "scsi_device.h" @@ -45,9 +44,9 @@ #define LCS6821N_ROM L"roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin" -#define RT1000B_ROM L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin" +#define RT1000B_810R_ROM L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin" +#define RT1000B_820R_ROM L"roms/scsi/ncr5380/RTBIOS82.rom" #define T130B_ROM L"roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin" -#define SCSIAT_ROM L"roms/scsi/ncr5380/sumo_scsiat_bios_v6.3.bin" #define NCR_CURDATA 0 /* current SCSI data (read only) */ @@ -95,91 +94,78 @@ #define STATUS_53C80_ACCESSIBLE 0x80 typedef struct { - uint8_t icr; - uint8_t mode; - uint8_t tcr; - uint8_t ser; - uint8_t isr; - uint8_t output_data; + uint8_t icr, mode, tcr, data_wait; + uint8_t isr, output_data, target_id, tx_data; + uint8_t msglun; - uint8_t target_id; + uint8_t command[20]; + uint8_t msgout[4]; + int msgout_pos; + int is_msgout; - int dma_mode; - - int bus_host, cur_bus, bus_in; - int new_phase; - int state; - - int clear_req, wait_data, wait_complete; - - int command_pos; - uint8_t command[20]; - int data_pos; - uint8_t tx_data; - - uint8_t unk_08, unk_08_ret; + int dma_mode, cur_bus, bus_in, new_phase; + int state, clear_req, wait_data, wait_complete; + int command_pos, data_pos; } ncr_t; typedef struct { + ncr_t ncr; + const char *name; + + uint8_t buffer[128]; + uint8_t int_ram[0x40], ext_ram[0x600]; + uint32_t rom_addr; uint16_t base; + int8_t irq; int8_t type; + int8_t bios_ver; + uint8_t block_count; + uint8_t status_ctrl; + uint8_t pad[2]; rom_t bios_rom; mem_mapping_t mapping; - uint8_t block_count; int block_count_loaded; - uint8_t status_ctrl; + int buffer_pos; + int buffer_host_pos; - uint8_t buffer[128]; - int buffer_pos; - int buffer_host_pos; - - uint8_t int_ram[0x40]; - uint8_t ext_ram[0x600]; - - ncr_t ncr; - int dma_enabled; - int64_t timer_period; - int64_t timer_enabled; - - int64_t media_period; - int64_t temp_period; + pc_timer_t timer; + double period; int ncr_busy; - - double period; - - int is_non_data_mode; } ncr5380_t; -#define STATE_IDLE 0 -#define STATE_COMMAND 1 -#define STATE_DATAIN 2 -#define STATE_DATAOUT 3 -#define STATE_STATUS 4 -#define STATE_MESSAGEIN 5 -#define STATE_SELECT 6 +#define STATE_IDLE 0 +#define STATE_COMMAND 1 +#define STATE_DATAIN 2 +#define STATE_DATAOUT 3 +#define STATE_STATUS 4 +#define STATE_MESSAGEIN 5 +#define STATE_SELECT 6 +#define STATE_MESSAGEOUT 7 +#define STATE_MESSAGE_ID 8 #define DMA_IDLE 0 #define DMA_SEND 1 #define DMA_INITIATOR_RECEIVE 2 +static int cmd_len[8] = {6, 10, 10, 6, 16, 12, 6, 6}; + + #ifdef ENABLE_NCR5380_LOG int ncr5380_do_log = ENABLE_NCR5380_LOG; -#endif static void ncr_log(const char *fmt, ...) { -#ifdef ENABLE_NCR5380_LOG va_list ap; if (ncr5380_do_log) { @@ -187,14 +173,18 @@ ncr_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define ncr_log(fmt, ...) +#endif + #define SET_BUS_STATE(ncr, state) ncr->cur_bus = (ncr->cur_bus & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) static void ncr_callback(void *priv); + static int get_dev_id(uint8_t data) { @@ -207,168 +197,369 @@ get_dev_id(uint8_t data) return(-1); } -/* get the length of a SCSI command based on its command byte type */ static int -get_cmd_len(int cbyte) +getmsglen(uint8_t *msgp, int len) { - int len; - int group; - - group = (cbyte>>5) & 7; - - if (group == 0) len = 6; - if (group == 1 || group == 2) len = 10; - - return(len); + uint8_t msg = msgp[0]; + if (msg == 0 || (msg >= 0x02 && msg <= 0x1f) ||msg >= 0x80) + return 1; + if (msg >= 0x20 && msg <= 0x2f) + return 2; + if (len < 2) + return 3; + return msgp[1]; } static void ncr_reset(ncr_t *ncr) { - memset(ncr, 0x00, sizeof(ncr_t)); - ncr_log("NCR reset\n"); + memset(ncr, 0x00, sizeof(ncr_t)); + ncr_log("NCR reset\n"); } + +static void +dma_timer_on(ncr5380_t *ncr_dev) +{ + ncr_t *ncr = &ncr_dev->ncr; + double period = ncr_dev->period; + + /* DMA Timer on: 1 wait period + 64 byte periods + 64 byte periods if first time. */ + if (ncr->data_wait & 2) { + ncr->data_wait &= ~2; + period *= 128.0; + } else + period *= 64.0; + + /* This is the 1 us wait period. */ + period += 1.0; + + timer_on_auto(&ncr_dev->timer, period); +} + + +static void +wait_timer_on(ncr5380_t *ncr_dev) +{ + /* PIO Wait Timer On: 1 period. */ + timer_on_auto(&ncr_dev->timer, ncr_dev->period); +} + + +static void +set_dma_enable(ncr5380_t *dev, int enable) +{ + if (enable) { + if (!timer_is_enabled(&dev->timer)) + dma_timer_on(dev); + } else + timer_stop(&dev->timer); +} + + +static void +dma_changed(ncr5380_t *dev, int mode, int enable) +{ + dev->dma_enabled = (mode && enable); + + set_dma_enable(dev, dev->dma_enabled && dev->block_count_loaded); +} + + static uint32_t get_bus_host(ncr_t *ncr) { uint32_t bus_host = 0; if (ncr->icr & ICR_DBP) - { - ncr_log("Data bus phase\n"); - bus_host |= BUS_DBP; - } + bus_host |= BUS_DBP; + if (ncr->icr & ICR_SEL) - { - ncr_log("Selection phase\n"); - bus_host |= BUS_SEL; - } + bus_host |= BUS_SEL; + if (ncr->tcr & TCR_IO) - { - ncr_log("Data phase\n"); - bus_host |= BUS_IO; - } + bus_host |= BUS_IO; + if (ncr->tcr & TCR_CD) - { - ncr_log("Command phase\n"); - bus_host |= BUS_CD; - } + bus_host |= BUS_CD; + if (ncr->tcr & TCR_MSG) - { - ncr_log("Message phase\n"); - bus_host |= BUS_MSG; - } + bus_host |= BUS_MSG; + if (ncr->tcr & TCR_REQ) - { - ncr_log("Request phase\n"); - bus_host |= BUS_REQ; - } + bus_host |= BUS_REQ; + if (ncr->icr & ICR_BSY) - { - ncr_log("Busy phase\n"); - bus_host |= BUS_BSY; - } - if (ncr->icr & ICR_ATN) - { - bus_host |= BUS_ATN; - } - if (ncr->icr & ICR_ACK) - { - ncr_log("ACK phase\n"); - bus_host |= BUS_ACK; - } - if (ncr->mode & MODE_ARBITRATE) - { - bus_host |= BUS_ARB; - } + bus_host |= BUS_BSY; + + if (ncr->icr & ICR_ATN) + bus_host |= BUS_ATN; + + if (ncr->icr & ICR_ACK) + bus_host |= BUS_ACK; + + if (ncr->mode & MODE_ARBITRATE) + bus_host |= BUS_ARB; return(bus_host | BUS_SETDATA(ncr->output_data)); } + static void -ncr_wait_process(ncr5380_t *ncr_dev) +ncr_bus_read(ncr5380_t *ncr_dev) { - ncr_t *ncr = &ncr_dev->ncr; - - /*Wait processes to handle bus requests*/ - ncr_log("Clear REQ=%d\n", ncr->clear_req); - if (ncr->clear_req) - { - ncr->clear_req--; - if (!ncr->clear_req) - { - ncr_log("Prelude to command data\n"); - SET_BUS_STATE(ncr, ncr->new_phase); - ncr->cur_bus |= BUS_REQ; - } - } - - if (ncr->wait_data) - { - ncr->wait_data--; - if (!ncr->wait_data) - { - scsi_device_t *dev; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev; + int phase; - dev = &SCSIDevices[ncr->target_id]; - SET_BUS_STATE(ncr, ncr->new_phase); + /*Wait processes to handle bus requests*/ + if (ncr->clear_req) { + ncr->clear_req--; + if (!ncr->clear_req) { + ncr_log("Prelude to command data\n"); + SET_BUS_STATE(ncr, ncr->new_phase); + ncr->cur_bus |= BUS_REQ; + } + } - if (ncr->new_phase == SCSI_PHASE_DATA_IN) - { - ncr_log("Data In bus phase\n"); - ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; - ncr->state = STATE_DATAIN; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; - } - else if (ncr->new_phase == SCSI_PHASE_STATUS) - { - ncr_log("Status bus phase\n"); - ncr->cur_bus |= BUS_REQ; - ncr->state = STATE_STATUS; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->Status) | BUS_DBP; - } - else if (ncr->new_phase == SCSI_PHASE_MESSAGE_IN) - { - ncr_log("Message In bus phase\n"); - ncr->state = STATE_MESSAGEIN; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; - } - else - { - if (ncr->new_phase & BUS_IDLE) { - ncr_log("Bus Idle phase\n"); - ncr->state = STATE_IDLE; - ncr->cur_bus &= ~BUS_BSY; - ncr_dev->media_period = 0LL; - ncr_dev->temp_period = 0LL; - } else { - ncr->state = STATE_DATAOUT; - ncr_log("Data Out bus phase\n"); - } - } - } - } - - if (ncr->wait_complete) - { - ncr->wait_complete--; - if (!ncr->wait_complete) - { + if (ncr->wait_data) { + ncr->wait_data--; + if (!ncr->wait_data) { + dev = &scsi_devices[ncr->target_id]; + SET_BUS_STATE(ncr, ncr->new_phase); + phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN); + + if (phase == SCSI_PHASE_DATA_IN) { + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + ncr->state = STATE_DATAIN; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; + } else if (phase == SCSI_PHASE_DATA_OUT) { + if (ncr->new_phase & BUS_IDLE) { + ncr->state = STATE_IDLE; + ncr->cur_bus &= ~BUS_BSY; + } else + ncr->state = STATE_DATAOUT; + } else if (phase == SCSI_PHASE_STATUS) { ncr->cur_bus |= BUS_REQ; + ncr->state = STATE_STATUS; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP; + } else if (phase == SCSI_PHASE_MESSAGE_IN) { + ncr->state = STATE_MESSAGEIN; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; + } else if (phase == SCSI_PHASE_MESSAGE_OUT) { + ncr->cur_bus |= BUS_REQ; + ncr->state = STATE_MESSAGEOUT; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->target_id >> 5) | BUS_DBP; } } - - ncr->bus_host = ncr->cur_bus; + } + + if (ncr->wait_complete) { + ncr->wait_complete--; + if (!ncr->wait_complete) + ncr->cur_bus |= BUS_REQ; + } } + +static void +ncr_bus_update(void *priv, int bus) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &scsi_devices[ncr->target_id]; + double p; + uint8_t sel_data; + int msglen; + + /*Start the SCSI command layer, which will also make the timings*/ + if (bus & BUS_ARB) + ncr->state = STATE_IDLE; + + if (ncr->state == STATE_IDLE) { + ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; + if ((bus & BUS_SEL) && !(bus & BUS_BSY)) { + ncr_log("Selection phase\n"); + sel_data = BUS_GETDATA(bus); + + ncr->target_id = get_dev_id(sel_data); + + ncr_log("Select - target ID = %i\n", ncr->target_id); + + /*Once the device has been found and selected, mark it as busy*/ + if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { + ncr->cur_bus |= BUS_BSY; + ncr->state = STATE_SELECT; + } else { + ncr_log("Device not found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); + if (ncr_dev->type == 1 && ncr_dev->bios_ver == 1) + ncr->cur_bus = 0; + } + } + } else if (ncr->state == STATE_SELECT) { + if (!(bus & BUS_SEL)) { + if (!(bus & BUS_ATN)) { + if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { + ncr_log("Device found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); + ncr->state = STATE_COMMAND; + ncr->cur_bus = BUS_BSY | BUS_REQ; + ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); + ncr->command_pos = 0; + SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); + picint(1 << ncr_dev->irq); + } else { + ncr->state = STATE_IDLE; + ncr->cur_bus = 0; + } + } else { + ncr_log("Set to SCSI Message Out\n"); + ncr->new_phase = SCSI_PHASE_MESSAGE_OUT; + ncr->wait_data = 4; + ncr->msgout_pos = 0; + ncr->is_msgout = 1; + } + } + } else if (ncr->state == STATE_COMMAND) { + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + /*Write command byte to the output data register*/ + ncr->command[ncr->command_pos++] = BUS_GETDATA(bus); + ncr->clear_req = 3; + ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; + ncr->cur_bus &= ~BUS_REQ; + + ncr_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(bus)); + + if (ncr->command_pos == cmd_len[(ncr->command[0] >> 5) & 7]) { + if (ncr->msglun >= 0 && ncr->is_msgout) { + ncr->is_msgout = 0; + ncr->command[1] &= ~(0x80 | 0x40 | 0x20); + ncr->command[1] |= ncr->msglun << 5; + } + + /*Reset data position to default*/ + ncr->data_pos = 0; + + dev = &scsi_devices[ncr->target_id]; + + ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status); + dev->buffer_length = -1; + scsi_device_command_phase0(dev, ncr->command); + ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase); + + ncr_dev->period = 1.0; /* 1 us default */ + ncr->wait_data = 4; + ncr->data_wait = 0; + + if (dev->status == SCSI_STATUS_OK) { + /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ + if (dev->buffer_length && (dev->phase == SCSI_PHASE_DATA_IN || dev->phase == SCSI_PHASE_DATA_OUT)) { + p = scsi_device_get_callback(dev); + if (p <= 0.0) + ncr_dev->period = 0.2/* * ((double) dev->buffer_length) */; + else + ncr_dev->period = p / ((double) dev->buffer_length); + ncr->data_wait |= 2; + } + } + + ncr->new_phase = dev->phase; + } + } + } else if (ncr->state == STATE_DATAIN) { + dev = &scsi_devices[ncr->target_id]; + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + if (ncr->data_pos >= dev->buffer_length) { + ncr->cur_bus &= ~BUS_REQ; + scsi_device_command_phase1(dev); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; + if (ncr->data_wait & 2) + ncr->data_wait &= ~2; + if (ncr->dma_mode == DMA_IDLE) { + ncr->data_wait |= 1; + wait_timer_on(ncr_dev); + } else + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_DATA_IN; + } + } + } else if (ncr->state == STATE_DATAOUT) { + dev = &scsi_devices[ncr->target_id]; + + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); + + if (ncr->data_pos >= dev->buffer_length) { + ncr->cur_bus &= ~BUS_REQ; + scsi_device_command_phase1(dev); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + /*More data is to be transferred, place a request*/ + if (ncr->dma_mode == DMA_IDLE) { + ncr->data_wait |= 1; + wait_timer_on(ncr_dev); + } else + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); + } + } + } else if (ncr->state == STATE_STATUS) { + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + /*All transfers done, wait until next transfer*/ + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_MESSAGE_IN; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } + } else if (ncr->state == STATE_MESSAGEIN) { + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = BUS_IDLE; + ncr->wait_data = 4; + } + } else if (ncr->state == STATE_MESSAGEOUT) { + ncr_log("Ack on MSGOUT = %02x\n", (bus & BUS_ACK)); + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + ncr->msgout[ncr->msgout_pos++] = BUS_GETDATA(bus); + msglen = getmsglen(ncr->msgout, ncr->msgout_pos); + if (ncr->msgout_pos >= msglen) { + if ((ncr->msgout[0] & (0x80 | 0x20)) == 0x80) + ncr->msglun = ncr->msgout[0] & 7; + ncr->cur_bus &= ~BUS_REQ; + ncr->state = STATE_MESSAGE_ID; + } + } + } else if (ncr->state == STATE_MESSAGE_ID) { + if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { + ncr_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); + ncr->state = STATE_COMMAND; + ncr->cur_bus = BUS_BSY | BUS_REQ; + ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); + ncr->command_pos = 0; + SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); + } + } + + ncr->bus_in = bus; +} + + static void ncr_write(uint16_t port, uint8_t val, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; - ncr_t *ncr = &ncr_dev->ncr; + ncr_t *ncr = &ncr_dev->ncr; + int bus_host = 0; - ncr_log("NCR5380 write(%04x,%02x) @%04X:%04X\n",port & 7,val,CS,cpu_state.pc); + ncr_log("NCR5380 write(%04x,%02x)\n",port & 7,val); switch (port & 7) { case 0: /* Output data register */ @@ -378,9 +569,11 @@ ncr_write(uint16_t port, uint8_t val, void *priv) case 1: /* Initiator Command Register */ ncr_log("Write: Initiator command register\n"); + if ((val & 0x80) && !(ncr->icr & 0x80)) { + ncr_log("Resetting the 5380\n"); + ncr_reset(&ncr_dev->ncr); + } ncr->icr = val; - - ncr_dev->timer_enabled = 1; break; case 2: /* Mode register */ @@ -391,9 +584,13 @@ ncr_write(uint16_t port, uint8_t val, void *priv) } ncr->mode = val; + + /*Don't stop the timer until it finishes the transfer*/ + if (ncr_dev->block_count_loaded && (ncr->mode & MODE_DMA)) + dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); - /*If it's not DMA mode, don't do anything*/ - if (!(ncr->mode & MODE_DMA)) { + /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ + if (!ncr_dev->block_count_loaded && !(ncr->mode & MODE_DMA)) { ncr_log("No DMA mode\n"); ncr->tcr &= ~TCR_LAST_BYTE_SENT; ncr->isr &= ~STATUS_END_OF_DMA; @@ -415,6 +612,7 @@ ncr_write(uint16_t port, uint8_t val, void *priv) ncr_log("Write 6 or 10, block count loaded=%d\n", ncr_dev->block_count_loaded); /*a Write 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_SEND; + dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); break; case 7: /* start DMA Initiator Receive */ @@ -422,20 +620,26 @@ ncr_write(uint16_t port, uint8_t val, void *priv) ncr_log("Read 6 or 10, block count loaded=%d\n", ncr_dev->block_count_loaded); /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_INITIATOR_RECEIVE; + dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); break; default: ncr_log("NCR5380: bad write %04x %02x\n", port, val); break; } + + bus_host = get_bus_host(ncr); + ncr_bus_update(priv, bus_host); } + static uint8_t ncr_read(uint16_t port, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; - ncr_t *ncr = &ncr_dev->ncr; + ncr_t *ncr = &ncr_dev->ncr; uint8_t ret = 0xff; + int bus, bus_state; switch (port & 7) { case 0: /* Current SCSI data */ @@ -446,15 +650,14 @@ ncr_read(uint16_t port, void *priv) ret = ncr->output_data; } else { /*Return the data from the SCSI bus*/ - ncr_wait_process(ncr_dev); - ncr_log("NCR GetData=%02x\n", BUS_GETDATA(ncr->bus_host)); - ret = BUS_GETDATA(ncr->bus_host); + ncr_bus_read(ncr_dev); + ncr_log("NCR GetData=%02x\n", BUS_GETDATA(ncr->cur_bus)); + ret = BUS_GETDATA(ncr->cur_bus); } break; case 1: /* Initiator Command Register */ - ncr_log("Read: Initiator Command register\n"); - ncr_log("NCR ICR Read=%02x\n", ncr->icr); + ncr_log("Read: Initiator Command register, NCR ICR Read=%02x\n", ncr->icr); ret = ncr->icr; break; @@ -465,60 +668,54 @@ ncr_read(uint16_t port, void *priv) break; case 3: /* Target Command Register */ - ncr_log("Read: Target Command register\n"); - ncr_log("NCR target stat=%02x\n", ncr->tcr); + ncr_log("Read: Target Command register, NCR target stat=%02x\n", ncr->tcr); ret = ncr->tcr; break; case 4: /* Current SCSI Bus status */ ncr_log("Read: SCSI bus status register\n"); ret = 0; - ncr_wait_process(ncr_dev); - ncr_log("NCR cur bus stat=%02x\n", ncr->bus_host & 0xff); - ret |= (ncr->bus_host & 0xff); + ncr_bus_read(ncr_dev); + ncr_log("NCR cur bus stat=%02x\n", ncr->cur_bus & 0xff); + ret |= (ncr->cur_bus & 0xff); break; case 5: /* Bus and Status register */ ncr_log("Read: Bus and Status register\n"); ret = 0; - ncr->bus_host = get_bus_host(ncr); + bus = get_bus_host(ncr); ncr_log("Get host from Interrupt\n"); /*Check if the phase in process matches with TCR's*/ - if ((ncr->bus_host & SCSI_PHASE_MESSAGE_IN) == - (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN)) - { + if ((bus & SCSI_PHASE_MESSAGE_IN) == (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN)) { ncr_log("Phase match\n"); ret |= STATUS_PHASE_MATCH; - } - else + } else picint(1 << ncr_dev->irq); - ncr_wait_process(ncr_dev); + ncr_bus_read(ncr_dev); + bus = ncr->cur_bus; - if (ncr->bus_host & BUS_ACK) + if (bus & BUS_ACK) ret |= STATUS_ACK; - if ((ncr->bus_host & BUS_REQ) && (ncr->mode & MODE_DMA)) { + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) { ncr_log("Entering DMA mode\n"); ret |= STATUS_DRQ; - int bus = 0; + bus_state = 0; - if (ncr->bus_host & BUS_IO) - bus |= TCR_IO; - if (ncr->bus_host & BUS_CD) - bus |= TCR_CD; - if (ncr->bus_host & BUS_MSG) - bus |= TCR_MSG; - if ((ncr->tcr & 7) != bus) - { + 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 (!(ncr->bus_host & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) - { + if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { ncr_log("Busy error\n"); ret |= STATUS_BUSY_ERROR; } @@ -536,11 +733,12 @@ ncr_read(uint16_t port, void *priv) break; } - ncr_log("NCR5380 read(%04x)=%02x @%04X:%04X\n", port & 7, ret, CS,cpu_state.pc); + ncr_log("NCR5380 read(%04x)=%02x\n", port & 7, ret); return(ret); } + /* Memory-mapped I/O READ handler. */ static uint8_t memio_read(uint32_t addr, void *priv) @@ -549,9 +747,6 @@ memio_read(uint32_t addr, void *priv) uint8_t ret = 0xff; addr &= 0x3fff; -#if ENABLE_NCR5380_LOG - ncr_log("memio_read %08x\n", addr); -#endif if (addr < 0x2000) ret = ncr_dev->bios_rom.rom[addr & 0x1fff]; @@ -575,18 +770,12 @@ memio_read(uint32_t addr, void *priv) break; case 0x3900: - ncr_log("Read 3900 host pos %i status ctrl %02x\n", ncr_dev->buffer_host_pos, ncr_dev->status_ctrl); - ncr_log("Read port 0x3900-0x397f\n"); - if (ncr_dev->buffer_host_pos >= 128 || !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) ret = 0xff; else { ret = ncr_dev->buffer[ncr_dev->buffer_host_pos++]; - ncr_log("Read host buffer=%d\n", ncr_dev->buffer_host_pos); - - if (ncr_dev->buffer_host_pos == 128) - { + if (ncr_dev->buffer_host_pos == 128) { ncr_log("Not ready\n"); ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; } @@ -596,12 +785,10 @@ memio_read(uint32_t addr, void *priv) case 0x3980: switch (addr) { case 0x3980: /* status */ - ret = ncr_dev->status_ctrl;// | 0x80; + ret = ncr_dev->status_ctrl; ncr_log("NCR status ctrl read=%02x\n", ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY); if (!ncr_dev->ncr_busy) - { ret |= STATUS_53C80_ACCESSIBLE; - } break; case 0x3981: /* block counter register*/ @@ -636,31 +823,24 @@ memio_write(uint32_t addr, uint8_t val, void *priv) addr &= 0x3fff; - ncr_log("memio_write(%08x,%02x) @%04X:%04X %i %02x\n", addr, val, CS,cpu_state.pc, ncr_dev->buffer_host_pos, ncr_dev->status_ctrl); + ncr_log("memio_write(%08x,%02x) %i %02x\n", addr, val, ncr_dev->buffer_host_pos, ncr_dev->status_ctrl); if (addr >= 0x3a00) ncr_dev->ext_ram[addr - 0x3a00] = val; else switch (addr & 0x3f80) { case 0x3800: -#if 0 - ncr_log("Write intram %02x %02x\n", addr & 0x3f, val); -#endif ncr_dev->int_ram[addr & 0x3f] = val; break; case 0x3880: -#if ENABLE_NCR5380_LOG - ncr_log("Write 53c80 %04x %02x\n", addr, val); -#endif ncr_write(addr, val, ncr_dev); break; case 0x3900: if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR) && ncr_dev->buffer_host_pos < 128) { ncr_dev->buffer[ncr_dev->buffer_host_pos++] = val; - - if (ncr_dev->buffer_host_pos == 128) - { + + if (ncr_dev->buffer_host_pos == 128) { ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; ncr_dev->ncr_busy = 1; } @@ -670,20 +850,11 @@ memio_write(uint32_t addr, uint8_t val, void *priv) case 0x3980: switch (addr) { case 0x3980: /* Control */ - ncr_log("Write 0x3980: val=%02x CS=%04x, pc=%04x\n", val, CS,cpu_state.pc); - if (val & 0x80) - { - ncr_log("Resetting the 53c400\n"); - picint(1 << ncr_dev->irq); - } - if ((val & CTRL_DATA_DIR) && !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { - ncr_log("Pos 128\n"); ncr_dev->buffer_host_pos = 128; ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; } else if (!(val & CTRL_DATA_DIR) && (ncr_dev->status_ctrl & CTRL_DATA_DIR)) { - ncr_log("Pos 0\n"); ncr_dev->buffer_host_pos = 0; ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; } @@ -691,18 +862,15 @@ memio_write(uint32_t addr, uint8_t val, void *priv) break; case 0x3981: /* block counter register */ - ncr_log("Write 0x3981: val=%d\n", val); + ncr_log("Write block counter register: val=%d\n", val); ncr_dev->block_count = val; ncr_dev->block_count_loaded = 1; + set_dma_enable(ncr_dev, ncr_dev->dma_enabled && ncr_dev->block_count_loaded); - ncr_log("Timer for transfers=%02x\n", ncr_dev->timer_enabled); - if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { - ncr_log("Data Read\n"); ncr_dev->buffer_host_pos = 128; ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; } else { - ncr_log("Data Write\n"); ncr_dev->buffer_host_pos = 0; ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; } @@ -723,10 +891,10 @@ t130b_read(uint32_t addr, void *priv) addr &= 0x3fff; if (addr < 0x1800) ret = ncr_dev->bios_rom.rom[addr & 0x1fff]; - else - if (addr < 0x1880) + else if (addr >= 0x1800 && addr < 0x1880) ret = ncr_dev->ext_ram[addr & 0x7f]; + ncr_log("MEM: Reading %02X from %08X\n", ret, addr); return(ret); } @@ -738,6 +906,7 @@ t130b_write(uint32_t addr, uint8_t val, void *priv) ncr5380_t *ncr_dev = (ncr5380_t *)priv; addr &= 0x3fff; + ncr_log("MEM: Writing %02X to %08X\n", val, addr); if (addr >= 0x1800 && addr < 0x1880) ncr_dev->ext_ram[addr & 0x7f] = val; } @@ -750,30 +919,21 @@ t130b_in(uint16_t port, void *priv) uint8_t ret = 0xff; switch (port & 0x0f) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: + case 0x00: case 0x01: case 0x02: case 0x03: ret = memio_read((port & 7) | 0x3980, ncr_dev); break; - case 0x04: - case 0x05: + case 0x04: case 0x05: ret = memio_read(0x3900, ncr_dev); break; - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: ret = ncr_read(port, ncr_dev); break; } + ncr_log("I/O: Reading %02X from %04X\n", ret, port); return(ret); } @@ -783,655 +943,180 @@ t130b_out(uint16_t port, uint8_t val, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_log("I/O: Writing %02X to %04X\n", val, port); + switch (port & 0x0f) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: + case 0x00: case 0x01: case 0x02: case 0x03: memio_write((port & 7) | 0x3980, val, ncr_dev); break; - case 0x04: - case 0x05: + case 0x04: case 0x05: memio_write(0x3900, val, ncr_dev); break; - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: ncr_write(port, val, ncr_dev); break; } } -static uint8_t -scsiat_in(uint16_t port, void *priv) -{ - ncr5380_t *ncr_dev = (ncr5380_t *)priv; - uint8_t ret = 0xff; - - switch (port & 0x0f) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - ret = ncr_read(port, ncr_dev); - break; - } - - pclog("SCSI AT read=0x%03x, ret=%02x, CS:%08x, PC:%08x\n", port, ret, CS,cpu_state.pc); - - return(ret); -} - - -static void -scsiat_out(uint16_t port, uint8_t val, void *priv) -{ - ncr5380_t *ncr_dev = (ncr5380_t *)priv; - ncr_t *ncr = &ncr_dev->ncr; - scsi_device_t *dev = &SCSIDevices[ncr->target_id]; - - pclog("SCSI AT write=0x%03x, val=%02x, CS:%08x, PC:%08x\n", port, val, CS,cpu_state.pc); - switch (port & 0x0f) { - case 0x08: - ncr->unk_08 = val; - - if (ncr->unk_08 & 0x08) - { - if (ncr->dma_mode == DMA_INITIATOR_RECEIVE) - { - while (ncr_dev->buffer_host_pos < 128) - { - uint8_t temp; - - temp = ncr_dev->buffer[ncr_dev->buffer_host_pos++]; - - pclog("Read Buffer host=%d\n", ncr_dev->buffer_host_pos); - - ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; - ncr->bus_host |= BUS_SETDATA(temp); - - if (ncr_dev->buffer_host_pos == 128) - break; - } - } - else if (ncr->dma_mode == DMA_SEND) - { - while (ncr_dev->buffer_host_pos < 128) - { - /* Data ready. */ - uint8_t temp; - - ncr_wait_process(ncr_dev); - temp = BUS_GETDATA(ncr->bus_host); - ncr->bus_host = get_bus_host(ncr); - - ncr_dev->buffer[ncr_dev->buffer_host_pos++] = temp; - - pclog("Write Buffer host=%d\n", ncr_dev->buffer_host_pos); - - if (ncr_dev->buffer_host_pos == 128) - { - - break; - } - } - } - } - - if (ncr->unk_08 & 0x01) - { - ncr_dev->block_count_loaded = 1; - ncr_dev->block_count = dev->BufferLength / 128; - } - break; - - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - ncr_write(port, val, ncr_dev); - break; - } -} static void ncr_callback(void *priv) { - ncr5380_t *ncr_dev = (ncr5380_t *)priv; - ncr_t *ncr = &ncr_dev->ncr; - scsi_device_t *dev = &SCSIDevices[ncr->target_id]; - int c = 0; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + int bus, bt = 0, c = 0; + uint8_t temp, data; - ncr_log("DMA mode=%d\n", ncr->dma_mode); - - if (!ncr_dev->timer_enabled) - { - if (ncr->dma_mode == DMA_IDLE) - { - ncr_dev->timer_period = 10LL * TIMER_USEC; - return; - } - else - { - ncr_dev->timer_period += 10LL * TIMER_USEC; - } - } - else - { - ncr_dev->timer_enabled = 0; - } + ncr_log("DMA mode=%d\n", ncr->dma_mode); + if (ncr->data_wait & 1) + ncr->clear_req = 3; + + if (ncr->dma_mode != DMA_IDLE) + dma_timer_on(ncr_dev); + + if (ncr->data_wait & 1) { + ncr->data_wait &= ~1; if (ncr->dma_mode == DMA_IDLE) - { - ncr->bus_host = get_bus_host(ncr); + return; + } - /*Start the SCSI command layer, which will also make the timings*/ - if (ncr->bus_host & BUS_ARB) - { - ncr_log("Arbitration\n"); - ncr->state = STATE_IDLE; + switch(ncr->dma_mode) { + case DMA_SEND: + if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { + ncr_log("DMA_SEND with DMA direction set wrong\n"); + break; } - if (ncr->state == STATE_IDLE) - { - ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; - if ((ncr->bus_host & BUS_SEL) && !(ncr->bus_host & BUS_BSY)) - { - ncr_log("Selection phase\n"); - uint8_t sel_data = BUS_GETDATA(ncr->bus_host); + ncr_log("Status for writing=%02x\n", ncr_dev->status_ctrl); - ncr->target_id = get_dev_id(sel_data); - - ncr_log("Select - target ID = %i\n", ncr->target_id); + if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) { + ncr_log("Buffer ready\n"); + break; + } - /*Once the device has been found and selected, mark it as busy*/ - if ((ncr->target_id != -1) && scsi_device_present(ncr->target_id)) { - ncr->cur_bus |= BUS_BSY; - ncr_log("Device found at ID %i\n", ncr->target_id); - ncr_log("Current Bus BSY=%02x\n", ncr->cur_bus); - ncr->state = STATE_COMMAND; - ncr->cur_bus = BUS_BSY | BUS_REQ; - ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); - ncr->command_pos = 0; - SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); - picint(1 << ncr_dev->irq); - } - else - { - ncr->state = STATE_IDLE; - ncr->cur_bus = 0; - } + if (!ncr_dev->block_count_loaded) + break; + + while (bt < 64) { + for (c = 0; c < 10; c++) { + ncr_bus_read(ncr_dev); + if (ncr->cur_bus & BUS_REQ) + break; } - } - else if (ncr->state == STATE_COMMAND) - { - int64_t p; - /*Command phase, make sure the ICR ACK bit is set to keep on, - because the device must be acknowledged by ICR*/ - ncr_log("NCR ICR for Command=%02x\n", ncr->bus_host & BUS_ACK); - if (ncr->bus_host & BUS_ACK) - { - /*Write command byte to the output data register*/ - ncr->command[ncr->command_pos++] = BUS_GETDATA(ncr->bus_host); - - ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; - ncr->clear_req = 3; - ncr_log("Current bus for command request=%02x\n", ncr->cur_bus & BUS_REQ); - ncr->cur_bus &= ~BUS_REQ; - - ncr_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(ncr->bus_host)); - if (get_cmd_len(ncr->command[0]) == ncr->command_pos) - { - /*Reset data position to default*/ - ncr->data_pos = 0; - - dev = &SCSIDevices[ncr->target_id]; - - ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->Status); - - dev->BufferLength = -1; - - /*Now, execute the given SCSI command*/ - scsi_device_command_phase0(ncr->target_id, ncr->command); - - ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->BufferLength, dev->Phase); - - if (dev->Status != SCSI_STATUS_OK) - ncr_dev->is_non_data_mode = 1; - - if (ncr_dev->is_non_data_mode) - { - ncr_dev->is_non_data_mode = 0; - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - return; - } - - /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ - if (dev->BufferLength && (dev->Phase == SCSI_PHASE_DATA_IN || dev->Phase == SCSI_PHASE_DATA_OUT)) { - dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength); - - p = scsi_device_get_callback(ncr->target_id); - if (p <= 0LL) { - ncr_dev->temp_period += (int64_t)(dev->BufferLength); - } else { - ncr_dev->media_period += p; - } - } - - if (dev->Phase == SCSI_PHASE_DATA_OUT) { - /* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */ - ncr_log("Next state is data out\n"); - ncr->new_phase = SCSI_PHASE_DATA_OUT; - ncr->wait_data = 4; - ncr->clear_req = 4; - } else { - /* Other command - execute immediately. */ - ncr->new_phase = dev->Phase; - - if (ncr->new_phase == SCSI_PHASE_DATA_IN) - { - scsi_device_command_phase1(ncr->target_id); - } - - ncr->wait_data = 4; - } - } - } - } - else if (ncr->state == STATE_DATAIN) - { - dev = &SCSIDevices[ncr->target_id]; - ncr_log("Data In ACK=%02x\n", ncr->bus_host & BUS_ACK); - if (ncr->bus_host & BUS_ACK) - { - if (ncr->data_pos >= dev->BufferLength) { - - if (dev->CmdBuffer != NULL) - { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; - ncr->clear_req = 3; - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_DATA_IN; - } - } - } - else if (ncr->state == STATE_DATAOUT) - { - dev = &SCSIDevices[ncr->target_id]; + if (c == 10) + break; - ncr_log("Data Out ACK=%02x\n", ncr->bus_host & BUS_ACK); - if (ncr->bus_host & BUS_ACK) - { - dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); - - if (ncr->data_pos >= dev->BufferLength) { - scsi_device_command_phase1(ncr->target_id); + /* Data ready. */ + data = ncr_dev->buffer[ncr_dev->buffer_pos]; + bus = get_bus_host(ncr) & ~BUS_DATAMASK; + bus |= BUS_SETDATA(data); - if (dev->CmdBuffer != NULL) - { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + ncr_bus_update(priv, bus | BUS_ACK); + ncr_bus_update(priv, bus & ~BUS_ACK); + + bt++; + ncr_dev->buffer_pos++; + ncr_log("Buffer pos for writing = %d\n", ncr_dev->buffer_pos); + + if (ncr_dev->buffer_pos == 128) { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + ncr_dev->ncr_busy = 0; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + ncr_log("Remaining blocks to be written=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + set_dma_enable(ncr_dev, 0); + ncr_log("IO End of write transfer\n"); + + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) { + ncr_log("NCR write irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); } - - ncr->cur_bus &= ~BUS_REQ; - ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } - else - { - /*More data is to be transferred, place a request*/ - ncr->cur_bus |= BUS_REQ; - ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); } + break; } } - else if (ncr->state == STATE_STATUS) - { - if (ncr->bus_host & BUS_ACK) - { - /*All transfers done, wait until next transfer*/ - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_MESSAGE_IN; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } + break; + + case DMA_INITIATOR_RECEIVE: + if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { + ncr_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); + break; } - else if (ncr->state == STATE_MESSAGEIN) - { - if (ncr->bus_host & BUS_ACK) - { - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = BUS_IDLE; - ncr->wait_data = 4; + + ncr_log("Status for reading=%02x\n", ncr_dev->status_ctrl); + + if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) + break; + + if (!ncr_dev->block_count_loaded) + break; + + while (bt < 64) { + for (c = 0; c < 10; c++) { + ncr_bus_read(ncr_dev); + if (ncr->cur_bus & BUS_REQ) + break; + } + + if (c == 10) + break; + + /* Data ready. */ + ncr_bus_read(ncr_dev); + temp = BUS_GETDATA(ncr->cur_bus); + + bus = get_bus_host(ncr); + + ncr_bus_update(priv, bus | BUS_ACK); + ncr_bus_update(priv, bus & ~BUS_ACK); + + ncr_dev->buffer[ncr_dev->buffer_pos++] = temp; + bt++; + + if (ncr_dev->buffer_pos == 128) { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + + ncr_log("Remaining blocks to be read=%d\n", ncr_dev->block_count); + + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + set_dma_enable(ncr_dev, 0); + ncr_log("IO End of read transfer\n"); + + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) { + ncr_log("NCR read irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } + } + break; } } - } - - if (ncr_dev->type < 3) - { - if (((ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY) && - (ncr->dma_mode == DMA_SEND || ncr->dma_mode == DMA_INITIATOR_RECEIVE))) - { - ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) ncr_dev->temp_period); - ncr_dev->timer_period = (ncr_dev->media_period + ((int64_t) ncr_dev->period) + (40LL * TIMER_USEC)) / 450; - ncr_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods), media periods = %" PRId64 " \n", ncr_dev->timer_period, ncr_dev->temp_period, ncr_dev->media_period); - } - - if (ncr->dma_mode == DMA_INITIATOR_RECEIVE) - { - if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { - ncr_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); - return; - } - - ncr_log("Status for reading=%02x\n", ncr_dev->status_ctrl); - - if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) return; - - if (!ncr_dev->block_count_loaded) return; - - while (c < 64) - { - /* Data ready. */ - uint8_t temp; + break; + } - ncr_wait_process(ncr_dev); - temp = BUS_GETDATA(ncr->bus_host); - ncr->bus_host = get_bus_host(ncr); + ncr_bus_read(ncr_dev); - if (ncr->data_pos >= dev->BufferLength) { - - if (dev->CmdBuffer != NULL) - { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; - ncr->clear_req = 3; - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_DATA_IN; - } - - ncr_dev->buffer[ncr_dev->buffer_pos++] = temp; - ncr_log("Buffer pos for reading=%d\n", ncr_dev->buffer_pos); - - c++; - - if (ncr_dev->buffer_pos == 128) - { - ncr_dev->buffer_pos = 0; - ncr_dev->buffer_host_pos = 0; - ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; - ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; - ncr_log("Remaining blocks to be read=%d\n", ncr_dev->block_count); - if (!ncr_dev->block_count) { - ncr_dev->block_count_loaded = 0; - ncr_log("IO End of read transfer\n"); - - ncr->isr |= STATUS_END_OF_DMA; - if (ncr->mode & MODE_ENA_EOP_INT) - { - ncr_log("NCR read irq\n"); - ncr->isr |= STATUS_INT; - picint(1 << ncr_dev->irq); - } - } - break; - } - } - } - else if (ncr->dma_mode == DMA_SEND) - { - if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { - ncr_log("DMA_SEND with DMA direction set wrong\n"); - return; - } - - ncr_log("Status for writing=%02x\n", ncr_dev->status_ctrl); - - if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) - { - ncr_log("Buffer ready\n"); - return; - } - - if (!ncr_dev->block_count_loaded) return; - - while (c < 64) - { - /* Data ready. */ - uint8_t data; - - data = ncr_dev->buffer[ncr_dev->buffer_pos]; - ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; - ncr->bus_host |= BUS_SETDATA(data); - - dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); - - if (ncr->data_pos >= dev->BufferLength) { - scsi_device_command_phase1(ncr->target_id); - - if (dev->CmdBuffer != NULL) - { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - ncr->cur_bus &= ~BUS_REQ; - ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } - else - { - /*More data is to be transferred, place a request*/ - ncr->cur_bus |= BUS_REQ; - ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); - } - - c++; - - if (++ncr_dev->buffer_pos == 128) { - ncr_dev->buffer_pos = 0; - ncr_dev->buffer_host_pos = 0; - ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; - ncr_dev->ncr_busy = 0; - ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; - ncr_log("Remaining blocks to be written=%d\n", ncr_dev->block_count); - if (!ncr_dev->block_count) { - ncr_dev->block_count_loaded = 0; - ncr_log("IO End of write transfer\n"); - - ncr->tcr |= TCR_LAST_BYTE_SENT; - ncr->isr |= STATUS_END_OF_DMA; - if (ncr->mode & MODE_ENA_EOP_INT) - { - ncr_log("NCR write irq\n"); - ncr->isr |= STATUS_INT; - picint(1 << ncr_dev->irq); - } - } - break; - } - } - } - } - else - { - if (((ncr->unk_08 & 0x01) && - (ncr->dma_mode == DMA_SEND || ncr->dma_mode == DMA_INITIATOR_RECEIVE))) - { - ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) ncr_dev->temp_period); - ncr_dev->timer_period = (ncr_dev->media_period + ((int64_t) ncr_dev->period) + (40LL * TIMER_USEC)) / 450; - ncr_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods), media periods = %" PRId64 " \n", ncr_dev->timer_period, ncr_dev->temp_period, ncr_dev->media_period); - } - - if (ncr->dma_mode == DMA_INITIATOR_RECEIVE) - { - if (!(ncr_dev->block_count_loaded)) - return; - - while (c < 64) - { - /* Data ready. */ - uint8_t temp; - - ncr_wait_process(ncr_dev); - temp = BUS_GETDATA(ncr->bus_host); - ncr->bus_host = get_bus_host(ncr); - - if (ncr->data_pos >= dev->BufferLength) { - - if (dev->CmdBuffer != NULL) - { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; - ncr->clear_req = 3; - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_DATA_IN; - } - - ncr_dev->buffer[ncr_dev->buffer_pos++] = temp; - pclog("Buffer pos for reading=%d\n", ncr_dev->buffer_pos); - - c++; - - if (ncr_dev->buffer_pos == 128) - { - ncr_dev->buffer_pos = 0; - ncr_dev->buffer_host_pos = 0; - ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; - pclog("Remaining blocks to be read=%d\n", ncr_dev->block_count); - if (!ncr_dev->block_count) { - ncr_dev->block_count_loaded = 0; - ncr_log("IO End of read transfer\n"); - - ncr->isr |= STATUS_END_OF_DMA; - if (ncr->mode & MODE_ENA_EOP_INT) - { - ncr_log("NCR read irq\n"); - ncr->isr |= STATUS_INT; - picint(1 << ncr_dev->irq); - } - } - break; - } - } - } - else if (ncr->dma_mode == DMA_SEND) - { - if (!ncr_dev->block_count_loaded) return; - - while (c < 64) - { - /* Data ready. */ - uint8_t data; - - data = ncr_dev->buffer[ncr_dev->buffer_pos]; - ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; - ncr->bus_host |= BUS_SETDATA(data); - - dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); - - if (ncr->data_pos >= dev->BufferLength) { - scsi_device_command_phase1(ncr->target_id); - - if (dev->CmdBuffer != NULL) - { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - ncr->cur_bus &= ~BUS_REQ; - ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } - else - { - /*More data is to be transferred, place a request*/ - ncr->cur_bus |= BUS_REQ; - ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); - } - - c++; - - if (++ncr_dev->buffer_pos == 128) { - ncr_dev->buffer_pos = 0; - ncr_dev->buffer_host_pos = 0; - ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; - pclog("Remaining blocks to be written=%d\n", ncr_dev->block_count); - if (!ncr_dev->block_count) { - ncr_dev->block_count_loaded = 0; - ncr_log("IO End of write transfer\n"); - - ncr->tcr |= TCR_LAST_BYTE_SENT; - ncr->isr |= STATUS_END_OF_DMA; - if (ncr->mode & MODE_ENA_EOP_INT) - { - ncr_log("NCR write irq\n"); - ncr->isr |= STATUS_INT; - picint(1 << ncr_dev->irq); - } - } - break; - } - } - } - } - - ncr_wait_process(ncr_dev); - if (!(ncr->bus_host & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { - pclog("Updating DMA\n"); + if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { + ncr_log("Updating DMA\n"); ncr->mode &= ~MODE_DMA; ncr->dma_mode = DMA_IDLE; + dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); } } @@ -1439,6 +1124,7 @@ ncr_callback(void *priv) static void * ncr_init(const device_t *info) { + wchar_t *fn = NULL; char temp[128]; ncr5380_t *ncr_dev; @@ -1449,64 +1135,54 @@ ncr_init(const device_t *info) switch(ncr_dev->type) { case 0: /* Longshine LCS6821N */ - ncr_dev->rom_addr = 0xDC000; + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); + ncr_dev->irq = device_get_config_int("irq"); rom_init(&ncr_dev->bios_rom, LCS6821N_ROM, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - mem_mapping_disable(&ncr_dev->bios_rom.mapping); mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, memio_read, NULL, NULL, memio_write, NULL, NULL, - ncr_dev->bios_rom.rom, 0, ncr_dev); + ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); break; case 1: /* Rancho RT1000B */ - ncr_dev->rom_addr = 0xDC000; - rom_init(&ncr_dev->bios_rom, RT1000B_ROM, + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); + ncr_dev->irq = device_get_config_int("irq"); + ncr_dev->bios_ver = device_get_config_int("bios_ver"); + + if (ncr_dev->bios_ver == 1) + fn = RT1000B_820R_ROM; + else + fn = RT1000B_810R_ROM; + + rom_init(&ncr_dev->bios_rom, fn, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - mem_mapping_disable(&ncr_dev->bios_rom.mapping); - mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, memio_read, NULL, NULL, memio_write, NULL, NULL, - ncr_dev->bios_rom.rom, 0, ncr_dev); + ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); break; case 2: /* Trantor T130B */ - ncr_dev->rom_addr = 0xDC000; + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); ncr_dev->base = device_get_config_hex16("base"); ncr_dev->irq = device_get_config_int("irq"); - rom_init(&ncr_dev->bios_rom, T130B_ROM, - ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, - t130b_read, NULL, NULL, - t130b_write, NULL, NULL, - ncr_dev->bios_rom.rom, 0, ncr_dev); + if (ncr_dev->rom_addr > 0x00000) { + rom_init(&ncr_dev->bios_rom, T130B_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + t130b_read, NULL, NULL, + t130b_write, NULL, NULL, + ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); + } io_sethandler(ncr_dev->base, 16, t130b_in,NULL,NULL, t130b_out,NULL,NULL, ncr_dev); break; - - case 3: /* Sumo SCSI-AT */ - ncr_dev->base = device_get_config_hex16("base"); - ncr_dev->irq = device_get_config_int("irq"); - ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); - rom_init(&ncr_dev->bios_rom, SCSIAT_ROM, - ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - mem_mapping_disable(&ncr_dev->bios_rom.mapping); - - mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, - t130b_read, NULL, NULL, - t130b_write, NULL, NULL, - ncr_dev->bios_rom.rom, 0, ncr_dev); - - io_sethandler(ncr_dev->base, 16, - scsiat_in,NULL,NULL, scsiat_out,NULL,NULL, ncr_dev); - break; } sprintf(temp, "%s: BIOS=%05X", ncr_dev->name, ncr_dev->rom_addr); @@ -1516,13 +1192,12 @@ ncr_init(const device_t *info) sprintf(&temp[strlen(temp)], " IRQ=%d", ncr_dev->irq); ncr_log("%s\n", temp); - ncr_reset(&ncr_dev->ncr); + ncr_reset(&ncr_dev->ncr); ncr_dev->status_ctrl = STATUS_BUFFER_NOT_READY; - ncr_dev->buffer_host_pos = 128; - - ncr_dev->timer_period = 10LL * TIMER_USEC; - timer_add(ncr_callback, &ncr_dev->timer_period, TIMER_ALWAYS_ENABLED, ncr_dev); - + ncr_dev->buffer_host_pos = 128; + + timer_add(&ncr_dev->timer, ncr_callback, ncr_dev, 0); + return(ncr_dev); } @@ -1532,15 +1207,13 @@ ncr_close(void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; - if (ncr_dev) - { - /* Tell the timer to terminate. */ - ncr_dev->timer_period = 0LL; - ncr_dev->timer_enabled = 0LL; - - free(ncr_dev); - ncr_dev = NULL; - } + if (ncr_dev) { + /* Tell the timer to terminate. */ + timer_stop(&ncr_dev->timer); + + free(ncr_dev); + ncr_dev = NULL; + } } @@ -1554,10 +1227,9 @@ lcs6821n_available(void) static int rt1000b_available(void) { - return(rom_present(RT1000B_ROM)); + return(rom_present(RT1000B_820R_ROM) && rom_present(RT1000B_810R_ROM)); } - static int t130b_available(void) { @@ -1565,13 +1237,126 @@ t130b_available(void) } -static int -scsiat_available(void) -{ - return(rom_present(SCSIAT_ROM)); -} +static const device_config_t ncr5380_mmio_config[] = { + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, + { + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "" + } + }, + + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_config_t rancho_config[] = { + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, + { + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "" + } + }, + + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "" + } + }, + }, + { + "bios_ver", "BIOS Version", CONFIG_SELECTION, "", 1, + { + { + "8.20R", 1 + }, + { + "8.10R", 0 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; static const device_config_t t130b_config[] = { + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "" + } + }, + }, { "base", "Address", CONFIG_HEX16, "", 0x0350, { @@ -1614,102 +1399,6 @@ static const device_config_t t130b_config[] = { } }; -static const device_config_t scsiat_config[] = { - { - "base", "Address", CONFIG_HEX16, "", 0x0310, - { - { - "None", 0 - }, - { - "300H", 0x0300 - }, - { - "310H", 0x0310 - }, - { - "320H", 0x0320 - }, - { - "330H", 0x0330 - }, - { - "340H", 0x0340 - }, - { - "350H", 0x0350 - }, - { - "360H", 0x0360 - }, - { - "370H", 0x0370 - }, - { - "" - } - }, - }, - { - "irq", "IRQ", CONFIG_SELECTION, "", 5, - { - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 10", 10 - }, - { - "IRQ 11", 11 - }, - { - "IRQ 12", 12 - }, - { - "IRQ 14", 14 - }, - { - "IRQ 15", 15 - }, - { - "" - } - }, - }, - { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, - { - { - "Disabled", 0 - }, - { - "C800H", 0xc8000 - }, - { - "CC00H", 0xcc000 - }, - { - "D800H", 0xd8000 - }, - { - "DC00H", 0xdc000 - }, - { - "" - } - }, - }, - { - "", "", -1 - } -}; - const device_t scsi_lcs6821n_device = { @@ -1719,7 +1408,7 @@ const device_t scsi_lcs6821n_device = ncr_init, ncr_close, NULL, lcs6821n_available, NULL, NULL, - NULL + ncr5380_mmio_config }; const device_t scsi_rt1000b_device = @@ -1730,7 +1419,7 @@ const device_t scsi_rt1000b_device = ncr_init, ncr_close, NULL, rt1000b_available, NULL, NULL, - NULL + rancho_config }; const device_t scsi_t130b_device = @@ -1743,14 +1432,3 @@ const device_t scsi_t130b_device = NULL, NULL, t130b_config }; - -const device_t scsi_scsiat_device = -{ - "Sumo SCSI-AT", - DEVICE_ISA, - 3, - ncr_init, ncr_close, NULL, - scsiat_available, - NULL, NULL, - scsiat_config -}; diff --git a/src/scsi/scsi_ncr5380.h b/src/scsi/scsi_ncr5380.h index 55b16f654..5e14f77a2 100644 --- a/src/scsi/scsi_ncr5380.h +++ b/src/scsi/scsi_ncr5380.h @@ -27,7 +27,9 @@ extern const device_t scsi_lcs6821n_device; extern const device_t scsi_rt1000b_device; extern const device_t scsi_t130b_device; +#if defined(DEV_BRANCH) && defined(USE_SUMO) extern const device_t scsi_scsiat_device; +#endif #endif /*SCSI_NCR5380_H*/ diff --git a/src/scsi/scsi_ncr53c810.c b/src/scsi/scsi_ncr53c810.c deleted file mode 100644 index 459ca28fd..000000000 --- a/src/scsi/scsi_ncr53c810.c +++ /dev/null @@ -1,2213 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of the NCR 53C810 SCSI Host Adapter made by - * NCR and later Symbios and LSI. This controller was designed - * for the PCI bus. - * - * Version: @(#)scsi_ncr53c810.c 1.0.14 2018/05/28 - * - * Authors: Paul Brook (QEMU) - * Artyom Tarasenko (QEMU) - * TheCollector1995, - * Miran Grca, - * - * Copyright 2006-2018 Paul Brook. - * Copyright 2009-2018 Artyom Tarasenko. - * Copyright 2017,2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include -#include "../86box.h" -#include "../io.h" -#include "../dma.h" -#include "../pic.h" -#include "../mem.h" -#include "../rom.h" -#include "../pci.h" -#include "../device.h" -#include "../nvr.h" -#include "../timer.h" -#include "../plat.h" -#include "scsi.h" -#include "scsi_device.h" -#include "scsi_ncr53c810.h" - -#define NCR53C810_ROM L"roms/scsi/ncr53c810/NCR307.BIN" - -#define NCR_SCNTL0_TRG 0x01 -#define NCR_SCNTL0_AAP 0x02 -#define NCR_SCNTL0_EPC 0x08 -#define NCR_SCNTL0_WATN 0x10 -#define NCR_SCNTL0_START 0x20 - -#define NCR_SCNTL1_SST 0x01 -#define NCR_SCNTL1_IARB 0x02 -#define NCR_SCNTL1_AESP 0x04 -#define NCR_SCNTL1_RST 0x08 -#define NCR_SCNTL1_CON 0x10 -#define NCR_SCNTL1_DHP 0x20 -#define NCR_SCNTL1_ADB 0x40 -#define NCR_SCNTL1_EXC 0x80 - -#define NCR_SCNTL2_WSR 0x01 -#define NCR_SCNTL2_VUE0 0x02 -#define NCR_SCNTL2_VUE1 0x04 -#define NCR_SCNTL2_WSS 0x08 -#define NCR_SCNTL2_SLPHBEN 0x10 -#define NCR_SCNTL2_SLPMD 0x20 -#define NCR_SCNTL2_CHM 0x40 -#define NCR_SCNTL2_SDU 0x80 - -#define NCR_ISTAT_DIP 0x01 -#define NCR_ISTAT_SIP 0x02 -#define NCR_ISTAT_INTF 0x04 -#define NCR_ISTAT_CON 0x08 -#define NCR_ISTAT_SEM 0x10 -#define NCR_ISTAT_SIGP 0x20 -#define NCR_ISTAT_SRST 0x40 -#define NCR_ISTAT_ABRT 0x80 - -#define NCR_SSTAT0_SDP0 0x01 -#define NCR_SSTAT0_RST 0x02 -#define NCR_SSTAT0_WOA 0x04 -#define NCR_SSTAT0_LOA 0x08 -#define NCR_SSTAT0_AIP 0x10 -#define NCR_SSTAT0_OLF 0x20 -#define NCR_SSTAT0_ORF 0x40 -#define NCR_SSTAT0_ILF 0x80 - -#define NCR_SIST0_PAR 0x01 -#define NCR_SIST0_RST 0x02 -#define NCR_SIST0_UDC 0x04 -#define NCR_SIST0_SGE 0x08 -#define NCR_SIST0_RSL 0x10 -#define NCR_SIST0_SEL 0x20 -#define NCR_SIST0_CMP 0x40 -#define NCR_SIST0_MA 0x80 - -#define NCR_SIST1_HTH 0x01 -#define NCR_SIST1_GEN 0x02 -#define NCR_SIST1_STO 0x04 -#define NCR_SIST1_SBMC 0x10 - -#define NCR_SOCL_IO 0x01 -#define NCR_SOCL_CD 0x02 -#define NCR_SOCL_MSG 0x04 -#define NCR_SOCL_ATN 0x08 -#define NCR_SOCL_SEL 0x10 -#define NCR_SOCL_BSY 0x20 -#define NCR_SOCL_ACK 0x40 -#define NCR_SOCL_REQ 0x80 - -#define NCR_DSTAT_IID 0x01 -#define NCR_DSTAT_SIR 0x04 -#define NCR_DSTAT_SSI 0x08 -#define NCR_DSTAT_ABRT 0x10 -#define NCR_DSTAT_BF 0x20 -#define NCR_DSTAT_MDPE 0x40 -#define NCR_DSTAT_DFE 0x80 - -#define NCR_DCNTL_COM 0x01 -#define NCR_DCNTL_IRQD 0x02 -#define NCR_DCNTL_STD 0x04 -#define NCR_DCNTL_IRQM 0x08 -#define NCR_DCNTL_SSM 0x10 -#define NCR_DCNTL_PFEN 0x20 -#define NCR_DCNTL_PFF 0x40 -#define NCR_DCNTL_CLSE 0x80 - -#define NCR_DMODE_MAN 0x01 -#define NCR_DMODE_BOF 0x02 -#define NCR_DMODE_ERMP 0x04 -#define NCR_DMODE_ERL 0x08 -#define NCR_DMODE_DIOM 0x10 -#define NCR_DMODE_SIOM 0x20 - -#define NCR_CTEST2_DACK 0x01 -#define NCR_CTEST2_DREQ 0x02 -#define NCR_CTEST2_TEOP 0x04 -#define NCR_CTEST2_PCICIE 0x08 -#define NCR_CTEST2_CM 0x10 -#define NCR_CTEST2_CIO 0x20 -#define NCR_CTEST2_SIGP 0x40 -#define NCR_CTEST2_DDIR 0x80 - -#define NCR_CTEST5_BL2 0x04 -#define NCR_CTEST5_DDIR 0x08 -#define NCR_CTEST5_MASR 0x10 -#define NCR_CTEST5_DFSN 0x20 -#define NCR_CTEST5_BBCK 0x40 -#define NCR_CTEST5_ADCK 0x80 - -/* Enable Response to Reselection */ -#define NCR_SCID_RRE 0x60 - -#define PHASE_DO 0 -#define PHASE_DI 1 -#define PHASE_CMD 2 -#define PHASE_ST 3 -#define PHASE_MO 6 -#define PHASE_MI 7 -#define PHASE_MASK 7 - -/* Maximum length of MSG IN data. */ -#define NCR_MAX_MSGIN_LEN 8 - -/* Flag set if this is a tagged command. */ -#define NCR_TAG_VALID (1 << 16) - -#define NCR_BUF_SIZE 4096 - -typedef struct ncr53c810_request { - uint32_t tag; - uint32_t dma_len; - uint8_t *dma_buf; - uint32_t pending; - int out; -} ncr53c810_request; - -typedef enum -{ - SCSI_STATE_SEND_COMMAND, - SCSI_STATE_READ_DATA, - SCSI_STATE_WRITE_DATA, - SCSI_STATE_READ_STATUS, - SCSI_STATE_READ_MESSAGE, - SCSI_STATE_WRITE_MESSAGE -} scsi_state_t; - -typedef struct { - uint8_t pci_slot; - int has_bios; - rom_t bios; - int PCIBase; - int MMIOBase; - mem_mapping_t mmio_mapping; - int RAMBase; - mem_mapping_t ram_mapping; - - int carry; /* ??? Should this be an a visible register somewhere? */ - int status; - /* Action to take at the end of a MSG IN phase. - 0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN. */ - int msg_action; - int msg_len; - uint8_t msg[NCR_MAX_MSGIN_LEN]; - /* 0 if SCRIPTS are running or stopped. - * 1 if a Wait Reselect instruction has been issued. - * 2 if processing DMA from ncr53c810_execute_script. - * 3 if a DMA operation is in progress. */ - int waiting; - - uint8_t current_lun; - uint8_t select_id; - int command_complete; - ncr53c810_request *current; - - int irq; - - uint32_t dsa; - uint32_t temp; - uint32_t dnad; - uint32_t dbc; - uint8_t istat; - uint8_t dcmd; - uint8_t dstat; - uint8_t dien; - uint8_t sist0; - uint8_t sist1; - uint8_t sien0; - uint8_t sien1; - uint8_t mbox0; - uint8_t mbox1; - uint8_t dfifo; - uint8_t ctest2; - uint8_t ctest3; - uint8_t ctest4; - uint8_t ctest5; - uint32_t dsp; - uint32_t dsps; - uint8_t dmode; - uint8_t dcntl; - uint8_t scntl0; - uint8_t scntl1; - uint8_t scntl2; - uint8_t scntl3; - uint8_t sstat0; - uint8_t sstat1; - uint8_t scid; - uint8_t sxfer; - uint8_t socl; - uint8_t sdid; - uint8_t ssid; - uint8_t sfbr; - uint8_t stest1; - uint8_t stest2; - uint8_t stest3; - uint8_t sidl; - uint8_t stime0; - uint8_t respid; - uint32_t scratcha; - uint32_t scratchb; - uint8_t sbr; - uint8_t chip_rev; - int last_level; - void *hba_private; - uint8_t gpreg0; - uint32_t buffer_pos; - int32_t temp_buf_len; - uint8_t last_command; - - uint8_t sstop; - - uint8_t regop; - uint32_t adder; - - int64_t timer_period; - int64_t timer_enabled; -} ncr53c810_t; - - -#ifdef ENABLE_NCR53C810_LOG -int ncr53c810_do_log = ENABLE_NCR53C810_LOG; -#endif - - -static void -ncr53c810_log(const char *fmt, ...) -{ -#ifdef ENABLE_NCR53C810_LOG - va_list ap; - - if (ncr53c810_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - -static uint8_t ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset); -static void ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val); - - -static __inline__ int32_t -sextract32(uint32_t value, int start, int length) -{ - /* Note that this implementation relies on right shift of signed - * integers being an arithmetic shift. - */ - return ((int32_t)(value << (32 - length - start))) >> (32 - length); -} - - -static __inline__ uint32_t -deposit32(uint32_t value, int start, int length, - uint32_t fieldval) -{ - uint32_t mask; - mask = (~0U >> (32 - length)) << start; - return (value & ~mask) | ((fieldval << start) & mask); -} - - -static __inline__ int -ncr53c810_irq_on_rsl(ncr53c810_t *dev) -{ - return (dev->sien0 & NCR_SIST0_RSL) && (dev->scid & NCR_SCID_RRE); -} - - -static void -ncr53c810_soft_reset(ncr53c810_t *dev) -{ - int i; - - ncr53c810_log("LSI Reset\n"); - dev->timer_period = dev->timer_enabled = 0; - - dev->carry = 0; - - dev->msg_action = 0; - dev->msg_len = 0; - dev->waiting = 0; - dev->dsa = 0; - dev->dnad = 0; - dev->dbc = 0; - dev->temp = 0; - dev->scratcha = 0; - dev->scratchb = 0; - dev->istat = 0; - dev->dcmd = 0x40; - dev->dstat = NCR_DSTAT_DFE; - dev->dien = 0; - dev->sist0 = 0; - dev->sist1 = 0; - dev->sien0 = 0; - dev->sien1 = 0; - dev->mbox0 = 0; - dev->mbox1 = 0; - dev->dfifo = 0; - dev->ctest2 = NCR_CTEST2_DACK; - dev->ctest3 = 0; - dev->ctest4 = 0; - dev->ctest5 = 0; - dev->dsp = 0; - dev->dsps = 0; - dev->dmode = 0; - dev->dcntl = 0; - dev->scntl0 = 0xc0; - dev->scntl1 = 0; - dev->scntl2 = 0; - dev->scntl3 = 0; - dev->sstat0 = 0; - dev->sstat1 = 0; - dev->scid = 7; - dev->sxfer = 0; - dev->socl = 0; - dev->sdid = 0; - dev->ssid = 0; - dev->stest1 = 0; - dev->stest2 = 0; - dev->stest3 = 0; - dev->sidl = 0; - dev->stime0 = 0; - dev->respid = 0x80; - dev->sbr = 0; - dev->last_level = 0; - dev->gpreg0 = 0; - dev->sstop = 1; - - for (i = 0; i < 16; i++) - scsi_device_reset(i); -} - - -static void -ncr53c810_read(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) -{ - uint32_t i = 0; - - ncr53c810_log("ncr53c810_read(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); - - if (dev->dmode & NCR_DMODE_SIOM) { - ncr53c810_log("NCR 810: Reading from I/O address %04X\n", (uint16_t) addr); - for (i = 0; i < len; i++) - buf[i] = inb((uint16_t) (addr + i)); - } else { - ncr53c810_log("NCR 810: Reading from memory address %08X\n", addr); - DMAPageRead(addr, buf, len); - } -} - - -static void -ncr53c810_write(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) -{ - uint32_t i = 0; - - ncr53c810_log("ncr53c810_write(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); - - if (dev->dmode & NCR_DMODE_DIOM) { - ncr53c810_log("NCR 810: Writing to I/O address %04X\n", (uint16_t) addr); - for (i = 0; i < len; i++) - outb((uint16_t) (addr + i), buf[i]); - } else { - ncr53c810_log("NCR 810: Writing to memory address %08X\n", addr); - DMAPageWrite(addr, buf, len); - } -} - - -static __inline__ uint32_t -read_dword(ncr53c810_t *dev, uint32_t addr) -{ - uint32_t buf; - ncr53c810_log("Reading the next DWORD from memory (%08X)...\n", addr); - DMAPageRead(addr, (uint8_t *)&buf, 4); - return buf; -} - - -static -void do_irq(ncr53c810_t *dev, int level) -{ - if (level) { - pci_set_irq(dev->pci_slot, PCI_INTA); - ncr53c810_log("Raising IRQ...\n"); - } else { - pci_clear_irq(dev->pci_slot, PCI_INTA); - ncr53c810_log("Lowering IRQ...\n"); - } -} - - -static void -ncr53c810_update_irq(ncr53c810_t *dev) -{ - int level; - - /* It's unclear whether the DIP/SIP bits should be cleared when the - Interrupt Status Registers are cleared or when istat is read. - We currently do the formwer, which seems to work. */ - level = 0; - if (dev->dstat & 0x7f) { - if ((dev->dstat & dev->dien) & 0x7f) - level = 1; - dev->istat |= NCR_ISTAT_DIP; - } else { - dev->istat &= ~NCR_ISTAT_DIP; - } - - if (dev->sist0 || dev->sist1) { - if ((dev->sist0 & dev->sien0) || (dev->sist1 & dev->sien1)) - level = 1; - dev->istat |= NCR_ISTAT_SIP; - } else { - dev->istat &= ~NCR_ISTAT_SIP; - } - if (dev->istat & NCR_ISTAT_INTF) { - level = 1; - } - - if (level != dev->last_level) { - ncr53c810_log("Update IRQ level %d dstat %02x sist %02x%02x\n", - level, dev->dstat, dev->sist1, dev->sist0); - dev->last_level = level; - do_irq(dev, level); /* Only do something with the IRQ if the new level differs from the previous one. */ - } -} - - -/* Stop SCRIPTS execution and raise a SCSI interrupt. */ -static void -ncr53c810_script_scsi_interrupt(ncr53c810_t *dev, int stat0, int stat1) -{ - uint32_t mask0; - uint32_t mask1; - - ncr53c810_log("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", - stat1, stat0, dev->sist1, dev->sist0); - dev->sist0 |= stat0; - dev->sist1 |= stat1; - /* Stop processor on fatal or unmasked interrupt. As a special hack - we don't stop processing when raising STO. Instead continue - execution and stop at the next insn that accesses the SCSI bus. */ - mask0 = dev->sien0 | ~(NCR_SIST0_CMP | NCR_SIST0_SEL | NCR_SIST0_RSL); - mask1 = dev->sien1 | ~(NCR_SIST1_GEN | NCR_SIST1_HTH); - mask1 &= ~NCR_SIST1_STO; - if ((dev->sist0 & mask0) || (dev->sist1 & mask1)) { - ncr53c810_log("NCR 810: IRQ-mandated stop\n"); - dev->sstop = 1; - dev->timer_period = dev->timer_enabled = 0; - } - ncr53c810_update_irq(dev); -} - - -/* Stop SCRIPTS execution and raise a DMA interrupt. */ -static void -ncr53c810_script_dma_interrupt(ncr53c810_t *dev, int stat) -{ - ncr53c810_log("DMA Interrupt 0x%x prev 0x%x\n", stat, dev->dstat); - dev->dstat |= stat; - ncr53c810_update_irq(dev); - dev->sstop = 1; - dev->timer_period = dev->timer_enabled = 0; -} - - -static __inline__ void -ncr53c810_set_phase(ncr53c810_t *dev, int phase) -{ - dev->sstat1 = (dev->sstat1 & ~PHASE_MASK) | phase; -} - - -static void -ncr53c810_bad_phase(ncr53c810_t *dev, int out, int new_phase) -{ - /* Trigger a phase mismatch. */ - ncr53c810_log("Phase mismatch interrupt\n"); - ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); - dev->sstop = 1; - dev->timer_period = dev->timer_enabled = 0; - ncr53c810_set_phase(dev, new_phase); -} - - -static void -ncr53c810_disconnect(ncr53c810_t *dev) -{ - dev->scntl1 &= ~NCR_SCNTL1_CON; - dev->sstat1 &= ~PHASE_MASK; - if (dev->dcmd & 0x01) /* Select with ATN */ - dev->sstat1 |= 0x07; -} - - -static void -ncr53c810_bad_selection(ncr53c810_t *dev, uint32_t id) -{ - ncr53c810_log("Selected absent target %d\n", id); - ncr53c810_script_scsi_interrupt(dev, 0, NCR_SIST1_STO); - ncr53c810_disconnect(dev); -} - - -/* Callback to indicate that the SCSI layer has completed a command. */ -static void -ncr53c810_command_complete(void *priv, uint32_t status) -{ - ncr53c810_t *dev = (ncr53c810_t *)priv; - int out; - - out = (dev->sstat1 & PHASE_MASK) == PHASE_DO; - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Command complete status=%d\n", dev->current->tag, dev->current_lun, dev->last_command, (int)status); - dev->status = status; - dev->command_complete = 2; - if (dev->waiting && dev->dbc != 0) { - /* Raise phase mismatch for short transfers. */ - ncr53c810_bad_phase(dev, out, PHASE_ST); - } else - ncr53c810_set_phase(dev, PHASE_ST); - - dev->sstop = 0; -} - - -static void -ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) -{ - uint32_t addr, tdbc; - int count; - - scsi_device_t *sd; - - sd = &SCSIDevices[id]; - - if ((!scsi_device_present(id))) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); - return; - } - - if (!dev->current->dma_len) { - /* Wait until data is available. */ - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", id, dev->current_lun, dev->last_command); - return; - } - - /* Make sure count is never bigger than BufferLength. */ - count = tdbc = dev->dbc; - if (count > dev->temp_buf_len) - count = dev->temp_buf_len; - - addr = dev->dnad; - - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA addr=0x%08x len=%d cur_len=%d dev->dbc=%d\n", id, dev->current_lun, dev->last_command, dev->dnad, dev->temp_buf_len, count, tdbc); - dev->dnad += count; - dev->dbc -= count; - - if (out) - ncr53c810_read(dev, addr, sd->CmdBuffer+dev->buffer_pos, count); - else { - if (!dev->buffer_pos) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command); - scsi_device_command_phase1(dev->current->tag); - } - ncr53c810_write(dev, addr, sd->CmdBuffer+dev->buffer_pos, count); - } - - dev->temp_buf_len -= count; - dev->buffer_pos += count; - - if (dev->temp_buf_len <= 0) { - if (out) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); - scsi_device_command_phase1(id); - } - if (sd->CmdBuffer != NULL) { - free(sd->CmdBuffer); - sd->CmdBuffer = NULL; - } - ncr53c810_command_complete(dev, sd->Status); - } else { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command); - dev->sstop = 0; - } -} - - -/* Queue a byte for a MSG IN phase. */ -static void -ncr53c810_add_msg_byte(ncr53c810_t *dev, uint8_t data) -{ - if (dev->msg_len >= NCR_MAX_MSGIN_LEN) - ncr53c810_log("MSG IN data too long\n"); - else { - ncr53c810_log("MSG IN 0x%02x\n", data); - dev->msg[dev->msg_len++] = data; - } -} - - -static int -ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) -{ - scsi_device_t *sd; - uint8_t buf[12]; - - int64_t p; - - double period; - - memset(buf, 0, 12); - DMAPageRead(dev->dnad, buf, MIN(12, dev->dbc)); - if (dev->dbc > 12) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: CDB length %i too big\n", id, dev->current_lun, buf[0], dev->dbc); - dev->dbc = 12; - } - dev->sfbr = buf[0]; - dev->command_complete = 0; - - sd = &SCSIDevices[id]; - if (!scsi_device_present(id)) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); - ncr53c810_bad_selection(dev, id); - return 0; - } - - dev->current = (ncr53c810_request*)malloc(sizeof(ncr53c810_request)); - dev->current->tag = id; - - sd->BufferLength = -1; - - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc); - dev->last_command = buf[0]; - - scsi_device_command_phase0(dev->current->tag, buf); - dev->hba_private = (void *)dev->current; - - dev->waiting = 0; - dev->buffer_pos = 0; - - dev->temp_buf_len = sd->BufferLength; - - if (sd->BufferLength > 0) { - sd->CmdBuffer = (uint8_t *)malloc(sd->BufferLength); - dev->current->dma_len = sd->BufferLength; - } - - if ((sd->Phase == SCSI_PHASE_DATA_IN) && (sd->BufferLength > 0)) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); - ncr53c810_set_phase(dev, PHASE_DI); - p = scsi_device_get_callback(dev->current->tag); - if (p <= 0LL) { - period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ - dev->timer_period += (int64_t) period; - } else - dev->timer_period += p; - return 1; - } else if ((sd->Phase == SCSI_PHASE_DATA_OUT) && (sd->BufferLength > 0)) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); - ncr53c810_set_phase(dev, PHASE_DO); - p = scsi_device_get_callback(dev->current->tag); - if (p <= 0LL) { - period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ - dev->timer_period += (int64_t) period; - } else - dev->timer_period += p; - return 1; - } else { - ncr53c810_command_complete(dev, sd->Status); - return 0; - } -} - - -static void -ncr53c810_do_status(ncr53c810_t *dev) -{ - uint8_t status; - ncr53c810_log("Get status len=%d status=%d\n", dev->dbc, dev->status); - if (dev->dbc != 1) - ncr53c810_log("Bad Status move\n"); - dev->dbc = 1; - status = dev->status; - dev->sfbr = status; - ncr53c810_write(dev, dev->dnad, &status, 1); - ncr53c810_set_phase(dev, PHASE_MI); - dev->msg_action = 1; - ncr53c810_add_msg_byte(dev, 0); /* COMMAND COMPLETE */ -} - - -static void -ncr53c810_do_msgin(ncr53c810_t *dev) -{ - uint32_t len; - ncr53c810_log("Message in len=%d/%d\n", dev->dbc, dev->msg_len); - dev->sfbr = dev->msg[0]; - len = dev->msg_len; - if (len > dev->dbc) - len = dev->dbc; - ncr53c810_write(dev, dev->dnad, dev->msg, len); - /* Linux drivers rely on the last byte being in the SIDL. */ - dev->sidl = dev->msg[len - 1]; - dev->msg_len -= len; - if (dev->msg_len) - memmove(dev->msg, dev->msg + len, dev->msg_len); - else { - /* ??? Check if ATN (not yet implemented) is asserted and maybe - switch to PHASE_MO. */ - switch (dev->msg_action) { - case 0: - ncr53c810_set_phase(dev, PHASE_CMD); - break; - case 1: - ncr53c810_disconnect(dev); - break; - case 2: - ncr53c810_set_phase(dev, PHASE_DO); - break; - case 3: - ncr53c810_set_phase(dev, PHASE_DI); - break; - default: - abort(); - } - } -} - - -/* Read the next byte during a MSGOUT phase. */ -static uint8_t -ncr53c810_get_msgbyte(ncr53c810_t *dev) -{ - uint8_t data; - DMAPageRead(dev->dnad, &data, 1); - dev->dnad++; - dev->dbc--; - return data; -} - - -/* Skip the next n bytes during a MSGOUT phase. */ -static void -ncr53c810_skip_msgbytes(ncr53c810_t *dev, unsigned int n) -{ - dev->dnad += n; - dev->dbc -= n; -} - - -static void -ncr53c810_bad_message(ncr53c810_t *dev, uint8_t msg) -{ - ncr53c810_log("Unimplemented message 0x%02x\n", msg); - ncr53c810_set_phase(dev, PHASE_MI); - ncr53c810_add_msg_byte(dev, 7); /* MESSAGE REJECT */ - dev->msg_action = 0; -} - - -static void -ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id) -{ - uint8_t msg; - int len; - uint32_t current_tag; - scsi_device_t *sd; - - sd = &SCSIDevices[id]; - - current_tag = id; - - ncr53c810_log("MSG out len=%d\n", dev->dbc); - while (dev->dbc) { - msg = ncr53c810_get_msgbyte(dev); - dev->sfbr = msg; - - switch (msg) { - case 0x04: - ncr53c810_log("MSG: Disconnect\n"); - ncr53c810_disconnect(dev); - break; - case 0x08: - ncr53c810_log("MSG: No Operation\n"); - ncr53c810_set_phase(dev, PHASE_CMD); - break; - case 0x01: - len = ncr53c810_get_msgbyte(dev); - msg = ncr53c810_get_msgbyte(dev); - (void) len; /* avoid a warning about unused variable*/ - ncr53c810_log("Extended message 0x%x (len %d)\n", msg, len); - switch (msg) { - case 1: - ncr53c810_log("SDTR (ignored)\n"); - ncr53c810_skip_msgbytes(dev, 2); - break; - case 3: - ncr53c810_log("WDTR (ignored)\n"); - ncr53c810_skip_msgbytes(dev, 1); - break; - default: - ncr53c810_bad_message(dev, msg); - return; - } - break; - case 0x20: /* SIMPLE queue */ - id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; - ncr53c810_log("SIMPLE queue tag=0x%x\n", id & 0xff); - break; - case 0x21: /* HEAD of queue */ - ncr53c810_log("HEAD queue not implemented\n"); - id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; - break; - case 0x22: /* ORDERED queue */ - ncr53c810_log("ORDERED queue not implemented\n"); - id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; - break; - case 0x0d: - /* The ABORT TAG message clears the current I/O process only. */ - ncr53c810_log("MSG: ABORT TAG tag=0x%x\n", current_tag); - if (sd->CmdBuffer) { - free(sd->CmdBuffer); - sd->CmdBuffer = NULL; - } - ncr53c810_disconnect(dev); - break; - case 0x06: - case 0x0e: - case 0x0c: - /* The ABORT message clears all I/O processes for the selecting - initiator on the specified logical unit of the target. */ - if (msg == 0x06) - ncr53c810_log("MSG: ABORT tag=0x%x\n", current_tag); - /* The CLEAR QUEUE message clears all I/O processes for all - initiators on the specified logical unit of the target. */ - if (msg == 0x0e) - ncr53c810_log("MSG: CLEAR QUEUE tag=0x%x\n", current_tag); - /* The BUS DEVICE RESET message clears all I/O processes for all - initiators on all logical units of the target. */ - if (msg == 0x0c) - ncr53c810_log("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag); - - /* clear the current I/O process */ - if (sd->CmdBuffer) { - free(sd->CmdBuffer); - sd->CmdBuffer = NULL; - } - ncr53c810_disconnect(dev); - break; - default: - if ((msg & 0x80) == 0) { - ncr53c810_bad_message(dev, msg); - return; - } else { - dev->current_lun = msg & 7; - ncr53c810_log("Select LUN %d\n", dev->current_lun); - ncr53c810_set_phase(dev, PHASE_CMD); - } - break; - } - } -} - - -static void -ncr53c810_memcpy(ncr53c810_t *dev, uint32_t dest, uint32_t src, int count) -{ - int n; - uint8_t buf[NCR_BUF_SIZE]; - - ncr53c810_log("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); - while (count) { - n = (count > NCR_BUF_SIZE) ? NCR_BUF_SIZE : count; - ncr53c810_read(dev, src, buf, n); - ncr53c810_write(dev, dest, buf, n); - src += n; - dest += n; - count -= n; - } -} - - -static void -ncr53c810_process_script(ncr53c810_t *dev) -{ - uint32_t insn, addr, id, buf[2], dest; - int opcode, insn_processed = 0, reg, operator, cond, jmp, n, i, c; - int32_t offset; - uint8_t op0, op1, data8, mask, data[7], *pp; - - dev->sstop = 0; -again: - insn_processed++; - insn = read_dword(dev, dev->dsp); - if (!insn) { - /* If we receive an empty opcode increment the DSP by 4 bytes - instead of 8 and execute the next opcode at that location */ - dev->dsp += 4; - dev->timer_period += (10LL * TIMER_USEC); - if (insn_processed < 100) - goto again; - else - return; - } - addr = read_dword(dev, dev->dsp + 4); - ncr53c810_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr); - dev->dsps = addr; - dev->dcmd = insn >> 24; - dev->dsp += 8; - - switch (insn >> 30) { - case 0: /* Block move. */ - ncr53c810_log("00: Block move\n"); - if (dev->sist1 & NCR_SIST1_STO) { - ncr53c810_log("Delayed select timeout\n"); - dev->sstop = 1; - break; - } - ncr53c810_log("Block Move DBC=%d\n", dev->dbc); - dev->dbc = insn & 0xffffff; - ncr53c810_log("Block Move DBC=%d now\n", dev->dbc); - /* ??? Set ESA. */ - if (insn & (1 << 29)) { - /* Indirect addressing. */ - /* Should this respect SIOM? */ - addr = read_dword(dev, addr); - ncr53c810_log("Indirect Block Move address: %08X\n", addr); - } else if (insn & (1 << 28)) { - /* Table indirect addressing. */ - - /* 32-bit Table indirect */ - offset = sextract32(addr, 0, 24); - DMAPageRead(dev->dsa + offset, (uint8_t *)buf, 8); - /* byte count is stored in bits 0:23 only */ - dev->dbc = buf[0] & 0xffffff; - addr = buf[1]; - - /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of - * table, bits [31:24] */ - } - if ((dev->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { - ncr53c810_log("Wrong phase got %d expected %d\n", - dev->sstat1 & PHASE_MASK, (insn >> 24) & 7); - ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); - break; - } - dev->dnad = addr; - switch (dev->sstat1 & 0x7) { - case PHASE_DO: - ncr53c810_log("Data Out Phase\n"); - dev->waiting = 0; - ncr53c810_do_dma(dev, 1, dev->sdid); - break; - case PHASE_DI: - ncr53c810_log("Data In Phase\n"); - dev->waiting = 0; - ncr53c810_do_dma(dev, 0, dev->sdid); - break; - case PHASE_CMD: - ncr53c810_log("Command Phase\n"); - c = ncr53c810_do_command(dev, dev->sdid); - - if (!c || dev->sstop || dev->waiting || ((dev->sstat1 & 0x7) == PHASE_ST)) - break; - - dev->dfifo = dev->dbc & 0xff; - dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); - - dev->timer_period += (40LL * TIMER_USEC); - - if (dev->dcntl & NCR_DCNTL_SSM) - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SSI); - return; - case PHASE_ST: - ncr53c810_log("Status Phase\n"); - ncr53c810_do_status(dev); - break; - case PHASE_MO: - ncr53c810_log("MSG Out Phase\n"); - ncr53c810_do_msgout(dev, dev->sdid); - break; - case PHASE_MI: - ncr53c810_log("MSG In Phase\n"); - ncr53c810_do_msgin(dev); - break; - default: - ncr53c810_log("Unimplemented phase %d\n", dev->sstat1 & PHASE_MASK); - } - dev->dfifo = dev->dbc & 0xff; - dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); - break; - - case 1: /* IO or Read/Write instruction. */ - ncr53c810_log("01: I/O or Read/Write instruction\n"); - opcode = (insn >> 27) & 7; - if (opcode < 5) { - if (insn & (1 << 25)) - id = read_dword(dev, dev->dsa + sextract32(insn, 0, 24)); - else - id = insn; - id = (id >> 16) & 0xf; - if (insn & (1 << 26)) - addr = dev->dsp + sextract32(addr, 0, 24); - dev->dnad = addr; - switch (opcode) { - case 0: /* Select */ - dev->sdid = id; - if (dev->scntl1 & NCR_SCNTL1_CON) { - ncr53c810_log("Already reselected, jumping to alternative address\n"); - dev->dsp = dev->dnad; - break; - } - dev->sstat0 |= NCR_SSTAT0_WOA; - dev->scntl1 &= ~NCR_SCNTL1_IARB; - if (!scsi_device_present(id)) { - ncr53c810_bad_selection(dev, id); - break; - } - ncr53c810_log("Selected target %d%s\n", - id, insn & (1 << 24) ? " ATN" : ""); - dev->select_id = id << 8; - dev->scntl1 |= NCR_SCNTL1_CON; - if (insn & (1 << 24)) - dev->socl |= NCR_SOCL_ATN; - ncr53c810_set_phase(dev, PHASE_MO); - dev->waiting = 0; - break; - case 1: /* Disconnect */ - ncr53c810_log("Wait Disconnect\n"); - dev->scntl1 &= ~NCR_SCNTL1_CON; - break; - case 2: /* Wait Reselect */ - ncr53c810_log("Wait Reselect\n"); - if (dev->istat & NCR_ISTAT_SIGP) - dev->dsp = dev->dnad; /* If SIGP is set, this command causes an immediate jump to DNAD. */ - else { - if (!ncr53c810_irq_on_rsl(dev)) - dev->waiting = 1; - } - break; - case 3: /* Set */ - ncr53c810_log("Set%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", - insn & (1 << 6) ? " ACK" : "", - insn & (1 << 9) ? " TM" : "", - insn & (1 << 10) ? " CC" : ""); - if (insn & (1 << 3)) { - dev->socl |= NCR_SOCL_ATN; - ncr53c810_set_phase(dev, PHASE_MO); - } - if (insn & (1 << 9)) - ncr53c810_log("Target mode not implemented\n"); - if (insn & (1 << 10)) - dev->carry = 1; - break; - case 4: /* Clear */ - ncr53c810_log("Clear%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", - insn & (1 << 6) ? " ACK" : "", - insn & (1 << 9) ? " TM" : "", - insn & (1 << 10) ? " CC" : ""); - if (insn & (1 << 3)) - dev->socl &= ~NCR_SOCL_ATN; - if (insn & (1 << 10)) - dev->carry = 0; - break; - } - } else { - reg = ((insn >> 16) & 0x7f) | (insn & 0x80); - data8 = (insn >> 8) & 0xff; - opcode = (insn >> 27) & 7; - operator = (insn >> 24) & 7; - op0 = op1 = 0; - switch (opcode) { - case 5: /* From SFBR */ - op0 = dev->sfbr; - op1 = data8; - break; - case 6: /* To SFBR */ - if (operator) - op0 = ncr53c810_reg_readb(dev, reg); - op1 = data8; - break; - case 7: /* Read-modify-write */ - if (operator) - op0 = ncr53c810_reg_readb(dev, reg); - if (insn & (1 << 23)) - op1 = dev->sfbr; - else - op1 = data8; - break; - } - - switch (operator) { - case 0: /* move */ - op0 = op1; - break; - case 1: /* Shift left */ - op1 = op0 >> 7; - op0 = (op0 << 1) | dev->carry; - dev->carry = op1; - break; - case 2: /* OR */ - op0 |= op1; - break; - case 3: /* XOR */ - op0 ^= op1; - break; - case 4: /* AND */ - op0 &= op1; - break; - case 5: /* SHR */ - op1 = op0 & 1; - op0 = (op0 >> 1) | (dev->carry << 7); - dev->carry = op1; - break; - case 6: /* ADD */ - op0 += op1; - dev->carry = op0 < op1; - break; - case 7: /* ADC */ - op0 += op1 + dev->carry; - if (dev->carry) - dev->carry = op0 <= op1; - else - dev->carry = op0 < op1; - break; - } - - switch (opcode) { - case 5: /* From SFBR */ - case 7: /* Read-modify-write */ - ncr53c810_reg_writeb(dev, reg, op0); - break; - case 6: /* To SFBR */ - dev->sfbr = op0; - break; - } - } - break; - - case 2: /* Transfer Control. */ - ncr53c810_log("02: Transfer Control\n"); - if ((insn & 0x002e0000) == 0) { - ncr53c810_log("NOP\n"); - break; - } - if (dev->sist1 & NCR_SIST1_STO) { - ncr53c810_log("Delayed select timeout\n"); - dev->sstop = 1; - break; - } - cond = jmp = (insn & (1 << 19)) != 0; - if (cond == jmp && (insn & (1 << 21))) { - ncr53c810_log("Compare carry %d\n", dev->carry == jmp); - cond = dev->carry != 0; - } - if (cond == jmp && (insn & (1 << 17))) { - ncr53c810_log("Compare phase %d %c= %d\n", (dev->sstat1 & PHASE_MASK), - jmp ? '=' : '!', ((insn >> 24) & 7)); - cond = (dev->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); - } - if (cond == jmp && (insn & (1 << 18))) { - mask = (~insn >> 8) & 0xff; - ncr53c810_log("Compare data 0x%x & 0x%x %c= 0x%x\n", dev->sfbr, mask, - jmp ? '=' : '!', insn & mask); - cond = (dev->sfbr & mask) == (insn & mask); - } - if (cond == jmp) { - if (insn & (1 << 23)) { - /* Relative address. */ - addr = dev->dsp + sextract32(addr, 0, 24); - } - switch ((insn >> 27) & 7) { - case 0: /* Jump */ - ncr53c810_log("Jump to 0x%08x\n", addr); - dev->adder = addr; - dev->dsp = addr; - break; - case 1: /* Call */ - ncr53c810_log("Call 0x%08x\n", addr); - dev->temp = dev->dsp; - dev->dsp = addr; - break; - case 2: /* Return */ - ncr53c810_log("Return to 0x%08x\n", dev->temp); - dev->dsp = dev->temp; - break; - case 3: /* Interrupt */ - ncr53c810_log("Interrupt 0x%08x\n", dev->dsps); - if ((insn & (1 << 20)) != 0) { - dev->istat |= NCR_ISTAT_INTF; - ncr53c810_update_irq(dev); - } else - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SIR); - break; - default: - ncr53c810_log("Illegal transfer control\n"); - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_IID); - break; - } - } else - ncr53c810_log("Control condition failed\n"); - break; - - case 3: - ncr53c810_log("00: Memory move\n"); - if ((insn & (1 << 29)) == 0) { - /* Memory move. */ - /* ??? The docs imply the destination address is loaded into - the TEMP register. However the Linux drivers rely on - the value being presrved. */ - dest = read_dword(dev, dev->dsp); - dev->dsp += 4; - ncr53c810_memcpy(dev, dest, addr, insn & 0xffffff); - } else { - pp = data; - - if (insn & (1 << 28)) - addr = dev->dsa + sextract32(addr, 0, 24); - n = (insn & 7); - reg = (insn >> 16) & 0xff; - if (insn & (1 << 24)) { - DMAPageRead(addr, data, n); - ncr53c810_log("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n, addr, - *(unsigned *)pp); - for (i = 0; i < n; i++) - ncr53c810_reg_writeb(dev, reg + i, data[i]); - } else { - ncr53c810_log("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); - for (i = 0; i < n; i++) - data[i] = ncr53c810_reg_readb(dev, reg + i); - DMAPageWrite(addr, data, n); - } - } - break; - - default: - ncr53c810_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); - } - - dev->timer_period += (40LL * TIMER_USEC); - - ncr53c810_log("instructions processed %i\n", insn_processed); - if (insn_processed > 10000 && !dev->waiting) { - /* Some windows drivers make the device spin waiting for a memory - location to change. If we have been executed a lot of code then - assume this is the case and force an unexpected device disconnect. - This is apparently sufficient to beat the drivers into submission. - */ - ncr53c810_log("Some windows drivers make the device spin...\n"); - if (!(dev->sien0 & NCR_SIST0_UDC)) - ncr53c810_log("inf. loop with UDC masked\n"); - ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_UDC, 0); - ncr53c810_disconnect(dev); - } else if (!dev->sstop && !dev->waiting) { - if (dev->dcntl & NCR_DCNTL_SSM) { - ncr53c810_log("NCR 810: SCRIPTS: Single-step mode\n"); - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SSI); - } else { - ncr53c810_log("NCR 810: SCRIPTS: Normal mode\n"); - if (insn_processed < 100) - goto again; - } - } else { - if (dev->sstop) - ncr53c810_log("NCR 810: SCRIPTS: Stopped\n"); - if (dev->waiting) - ncr53c810_log("NCR 810: SCRIPTS: Waiting\n"); - } - - ncr53c810_log("SCRIPTS execution stopped\n"); -} - - -static void -ncr53c810_execute_script(ncr53c810_t *dev) -{ - dev->sstop = 0; - dev->timer_period = 40LL * TIMER_USEC; - dev->timer_enabled = 1; -} - - -static void -ncr53c810_callback(void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *) p; - - dev->timer_period = 0; - if (!dev->sstop) { - if (dev->waiting) - dev->timer_period = 40LL * TIMER_USEC; - else - ncr53c810_process_script(dev); - } - - if (dev->sstop) { - dev->timer_enabled = 0; - dev->timer_period = 0; - } else - dev->timer_enabled = 1; -} - - -static void -ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) -{ - uint8_t tmp = 0; - -#define CASE_SET_REG24(name, addr) \ - case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ - case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ - case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; - -#define CASE_SET_REG32(name, addr) \ - case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ - case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ - case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; \ - case addr + 3: dev->name &= 0x00ffffff; dev->name |= val << 24; break; - -#ifdef DEBUG_NCR_REG - ncr53c810_log("Write reg %02x = %02x\n", offset, val); -#endif - - dev->regop = 1; - - switch (offset) { - case 0x00: /* SCNTL0 */ - dev->scntl0 = val; - if (val & NCR_SCNTL0_START) { - /* Looks like this (turn on bit 4 of SSTAT0 to mark arbitration in progress) - is enough to make BIOS v4.x happy. */ - ncr53c810_log("NCR 810: Selecting SCSI ID %i\n", dev->sdid); - dev->select_id = dev->sdid; - dev->sstat0 |= 0x10; - } - break; - case 0x01: /* SCNTL1 */ - dev->scntl1 = val & ~NCR_SCNTL1_SST; - if (val & NCR_SCNTL1_IARB) { - dev->select_id = dev->sdid; - ncr53c810_log("Arbitration lost\n"); - dev->sstat0 |= 0x08; - dev->waiting = 0; - } - if (val & NCR_SCNTL1_RST) { - if (!(dev->sstat0 & NCR_SSTAT0_RST)) { - dev->sstat0 |= NCR_SSTAT0_RST; - ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_RST, 0); - } - } else - dev->sstat0 &= ~NCR_SSTAT0_RST; - break; - case 0x02: /* SCNTL2 */ - val &= ~(NCR_SCNTL2_WSR | NCR_SCNTL2_WSS); - dev->scntl2 = val; - break; - case 0x03: /* SCNTL3 */ - dev->scntl3 = val; - break; - case 0x04: /* SCID */ - dev->scid = val; - break; - case 0x05: /* SXFER */ - dev->sxfer = val; - break; - case 0x06: /* SDID */ - if ((dev->ssid & 0x80) && (val & 0xf) != (dev->ssid & 0xf)) - ncr53c810_log("Destination ID does not match SSID\n"); - dev->sdid = val & 0xf; - break; - case 0x07: /* GPREG0 */ - ncr53c810_log("NCR 810: GPREG0 write %02X\n", val); - dev->gpreg0 = val & 0x03; - break; - case 0x08: /* SFBR */ - /* The CPU is not allowed to write to this register. However the - SCRIPTS register move instructions are. */ - dev->sfbr = val; - break; - case 0x09: /* SOCL */ - ncr53c810_log("NCR 810: SOCL write %02X\n", val); - dev->socl = val; - break; - case 0x0a: case 0x0b: - /* Openserver writes to these readonly registers on startup */ - return; - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - /* Linux writes to these readonly registers on startup. */ - return; - CASE_SET_REG32(dsa, 0x10) - case 0x14: /* ISTAT */ - ncr53c810_log("ISTAT write: %02X\n", val); - tmp = dev->istat; - dev->istat = (dev->istat & 0x0f) | (val & 0xf0); - if ((val & NCR_ISTAT_ABRT) && !(val & NCR_ISTAT_SRST)) - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_ABRT); - if (val & NCR_ISTAT_INTF) { - dev->istat &= ~NCR_ISTAT_INTF; - ncr53c810_update_irq(dev); - } - - if ((dev->waiting == 1) && (val & NCR_ISTAT_SIGP)) { - ncr53c810_log("Woken by SIGP\n"); - dev->waiting = 0; - dev->dsp = dev->dnad; - /* ncr53c810_execute_script(dev); */ - } - if ((val & NCR_ISTAT_SRST) && !(tmp & NCR_ISTAT_SRST)) { - ncr53c810_soft_reset(dev); - ncr53c810_update_irq(dev); - dev->istat = 0; - } - break; - case 0x16: /* MBOX0 */ - dev->mbox0 = val; - break; - case 0x17: /* MBOX1 */ - dev->mbox1 = val; - break; - case 0x18: /* CTEST0 */ - /* nothing to do */ - break; - case 0x19: /* CTEST1 */ - /* nothing to do */ - break; - case 0x1a: /* CTEST2 */ - dev->ctest2 = val & NCR_CTEST2_PCICIE; - break; - case 0x1b: /* CTEST3 */ - dev->ctest3 = val & 0x0f; - break; - CASE_SET_REG32(temp, 0x1c) - case 0x21: /* CTEST4 */ - if (val & 7) - ncr53c810_log("Unimplemented CTEST4-FBL 0x%x\n", val); - dev->ctest4 = val; - break; - case 0x22: /* CTEST5 */ - if (val & (NCR_CTEST5_ADCK | NCR_CTEST5_BBCK)) - ncr53c810_log("CTEST5 DMA increment not implemented\n"); - dev->ctest5 = val; - break; - CASE_SET_REG24(dbc, 0x24) - CASE_SET_REG32(dnad, 0x28) - case 0x2c: /* DSP[0:7] */ - dev->dsp &= 0xffffff00; - dev->dsp |= val; - break; - case 0x2d: /* DSP[8:15] */ - dev->dsp &= 0xffff00ff; - dev->dsp |= val << 8; - break; - case 0x2e: /* DSP[16:23] */ - dev->dsp &= 0xff00ffff; - dev->dsp |= val << 16; - break; - case 0x2f: /* DSP[24:31] */ - dev->dsp &= 0x00ffffff; - dev->dsp |= val << 24; - if (!(dev->dmode & NCR_DMODE_MAN) && dev->sstop) - ncr53c810_execute_script(dev); - break; - CASE_SET_REG32(dsps, 0x30) - CASE_SET_REG32(scratcha, 0x34) - case 0x38: /* DMODE */ - dev->dmode = val; - break; - case 0x39: /* DIEN */ - ncr53c810_log("DIEN write: %02X\n", val); - dev->dien = val; - ncr53c810_update_irq(dev); - break; - case 0x3a: /* SBR */ - dev->sbr = val; - break; - case 0x3b: /* DCNTL */ - dev->dcntl = val & ~(NCR_DCNTL_PFF | NCR_DCNTL_STD); - if ((val & NCR_DCNTL_STD) && dev->sstop) - ncr53c810_execute_script(dev); - break; - case 0x40: /* SIEN0 */ - dev->sien0 = val; - ncr53c810_update_irq(dev); - break; - case 0x41: /* SIEN1 */ - dev->sien1 = val; - ncr53c810_update_irq(dev); - break; - case 0x47: /* GPCNTL0 */ - break; - case 0x48: /* STIME0 */ - dev->stime0 = val; - break; - case 0x49: /* STIME1 */ - if (val & 0xf) { - ncr53c810_log("General purpose timer not implemented\n"); - /* ??? Raising the interrupt immediately seems to be sufficient - to keep the FreeBSD driver happy. */ - ncr53c810_script_scsi_interrupt(dev, 0, NCR_SIST1_GEN); - } - break; - case 0x4a: /* RESPID */ - dev->respid = val; - break; - case 0x4d: /* STEST1 */ - dev->stest1 = val; - break; - case 0x4e: /* STEST2 */ - if (val & 1) - ncr53c810_log("Low level mode not implemented\n"); - dev->stest2 = val; - break; - case 0x4f: /* STEST3 */ - if (val & 0x41) - ncr53c810_log("SCSI FIFO test mode not implemented\n"); - dev->stest3 = val; - break; - case 0x54: - break; - CASE_SET_REG32(scratchb, 0x5c) - default: - ncr53c810_log("Unhandled writeb 0x%x = 0x%x\n", offset, val); - } -#undef CASE_SET_REG24 -#undef CASE_SET_REG32 -} - - -static uint8_t -ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset) -{ - uint8_t tmp; -#define CASE_GET_REG24(name, addr) \ - case addr: return dev->name & 0xff; \ - case addr + 1: return (dev->name >> 8) & 0xff; \ - case addr + 2: return (dev->name >> 16) & 0xff; - -#define CASE_GET_REG32(name, addr) \ - case addr: return dev->name & 0xff; \ - case addr + 1: return (dev->name >> 8) & 0xff; \ - case addr + 2: return (dev->name >> 16) & 0xff; \ - case addr + 3: return (dev->name >> 24) & 0xff; - - dev->regop = 1; - - switch (offset) { - case 0x00: /* SCNTL0 */ - ncr53c810_log("NCR 810: Read SCNTL0 %02X\n", dev->scntl0); - return dev->scntl0; - case 0x01: /* SCNTL1 */ - ncr53c810_log("NCR 810: Read SCNTL1 %02X\n", dev->scntl1); - return dev->scntl1; - case 0x02: /* SCNTL2 */ - ncr53c810_log("NCR 810: Read SCNTL2 %02X\n", dev->scntl2); - return dev->scntl2; - case 0x03: /* SCNTL3 */ - ncr53c810_log("NCR 810: Read SCNTL3 %02X\n", dev->scntl3); - return dev->scntl3; - case 0x04: /* SCID */ - ncr53c810_log("NCR 810: Read SCID %02X\n", dev->scid); - return dev->scid; - case 0x05: /* SXFER */ - ncr53c810_log("NCR 810: Read SXFER %02X\n", dev->sxfer); - return dev->sxfer; - case 0x06: /* SDID */ - ncr53c810_log("NCR 810: Read SDID %02X\n", dev->sdid); - return dev->sdid; - case 0x07: /* GPREG0 */ - ncr53c810_log("NCR 810: Read GPREG0 %02X\n", dev->gpreg0 & 3); - return dev->gpreg0 & 3; - case 0x08: /* Revision ID */ - ncr53c810_log("NCR 810: Read REVID 00\n"); - return 0x00; - case 0xa: /* SSID */ - ncr53c810_log("NCR 810: Read SSID %02X\n", dev->ssid); - return dev->ssid; - case 0xb: /* SBCL */ - /* Bit 7 = REQ (SREQ/ status) - Bit 6 = ACK (SACK/ status) - Bit 5 = BSY (SBSY/ status) - Bit 4 = SEL (SSEL/ status) - Bit 3 = ATN (SATN/ status) - Bit 2 = MSG (SMSG/ status) - Bit 1 = C/D (SC_D/ status) - Bit 0 = I/O (SI_O/ status) */ - tmp = (dev->sstat1 & 7); - ncr53c810_log("NCR 810: Read SBCL %02X\n", tmp); - return tmp; /* For now, return the MSG, C/D, and I/O bits from SSTAT1. */ - case 0xc: /* DSTAT */ - tmp = dev->dstat | NCR_DSTAT_DFE; - if ((dev->istat & NCR_ISTAT_INTF) == 0) - dev->dstat = 0; - ncr53c810_update_irq(dev); - ncr53c810_log("NCR 810: Read DSTAT %02X\n", tmp); - return tmp; - case 0x0d: /* SSTAT0 */ - ncr53c810_log("NCR 810: Read SSTAT0 %02X\n", dev->sstat0); - return dev->sstat0; - case 0x0e: /* SSTAT1 */ - ncr53c810_log("NCR 810: Read SSTAT1 %02X\n", dev->sstat1); - return dev->sstat1; - case 0x0f: /* SSTAT2 */ - ncr53c810_log("NCR 810: Read SSTAT2 %02X\n", dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2); - return dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2; - CASE_GET_REG32(dsa, 0x10) - case 0x14: /* ISTAT */ - ncr53c810_log("NCR 810: Read ISTAT %02X\n", dev->istat); - tmp = dev->istat; - return tmp; - case 0x16: /* MBOX0 */ - ncr53c810_log("NCR 810: Read MBOX0 %02X\n", dev->mbox0); - return dev->mbox0; - case 0x17: /* MBOX1 */ - ncr53c810_log("NCR 810: Read MBOX1 %02X\n", dev->mbox1); - return dev->mbox1; - case 0x18: /* CTEST0 */ - ncr53c810_log("NCR 810: Read CTEST0 FF\n"); - return 0xff; - case 0x19: /* CTEST1 */ - ncr53c810_log("NCR 810: Read CTEST1 F0\n"); - return 0xf0; /* dma fifo empty */ - case 0x1a: /* CTEST2 */ - tmp = dev->ctest2 | NCR_CTEST2_DACK | NCR_CTEST2_CM; - if (dev->istat & NCR_ISTAT_SIGP) { - dev->istat &= ~NCR_ISTAT_SIGP; - tmp |= NCR_CTEST2_SIGP; - } - ncr53c810_log("NCR 810: Read CTEST2 %02X\n", tmp); - return tmp; - case 0x1b: /* CTEST3 */ - ncr53c810_log("NCR 810: Read CTEST3 %02X\n", - (dev->ctest3 & (0x08 | 0x02 | 0x01)) | dev->chip_rev); - return (dev->ctest3 & (0x08 | 0x02 | 0x01)) | dev->chip_rev; - CASE_GET_REG32(temp, 0x1c) - case 0x20: /* DFIFO */ - ncr53c810_log("NCR 810: Read DFIFO 00\n"); - return 0; - case 0x21: /* CTEST4 */ - ncr53c810_log("NCR 810: Read CTEST4 %02X\n", dev->ctest4); - return dev->ctest4; - case 0x22: /* CTEST5 */ - ncr53c810_log("NCR 810: Read CTEST5 %02X\n", dev->ctest5); - return dev->ctest5; - case 0x23: /* CTEST6 */ - ncr53c810_log("NCR 810: Read CTEST6 00\n"); - return 0; - CASE_GET_REG24(dbc, 0x24) - case 0x27: /* DCMD */ - ncr53c810_log("NCR 810: Read DCMD %02X\n", dev->dcmd); - return dev->dcmd; - CASE_GET_REG32(dnad, 0x28) - CASE_GET_REG32(dsp, 0x2c) - CASE_GET_REG32(dsps, 0x30) - CASE_GET_REG32(scratcha, 0x34) - case 0x38: /* DMODE */ - ncr53c810_log("NCR 810: Read DMODE %02X\n", dev->dmode); - return dev->dmode; - case 0x39: /* DIEN */ - ncr53c810_log("NCR 810: Read DIEN %02X\n", dev->dien); - return dev->dien; - case 0x3a: /* SBR */ - ncr53c810_log("NCR 810: Read SBR %02X\n", dev->sbr); - return dev->sbr; - case 0x3b: /* DCNTL */ - ncr53c810_log("NCR 810: Read DCNTL %02X\n", dev->dcntl); - return dev->dcntl; - CASE_GET_REG32(adder, 0x3c) /* ADDER Output (Debug of relative jump address) */ - case 0x40: /* SIEN0 */ - ncr53c810_log("NCR 810: Read SIEN0 %02X\n", dev->sien0); - return dev->sien0; - case 0x41: /* SIEN1 */ - ncr53c810_log("NCR 810: Read SIEN1 %02X\n", dev->sien1); - return dev->sien1; - case 0x42: /* SIST0 */ - tmp = dev->sist0; - dev->sist0 = 0; - ncr53c810_update_irq(dev); - ncr53c810_log("NCR 810: Read SIST0 %02X\n", tmp); - return tmp; - case 0x43: /* SIST1 */ - tmp = dev->sist1; - dev->sist1 = 0; - ncr53c810_update_irq(dev); - ncr53c810_log("NCR 810: Read SIST1 %02X\n", tmp); - return tmp; - case 0x46: /* MACNTL */ - ncr53c810_log("NCR 810: Read MACNTL 4F\n"); - return 0x4f; - case 0x47: /* GPCNTL0 */ - ncr53c810_log("NCR 810: Read GPCNTL0 0F\n"); - return 0x0f; - case 0x48: /* STIME0 */ - ncr53c810_log("NCR 810: Read STIME0 %02X\n", dev->stime0); - return dev->stime0; - case 0x4a: /* RESPID */ - ncr53c810_log("NCR 810: Read RESPID %02X\n", dev->respid); - return dev->respid; - case 0x4c: /* STEST0 */ - ncr53c810_log("NCR 810: Read STEST0 %02X\n", dev->stest1); - return 0x00; - case 0x4d: /* STEST1 */ - ncr53c810_log("NCR 810: Read STEST1 %02X\n", dev->stest1); - return dev->stest1; - case 0x4e: /* STEST2 */ - ncr53c810_log("NCR 810: Read STEST2 %02X\n", dev->stest2); - return dev->stest2; - case 0x4f: /* STEST3 */ - ncr53c810_log("NCR 810: Read STEST3 %02X\n", dev->stest3); - return dev->stest3; - case 0x50: /* SIDL */ - /* This is needed by the linux drivers. We currently only update it - during the MSG IN phase. */ - ncr53c810_log("NCR 810: Read SIDL %02X\n", dev->sidl); - return dev->sidl; - case 0x52: /* STEST4 */ - ncr53c810_log("NCR 810: Read STEST4 E0\n"); - return 0xe0; - case 0x58: /* SBDL */ - /* Some drivers peek at the data bus during the MSG IN phase. */ - if ((dev->sstat1 & PHASE_MASK) == PHASE_MI) { - ncr53c810_log("NCR 810: Read SBDL %02X\n", dev->msg[0]); - return dev->msg[0]; - } - ncr53c810_log("NCR 810: Read SBDL 00\n"); - return 0; - case 0x59: /* SBDL high */ - ncr53c810_log("NCR 810: Read SBDLH 00\n"); - return 0; - CASE_GET_REG32(scratchb, 0x5c) - } - ncr53c810_log("readb 0x%x\n", offset); - return 0; - -#undef CASE_GET_REG24 -#undef CASE_GET_REG32 -} - - -static uint8_t -ncr53c810_io_readb(uint16_t addr, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - return ncr53c810_reg_readb(dev, addr & 0xff); -} - - -static uint16_t -ncr53c810_io_readw(uint16_t addr, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - uint16_t val; - - addr &= 0xff; - val = ncr53c810_reg_readb(dev, addr); - val |= ncr53c810_reg_readb(dev, addr + 1) << 8; - return val; -} - - -static uint32_t -ncr53c810_io_readl(uint16_t addr, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - uint32_t val; - - addr &= 0xff; - val = ncr53c810_reg_readb(dev, addr); - val |= ncr53c810_reg_readb(dev, addr + 1) << 8; - val |= ncr53c810_reg_readb(dev, addr + 2) << 16; - val |= ncr53c810_reg_readb(dev, addr + 3) << 24; - return val; -} - - -static void -ncr53c810_io_writeb(uint16_t addr, uint8_t val, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - ncr53c810_reg_writeb(dev, addr & 0xff, val); -} - - -static void -ncr53c810_io_writew(uint16_t addr, uint16_t val, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - addr &= 0xff; - ncr53c810_reg_writeb(dev, addr, val & 0xff); - ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); -} - - -static void -ncr53c810_io_writel(uint16_t addr, uint32_t val, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - addr &= 0xff; - ncr53c810_reg_writeb(dev, addr, val & 0xff); - ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); - ncr53c810_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); - ncr53c810_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); -} - - -static void -ncr53c810_mmio_writeb(uint32_t addr, uint8_t val, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - - ncr53c810_reg_writeb(dev, addr & 0xff, val); -} - - -static void -ncr53c810_mmio_writew(uint32_t addr, uint16_t val, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - - addr &= 0xff; - ncr53c810_reg_writeb(dev, addr, val & 0xff); - ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); -} - - -static void -ncr53c810_mmio_writel(uint32_t addr, uint32_t val, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - - addr &= 0xff; - ncr53c810_reg_writeb(dev, addr, val & 0xff); - ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); - ncr53c810_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); - ncr53c810_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); -} - - -static uint8_t -ncr53c810_mmio_readb(uint32_t addr, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - - return ncr53c810_reg_readb(dev, addr & 0xff); -} - - -static uint16_t -ncr53c810_mmio_readw(uint32_t addr, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - uint16_t val; - - addr &= 0xff; - val = ncr53c810_reg_readb(dev, addr); - val |= ncr53c810_reg_readb(dev, addr + 1) << 8; - return val; -} - - -static uint32_t -ncr53c810_mmio_readl(uint32_t addr, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - uint32_t val; - - addr &= 0xff; - val = ncr53c810_reg_readb(dev, addr); - val |= ncr53c810_reg_readb(dev, addr + 1) << 8; - val |= ncr53c810_reg_readb(dev, addr + 2) << 16; - val |= ncr53c810_reg_readb(dev, addr + 3) << 24; - return val; -} - - -static void -ncr53c810_io_set(ncr53c810_t *dev, uint32_t base, uint16_t len) -{ - ncr53c810_log("NCR53c810: [PCI] Setting I/O handler at %04X\n", base); - io_sethandler(base, len, - ncr53c810_io_readb, ncr53c810_io_readw, ncr53c810_io_readl, - ncr53c810_io_writeb, ncr53c810_io_writew, ncr53c810_io_writel, dev); -} - - -static void -ncr53c810_io_remove(ncr53c810_t *dev, uint32_t base, uint16_t len) -{ - ncr53c810_log("NCR53c810: Removing I/O handler at %04X\n", base); - io_removehandler(base, len, - ncr53c810_io_readb, ncr53c810_io_readw, ncr53c810_io_readl, - ncr53c810_io_writeb, ncr53c810_io_writew, ncr53c810_io_writel, dev); -} - - -static void -ncr53c810_mem_init(ncr53c810_t *dev, uint32_t addr) -{ - mem_mapping_add(&dev->mmio_mapping, addr, 0x100, - ncr53c810_mmio_readb, ncr53c810_mmio_readw, ncr53c810_mmio_readl, - ncr53c810_mmio_writeb, ncr53c810_mmio_writew, ncr53c810_mmio_writel, - NULL, MEM_MAPPING_EXTERNAL, dev); -} - - -static void -ncr53c810_mem_set_addr(ncr53c810_t *dev, uint32_t base) -{ - mem_mapping_set_addr(&dev->mmio_mapping, base, 0x100); -} - - -static void -ncr53c810_mem_disable(ncr53c810_t *dev) -{ - mem_mapping_disable(&dev->mmio_mapping); -} - - -uint8_t ncr53c810_pci_regs[256]; -bar_t ncr53c810_pci_bar[2]; - - -static uint8_t -ncr53c810_pci_read(int func, int addr, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - - ncr53c810_log("NCR53c810: Reading register %02X\n", addr & 0xff); - - if ((addr >= 0x80) && (addr <= 0xDF)) - return ncr53c810_reg_readb(dev, addr & 0x7F); - - switch (addr) { - case 0x00: - return 0x00; - case 0x01: - return 0x10; - case 0x02: - return 0x01; - case 0x03: - return 0x00; - case 0x04: - return ncr53c810_pci_regs[0x04] & 0x57; /*Respond to IO and memory accesses*/ - case 0x05: - return ncr53c810_pci_regs[0x05] & 0x01; - case 0x07: - return 2; - case 0x08: - return 0x10; /*Revision ID*/ - case 0x09: - return 0; /*Programming interface*/ - case 0x0A: - return 0; /*devubclass*/ - case 0x0B: - return 1; /*Class code*/ - case 0x0C: - case 0x0D: - return ncr53c810_pci_regs[addr]; - case 0x0E: - return 0; /*Header type */ - case 0x10: - return 1; /*I/O space*/ - case 0x11: - return ncr53c810_pci_bar[0].addr_regs[1]; - case 0x12: - return ncr53c810_pci_bar[0].addr_regs[2]; - case 0x13: - return ncr53c810_pci_bar[0].addr_regs[3]; - case 0x14: - return 0; /*Memory space*/ - case 0x15: - return ncr53c810_pci_bar[1].addr_regs[1]; - case 0x16: - return ncr53c810_pci_bar[1].addr_regs[2]; - case 0x17: - return ncr53c810_pci_bar[1].addr_regs[3]; - case 0x2C: - return 0x00; - case 0x2D: - return 0x10; - case 0x2E: - return 0x01; - case 0x2F: - return 0x00; - case 0x3C: - return dev->irq; - case 0x3D: - return PCI_INTA; - case 0x3E: - return 0x11; - case 0x3F: - return 0x40; - } - - return(0); -} - - -static void -ncr53c810_pci_write(int func, int addr, uint8_t val, void *p) -{ - ncr53c810_t *dev = (ncr53c810_t *)p; - uint8_t valxor; - - ncr53c810_log("NCR53c810: Write value %02X to register %02X\n", val, addr & 0xff); - - if ((addr >= 0x80) && (addr <= 0xDF)) { - ncr53c810_reg_writeb(dev, addr & 0x7F, val); - return; - } - - switch (addr) - { - case 0x04: - valxor = (val & 0x57) ^ ncr53c810_pci_regs[addr]; - if (valxor & PCI_COMMAND_IO) { - ncr53c810_io_remove(dev, dev->PCIBase, 0x0100); - if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) { - ncr53c810_io_set(dev, dev->PCIBase, 0x0100); - } - } - if (valxor & PCI_COMMAND_MEM) { - ncr53c810_mem_disable(dev); - if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) { - ncr53c810_mem_set_addr(dev, dev->MMIOBase); - } - } - ncr53c810_pci_regs[addr] = val & 0x57; - break; - - case 0x05: - ncr53c810_pci_regs[addr] = val & 0x01; - break; - - case 0x0C: - case 0x0D: - ncr53c810_pci_regs[addr] = val; - break; - - case 0x10: case 0x11: case 0x12: case 0x13: - /* I/O Base set. */ - /* First, remove the old I/O. */ - ncr53c810_io_remove(dev, dev->PCIBase, 0x0100); - /* Then let's set the PCI regs. */ - ncr53c810_pci_bar[0].addr_regs[addr & 3] = val; - /* Then let's calculate the new I/O base. */ - ncr53c810_pci_bar[0].addr &= 0xff00; - dev->PCIBase = ncr53c810_pci_bar[0].addr; - /* Log the new base. */ - ncr53c810_log("NCR53c810: New I/O base is %04X\n" , dev->PCIBase); - /* We're done, so get out of the here. */ - if (ncr53c810_pci_regs[4] & PCI_COMMAND_IO) { - if (dev->PCIBase != 0) { - ncr53c810_io_set(dev, dev->PCIBase, 0x0100); - } - } - return; - - case 0x15: case 0x16: case 0x17: - /* MMIO Base set. */ - /* First, remove the old I/O. */ - ncr53c810_mem_disable(dev); - /* Then let's set the PCI regs. */ - ncr53c810_pci_bar[1].addr_regs[addr & 3] = val; - /* Then let's calculate the new I/O base. */ - dev->MMIOBase = ncr53c810_pci_bar[1].addr & 0xffffff00; - /* Log the new base. */ - ncr53c810_log("NCR53c810: New MMIO base is %08X\n" , dev->MMIOBase); - /* We're done, so get out of the here. */ - if (ncr53c810_pci_regs[4] & PCI_COMMAND_MEM) { - if (dev->MMIOBase != 0) { - ncr53c810_mem_set_addr(dev, dev->MMIOBase); - } - } - return; - - case 0x3C: - ncr53c810_pci_regs[addr] = val; - dev->irq = val; - return; - } -} - - -static void * -ncr53c810_init(const device_t *info) -{ - ncr53c810_t *dev; - - dev = malloc(sizeof(ncr53c810_t)); - memset(dev, 0x00, sizeof(ncr53c810_t)); - - dev->chip_rev = 0; - dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c810_pci_read, ncr53c810_pci_write, dev); - - ncr53c810_pci_bar[0].addr_regs[0] = 1; - ncr53c810_pci_bar[1].addr_regs[0] = 0; - ncr53c810_pci_regs[0x04] = 3; - - ncr53c810_mem_init(dev, 0x0fffff00); - ncr53c810_mem_disable(dev); - - ncr53c810_soft_reset(dev); - - timer_add(ncr53c810_callback, &dev->timer_period, &dev->timer_enabled, dev); - - dev->has_bios = device_get_config_int("bios"); - - /* Enable our BIOS space in PCI, if needed. */ - if (dev->has_bios) - rom_init(&dev->bios, NCR53C810_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - return(dev); -} - - -static void -ncr53c810_close(void *priv) -{ - ncr53c810_t *dev = (ncr53c810_t *)priv; - - if (dev) { - free(dev); - dev = NULL; - } -} - - -static const device_config_t ncr53c810_pci_config[] = { - { - "bios", "Enable BIOS", CONFIG_BINARY, "", 0 - }, - { - "", "", -1 - } -}; - - -const device_t ncr53c810_pci_device = -{ - "NCR 53c810 (SCSI)", - DEVICE_PCI, - 0, - ncr53c810_init, ncr53c810_close, NULL, - NULL, NULL, NULL, - ncr53c810_pci_config -}; diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c new file mode 100644 index 000000000..56af023a1 --- /dev/null +++ b/src/scsi/scsi_ncr53c8xx.c @@ -0,0 +1,2726 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the NCR 53C810 and 53C875 SCSI Host + * Adapters made by NCR and later Symbios and LSI. These + * controllers were designed for the PCI bus. + * + * To do: Identify the type of serial EEPROM used and its + * interface. + * + * Version: @(#)scsi_ncr53c8xx.c 1.0.18 2019/11/19 + * + * Authors: Paul Brook (QEMU) + * Artyom Tarasenko (QEMU) + * TheCollector1995, + * Miran Grca, + * + * Copyright 2006-2018 Paul Brook. + * Copyright 2009-2018 Artyom Tarasenko. + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include "../86box.h" +#include "../io.h" +#include "../timer.h" +#include "../dma.h" +#include "../pic.h" +#include "../mem.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../nvr.h" +#include "../plat.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_ncr53c8xx.h" + +#define NCR53C8XX_ROM L"roms/scsi/ncr53c8xx/NCR307.BIN" + +#define CHIP_810 0x01 +#define CHIP_825 0x03 +#define CHIP_875 0x0f + +#define NCR_SCNTL0_TRG 0x01 +#define NCR_SCNTL0_AAP 0x02 +#define NCR_SCNTL0_EPC 0x08 +#define NCR_SCNTL0_WATN 0x10 +#define NCR_SCNTL0_START 0x20 + +#define NCR_SCNTL1_SST 0x01 +#define NCR_SCNTL1_IARB 0x02 +#define NCR_SCNTL1_AESP 0x04 +#define NCR_SCNTL1_RST 0x08 +#define NCR_SCNTL1_CON 0x10 +#define NCR_SCNTL1_DHP 0x20 +#define NCR_SCNTL1_ADB 0x40 +#define NCR_SCNTL1_EXC 0x80 + +#define NCR_SCNTL2_WSR 0x01 +#define NCR_SCNTL2_VUE0 0x02 +#define NCR_SCNTL2_VUE1 0x04 +#define NCR_SCNTL2_WSS 0x08 +#define NCR_SCNTL2_SLPHBEN 0x10 +#define NCR_SCNTL2_SLPMD 0x20 +#define NCR_SCNTL2_CHM 0x40 +#define NCR_SCNTL2_SDU 0x80 + +#define NCR_ISTAT_DIP 0x01 +#define NCR_ISTAT_SIP 0x02 +#define NCR_ISTAT_INTF 0x04 +#define NCR_ISTAT_CON 0x08 +#define NCR_ISTAT_SEM 0x10 +#define NCR_ISTAT_SIGP 0x20 +#define NCR_ISTAT_SRST 0x40 +#define NCR_ISTAT_ABRT 0x80 + +#define NCR_SSTAT0_SDP0 0x01 +#define NCR_SSTAT0_RST 0x02 +#define NCR_SSTAT0_WOA 0x04 +#define NCR_SSTAT0_LOA 0x08 +#define NCR_SSTAT0_AIP 0x10 +#define NCR_SSTAT0_OLF 0x20 +#define NCR_SSTAT0_ORF 0x40 +#define NCR_SSTAT0_ILF 0x80 + +#define NCR_SIST0_PAR 0x01 +#define NCR_SIST0_RST 0x02 +#define NCR_SIST0_UDC 0x04 +#define NCR_SIST0_SGE 0x08 +#define NCR_SIST0_RSL 0x10 +#define NCR_SIST0_SEL 0x20 +#define NCR_SIST0_CMP 0x40 +#define NCR_SIST0_MA 0x80 + +#define NCR_SIST1_HTH 0x01 +#define NCR_SIST1_GEN 0x02 +#define NCR_SIST1_STO 0x04 +#define NCR_SIST1_SBMC 0x10 + +#define NCR_SOCL_IO 0x01 +#define NCR_SOCL_CD 0x02 +#define NCR_SOCL_MSG 0x04 +#define NCR_SOCL_ATN 0x08 +#define NCR_SOCL_SEL 0x10 +#define NCR_SOCL_BSY 0x20 +#define NCR_SOCL_ACK 0x40 +#define NCR_SOCL_REQ 0x80 + +#define NCR_DSTAT_IID 0x01 +#define NCR_DSTAT_SIR 0x04 +#define NCR_DSTAT_SSI 0x08 +#define NCR_DSTAT_ABRT 0x10 +#define NCR_DSTAT_BF 0x20 +#define NCR_DSTAT_MDPE 0x40 +#define NCR_DSTAT_DFE 0x80 + +#define NCR_DCNTL_COM 0x01 +#define NCR_DCNTL_IRQD 0x02 +#define NCR_DCNTL_STD 0x04 +#define NCR_DCNTL_IRQM 0x08 +#define NCR_DCNTL_SSM 0x10 +#define NCR_DCNTL_PFEN 0x20 +#define NCR_DCNTL_PFF 0x40 +#define NCR_DCNTL_CLSE 0x80 + +#define NCR_DMODE_MAN 0x01 +#define NCR_DMODE_BOF 0x02 +#define NCR_DMODE_ERMP 0x04 +#define NCR_DMODE_ERL 0x08 +#define NCR_DMODE_DIOM 0x10 +#define NCR_DMODE_SIOM 0x20 + +#define NCR_CTEST2_DACK 0x01 +#define NCR_CTEST2_DREQ 0x02 +#define NCR_CTEST2_TEOP 0x04 +#define NCR_CTEST2_PCICIE 0x08 +#define NCR_CTEST2_CM 0x10 +#define NCR_CTEST2_CIO 0x20 +#define NCR_CTEST2_SIGP 0x40 +#define NCR_CTEST2_DDIR 0x80 + +#define NCR_CTEST5_BL2 0x04 +#define NCR_CTEST5_DDIR 0x08 +#define NCR_CTEST5_MASR 0x10 +#define NCR_CTEST5_DFSN 0x20 +#define NCR_CTEST5_BBCK 0x40 +#define NCR_CTEST5_ADCK 0x80 + +/* Enable Response to Reselection */ +#define NCR_SCID_RRE 0x60 + +#define PHASE_DO 0 +#define PHASE_DI 1 +#define PHASE_CMD 2 +#define PHASE_ST 3 +#define PHASE_MO 6 +#define PHASE_MI 7 +#define PHASE_MASK 7 + +/* Maximum length of MSG IN data. */ +#define NCR_MAX_MSGIN_LEN 8 + +/* Flag set if this is a tagged command. */ +#define NCR_TAG_VALID (1 << 16) + +#define NCR_BUF_SIZE 4096 + +typedef struct ncr53c8xx_request { + uint32_t tag; + uint32_t dma_len; + uint8_t *dma_buf; + uint32_t pending; + int out; +} ncr53c8xx_request; + +typedef enum +{ + SCSI_STATE_SEND_COMMAND, + SCSI_STATE_READ_DATA, + SCSI_STATE_WRITE_DATA, + SCSI_STATE_READ_STATUS, + SCSI_STATE_READ_MESSAGE, + SCSI_STATE_WRITE_MESSAGE +} scsi_state_t; + +typedef struct { + wchar_t *nvr_path; + uint8_t pci_slot; + uint8_t chip; + int has_bios; + int BIOSBase; + rom_t bios; + int PCIBase; + int MMIOBase; + mem_mapping_t mmio_mapping; + int RAMBase; + mem_mapping_t ram_mapping; + + int carry; /* ??? Should this be an a visible register somewhere? */ + int status; + /* Action to take at the end of a MSG IN phase. + 0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN. */ + int msg_action; + int msg_len; + uint8_t msg[NCR_MAX_MSGIN_LEN]; +#ifdef USE_NVRAM + uint16_t nvram; + uint8_t nvram_t; + uint8_t nvram_op; + uint8_t nvram_param; + uint8_t nvram_start; + uint8_t nvram_index; +#endif + uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */ + /* 0 if SCRIPTS are running or stopped. + * 1 if a Wait Reselect instruction has been issued. + * 2 if processing DMA from ncr53c8xx_execute_script. + * 3 if a DMA operation is in progress. */ + int waiting; + + uint8_t current_lun; + + uint8_t istat; + uint8_t dcmd; + uint8_t dstat; + uint8_t dien; + uint8_t sist0; + uint8_t sist1; + uint8_t sien0; + uint8_t sien1; + uint8_t mbox0; + uint8_t mbox1; + uint8_t dfifo; + uint8_t ctest2; + uint8_t ctest3; + uint8_t ctest4; + uint8_t ctest5; + uint8_t dmode; + uint8_t dcntl; + uint8_t scntl0; + uint8_t scntl1; + uint8_t scntl2; + uint8_t scntl3; + uint8_t sstat0; + uint8_t sstat1; + uint8_t scid; + uint8_t sxfer; + uint8_t socl; + uint8_t sdid; + uint8_t ssid; + uint8_t sfbr; + uint8_t stest1; + uint8_t stest2; + uint8_t stest3; + uint8_t sidl0; + uint8_t sidl1; + uint8_t stime0; + uint8_t respid0; + uint8_t respid1; + uint8_t sbr; + uint8_t chip_rev; + uint8_t gpreg; + uint8_t slpar; + uint8_t swide; + uint8_t gpcntl; + uint8_t last_command; + + int command_complete; + ncr53c8xx_request *current; + + int irq; + + uint32_t dsa; + uint32_t temp; + uint32_t dnad; + uint32_t dbc; + uint32_t dsp; + uint32_t dsps; + uint32_t scratcha, scratchb, scratchc, scratchd; + uint32_t scratche, scratchf, scratchg, scratchh; + uint32_t scratchi, scratchj; + int last_level; + void *hba_private; + uint32_t buffer_pos; + int32_t temp_buf_len; + + uint8_t sstop; + + uint8_t regop; + uint32_t adder; + + pc_timer_t timer; +} ncr53c8xx_t; + + +#ifdef ENABLE_NCR53C8XX_LOG +int ncr53c8xx_do_log = ENABLE_NCR53C8XX_LOG; + + +static void +ncr53c8xx_log(const char *fmt, ...) +{ + va_list ap; + + if (ncr53c8xx_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ncr53c8xx_log(fmt, ...) +#endif + + +static uint8_t ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset); +static void ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val); + + +static __inline__ int32_t +sextract32(uint32_t value, int start, int length) +{ + /* Note that this implementation relies on right shift of signed + * integers being an arithmetic shift. + */ + return ((int32_t)(value << (32 - length - start))) >> (32 - length); +} + + +static __inline__ int +ncr53c8xx_irq_on_rsl(ncr53c8xx_t *dev) +{ + return (dev->sien0 & NCR_SIST0_RSL) && (dev->scid & NCR_SCID_RRE); +} + + +static void +ncr53c8xx_soft_reset(ncr53c8xx_t *dev) +{ + int i; + + ncr53c8xx_log("LSI Reset\n"); + timer_stop(&dev->timer); + + dev->carry = 0; + + dev->msg_action = 0; + dev->msg_len = 0; + dev->waiting = 0; + dev->dsa = 0; + dev->dnad = 0; + dev->dbc = 0; + dev->temp = 0; + dev->scratcha = 0; + dev->scratchb = 0; + dev->scratchc = 0; + dev->scratchd = 0; + dev->scratche = 0; + dev->scratchf = 0; + dev->scratchg = 0; + dev->scratchh = 0; + dev->scratchi = 0; + dev->scratchj = 0; + dev->istat = 0; + dev->dcmd = 0x40; + dev->dstat = NCR_DSTAT_DFE; + dev->dien = 0; + dev->sist0 = 0; + dev->sist1 = 0; + dev->sien0 = 0; + dev->sien1 = 0; + dev->mbox0 = 0; + dev->mbox1 = 0; + dev->dfifo = 0; + dev->ctest2 = NCR_CTEST2_DACK; + dev->ctest3 = 0; + dev->ctest4 = 0; + dev->ctest5 = 0; + dev->dsp = 0; + dev->dsps = 0; + dev->dmode = 0; + dev->dcntl = 0; + dev->scntl0 = 0xc0; + dev->scntl1 = 0; + dev->scntl2 = 0; + if (dev->chip >= CHIP_825) + dev->scntl3 = 8; + else + dev->scntl3 = 0; + dev->sstat0 = 0; + dev->sstat1 = 0; + dev->scid = 7; + dev->sxfer = 0; + dev->socl = 0; + dev->sdid = 0; + dev->ssid = 0; + dev->stest1 = 0; + dev->stest2 = 0; + dev->stest3 = 0; + dev->sidl0 = 0; + dev->sidl1 = 0; + dev->stime0 = 0; + dev->stime0 = 1; + dev->respid0 = 0x80; + dev->respid1 = 0x00; + dev->sbr = 0; + dev->last_level = 0; + dev->gpreg = 0; + dev->slpar = 0; + dev->sstop = 1; + dev->gpcntl = 0x0f; +#ifdef USE_NVRAM + dev->nvram_t = dev->nvram_index = 0; +#endif + + if (dev->chip >= CHIP_825) { + /* This *IS* a wide SCSI controller, so reset all SCSI + devices. */ + for (i = 0; i < 16; i++) + scsi_device_reset(&scsi_devices[i]); + } else { + /* This is *NOT* a wide SCSI controller, so do not touch + SCSI devices with ID's >= 8. */ + for (i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[i]); + } +} + + +static void +ncr53c8xx_read(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +{ + uint32_t i = 0; + + ncr53c8xx_log("ncr53c8xx_read(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + + if (dev->dmode & NCR_DMODE_SIOM) { + ncr53c8xx_log("NCR 810: Reading from I/O address %04X\n", (uint16_t) addr); + for (i = 0; i < len; i++) + buf[i] = inb((uint16_t) (addr + i)); + } else { + ncr53c8xx_log("NCR 810: Reading from memory address %08X\n", addr); + DMAPageRead(addr, buf, len); + } +} + + +static void +ncr53c8xx_write(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +{ + uint32_t i = 0; + + ncr53c8xx_log("ncr53c8xx_write(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + + if (dev->dmode & NCR_DMODE_DIOM) { + ncr53c8xx_log("NCR 810: Writing to I/O address %04X\n", (uint16_t) addr); + for (i = 0; i < len; i++) + outb((uint16_t) (addr + i), buf[i]); + } else { + ncr53c8xx_log("NCR 810: Writing to memory address %08X\n", addr); + DMAPageWrite(addr, buf, len); + } +} + + +static __inline__ uint32_t +read_dword(ncr53c8xx_t *dev, uint32_t addr) +{ + uint32_t buf; + ncr53c8xx_log("Reading the next DWORD from memory (%08X)...\n", addr); + DMAPageRead(addr, (uint8_t *)&buf, 4); + return buf; +} + + +static +void do_irq(ncr53c8xx_t *dev, int level) +{ + if (level) { + pci_set_irq(dev->pci_slot, PCI_INTA); + ncr53c8xx_log("Raising IRQ...\n"); + } else { + pci_clear_irq(dev->pci_slot, PCI_INTA); + ncr53c8xx_log("Lowering IRQ...\n"); + } +} + + +static void +ncr53c8xx_update_irq(ncr53c8xx_t *dev) +{ + int level; + + /* It's unclear whether the DIP/SIP bits should be cleared when the + Interrupt Status Registers are cleared or when istat is read. + We currently do the formwer, which seems to work. */ + level = 0; + if (dev->dstat & 0x7f) { + if ((dev->dstat & dev->dien) & 0x7f) + level = 1; + dev->istat |= NCR_ISTAT_DIP; + } else { + dev->istat &= ~NCR_ISTAT_DIP; + } + + if (dev->sist0 || dev->sist1) { + if ((dev->sist0 & dev->sien0) || (dev->sist1 & dev->sien1)) + level = 1; + dev->istat |= NCR_ISTAT_SIP; + } else { + dev->istat &= ~NCR_ISTAT_SIP; + } + if (dev->istat & NCR_ISTAT_INTF) { + level = 1; + } + + if (level != dev->last_level) { + ncr53c8xx_log("Update IRQ level %d dstat %02x sist %02x%02x\n", + level, dev->dstat, dev->sist1, dev->sist0); + dev->last_level = level; + do_irq(dev, level); /* Only do something with the IRQ if the new level differs from the previous one. */ + } +} + + +/* Stop SCRIPTS execution and raise a SCSI interrupt. */ +static void +ncr53c8xx_script_scsi_interrupt(ncr53c8xx_t *dev, int stat0, int stat1) +{ + uint32_t mask0; + uint32_t mask1; + + ncr53c8xx_log("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", + stat1, stat0, dev->sist1, dev->sist0); + dev->sist0 |= stat0; + dev->sist1 |= stat1; + /* Stop processor on fatal or unmasked interrupt. As a special hack + we don't stop processing when raising STO. Instead continue + execution and stop at the next insn that accesses the SCSI bus. */ + mask0 = dev->sien0 | ~(NCR_SIST0_CMP | NCR_SIST0_SEL | NCR_SIST0_RSL); + mask1 = dev->sien1 | ~(NCR_SIST1_GEN | NCR_SIST1_HTH); + mask1 &= ~NCR_SIST1_STO; + if ((dev->sist0 & mask0) || (dev->sist1 & mask1)) { + ncr53c8xx_log("NCR 810: IRQ-mandated stop\n"); + dev->sstop = 1; + timer_stop(&dev->timer); + } + ncr53c8xx_update_irq(dev); +} + + +/* Stop SCRIPTS execution and raise a DMA interrupt. */ +static void +ncr53c8xx_script_dma_interrupt(ncr53c8xx_t *dev, int stat) +{ + ncr53c8xx_log("DMA Interrupt 0x%x prev 0x%x\n", stat, dev->dstat); + dev->dstat |= stat; + ncr53c8xx_update_irq(dev); + dev->sstop = 1; + timer_stop(&dev->timer); +} + + +static __inline__ void +ncr53c8xx_set_phase(ncr53c8xx_t *dev, int phase) +{ + dev->sstat1 = (dev->sstat1 & ~PHASE_MASK) | phase; +} + + +static void +ncr53c8xx_bad_phase(ncr53c8xx_t *dev, int out, int new_phase) +{ + /* Trigger a phase mismatch. */ + ncr53c8xx_log("Phase mismatch interrupt\n"); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + dev->sstop = 1; + timer_stop(&dev->timer); + ncr53c8xx_set_phase(dev, new_phase); +} + + +static void +ncr53c8xx_disconnect(ncr53c8xx_t *dev) +{ + dev->scntl1 &= ~NCR_SCNTL1_CON; + dev->sstat1 &= ~PHASE_MASK; + if (dev->dcmd & 0x01) /* Select with ATN */ + dev->sstat1 |= 0x07; +} + + +static void +ncr53c8xx_bad_selection(ncr53c8xx_t *dev, uint32_t id) +{ + ncr53c8xx_log("Selected absent target %d\n", id); + ncr53c8xx_script_scsi_interrupt(dev, 0, NCR_SIST1_STO); + ncr53c8xx_disconnect(dev); +} + + +/* Callback to indicate that the SCSI layer has completed a command. */ +static void +ncr53c8xx_command_complete(void *priv, uint32_t status) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; + int out; + + out = (dev->sstat1 & PHASE_MASK) == PHASE_DO; + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Command complete status=%d\n", dev->current->tag, dev->current_lun, dev->last_command, (int)status); + dev->status = status; + dev->command_complete = 2; + if (dev->waiting && dev->dbc != 0) { + /* Raise phase mismatch for short transfers. */ + ncr53c8xx_bad_phase(dev, out, PHASE_ST); + } else + ncr53c8xx_set_phase(dev, PHASE_ST); + + dev->sstop = 0; +} + + +static void +ncr53c8xx_do_dma(ncr53c8xx_t *dev, int out, uint8_t id) +{ + uint32_t addr, tdbc; + int count; + + scsi_device_t *sd = &scsi_devices[id]; + + if ((!scsi_device_present(sd))) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); + return; + } + + if (!dev->current->dma_len) { + /* Wait until data is available. */ + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", id, dev->current_lun, dev->last_command); + return; + } + + /* Make sure count is never bigger than buffer_length. */ + count = tdbc = dev->dbc; + if (count > dev->temp_buf_len) + count = dev->temp_buf_len; + + addr = dev->dnad; + + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA addr=0x%08x len=%d cur_len=%d dev->dbc=%d\n", id, dev->current_lun, dev->last_command, dev->dnad, dev->temp_buf_len, count, tdbc); + dev->dnad += count; + dev->dbc -= count; + + if (out) + ncr53c8xx_read(dev, addr, sd->sc->temp_buffer + dev->buffer_pos, count); + else { +#ifdef ENABLE_NCR53C8XX_LOG + if (!dev->buffer_pos) + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command); +#endif + ncr53c8xx_write(dev, addr, sd->sc->temp_buffer + dev->buffer_pos, count); + } + + dev->temp_buf_len -= count; + dev->buffer_pos += count; + + if (dev->temp_buf_len <= 0) { + scsi_device_command_phase1(&scsi_devices[id]); +#ifdef ENABLE_NCR53C8XX_LOG + if (out) + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); +#endif + ncr53c8xx_command_complete(dev, sd->status); + } else { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command); + dev->sstop = 0; + } +} + + +/* Queue a byte for a MSG IN phase. */ +static void +ncr53c8xx_add_msg_byte(ncr53c8xx_t *dev, uint8_t data) +{ + if (dev->msg_len >= NCR_MAX_MSGIN_LEN) + ncr53c8xx_log("MSG IN data too long\n"); + else { + ncr53c8xx_log("MSG IN 0x%02x\n", data); + dev->msg[dev->msg_len++] = data; + } +} + + +static void +ncr53c8xx_timer_on(ncr53c8xx_t *dev, scsi_device_t *sd, double p) +{ + double period; + + /* Fast SCSI: 10000000 bytes per second */ + period = (p > 0.0) ? p : (((double) sd->buffer_length) * 0.1); + + timer_on_auto(&dev->timer, period + 40.0); +} + + +static int +ncr53c8xx_do_command(ncr53c8xx_t *dev, uint8_t id) +{ + scsi_device_t *sd; + uint8_t buf[12]; + + memset(buf, 0, 12); + DMAPageRead(dev->dnad, buf, MIN(12, dev->dbc)); + if (dev->dbc > 12) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: CDB length %i too big\n", id, dev->current_lun, buf[0], dev->dbc); + dev->dbc = 12; + } + dev->sfbr = buf[0]; + dev->command_complete = 0; + + sd = &scsi_devices[id]; + if (!scsi_device_present(sd)) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); + ncr53c8xx_bad_selection(dev, id); + return 0; + } + + dev->current = (ncr53c8xx_request*)malloc(sizeof(ncr53c8xx_request)); + dev->current->tag = id; + + sd->buffer_length = -1; + + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc); + dev->last_command = buf[0]; + + /* Make sure bits 5-7 of the CDB have the correct LUN. */ + if ((buf[1] & 0xe0) != (dev->current_lun << 5)) + buf[1] = (buf[1] & 0x1f) | (dev->current_lun << 5); + + scsi_device_command_phase0(&scsi_devices[dev->current->tag], buf); + dev->hba_private = (void *)dev->current; + + dev->waiting = 0; + dev->buffer_pos = 0; + + dev->temp_buf_len = sd->buffer_length; + + if (sd->buffer_length > 0) { + /* This should be set to the underlying device's buffer by command phase 0. */ + dev->current->dma_len = sd->buffer_length; + } + + if ((sd->phase == SCSI_PHASE_DATA_IN) && (sd->buffer_length > 0)) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); + ncr53c8xx_set_phase(dev, PHASE_DI); + ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); + return 1; + } else if ((sd->phase == SCSI_PHASE_DATA_OUT) && (sd->buffer_length > 0)) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); + ncr53c8xx_set_phase(dev, PHASE_DO); + ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); + return 1; + } else { + ncr53c8xx_command_complete(dev, sd->status); + return 0; + } +} + + +static void +ncr53c8xx_do_status(ncr53c8xx_t *dev) +{ + uint8_t status; + ncr53c8xx_log("Get status len=%d status=%d\n", dev->dbc, dev->status); + if (dev->dbc != 1) + ncr53c8xx_log("Bad Status move\n"); + dev->dbc = 1; + status = dev->status; + dev->sfbr = status; + ncr53c8xx_write(dev, dev->dnad, &status, 1); + ncr53c8xx_set_phase(dev, PHASE_MI); + dev->msg_action = 1; + ncr53c8xx_add_msg_byte(dev, 0); /* COMMAND COMPLETE */ +} + + +#ifdef USE_WDTR +static void +ncr53c8xx_do_wdtr(ncr53c8xx_t *dev, int exponent) +{ + ncr53c8xx_log("Target-initiated WDTR (%08X)\n", dev); + ncr53c8xx_set_phase(dev, PHASE_MI); + dev->msg_action = 4; + ncr53c8xx_add_msg_byte(dev, 0x01); /* EXTENDED MESSAGE */ + ncr53c8xx_add_msg_byte(dev, 0x02); /* EXTENDED MESSAGE LENGTH */ + ncr53c8xx_add_msg_byte(dev, 0x03); /* WIDE DATA TRANSFER REQUEST */ + ncr53c8xx_add_msg_byte(dev, exponent); /* TRANSFER WIDTH EXPONENT (16-bit) */ +} +#endif + + +static void +ncr53c8xx_do_msgin(ncr53c8xx_t *dev) +{ + uint32_t len; + ncr53c8xx_log("Message in len=%d/%d\n", dev->dbc, dev->msg_len); + dev->sfbr = dev->msg[0]; + len = dev->msg_len; + if (len > dev->dbc) + len = dev->dbc; + ncr53c8xx_write(dev, dev->dnad, dev->msg, len); + /* Linux drivers rely on the last byte being in the SIDL. */ + dev->sidl0 = dev->msg[len - 1]; + dev->msg_len -= len; + if (dev->msg_len) + memmove(dev->msg, dev->msg + len, dev->msg_len); + else { + /* ??? Check if ATN (not yet implemented) is asserted and maybe + switch to PHASE_MO. */ + switch (dev->msg_action) { + case 0: + ncr53c8xx_set_phase(dev, PHASE_CMD); + break; + case 1: + ncr53c8xx_disconnect(dev); + break; + case 2: + ncr53c8xx_set_phase(dev, PHASE_DO); + break; + case 3: + ncr53c8xx_set_phase(dev, PHASE_DI); + break; + case 4: + ncr53c8xx_set_phase(dev, PHASE_MO); + break; + default: + abort(); + } + } +} + + +/* Read the next byte during a MSGOUT phase. */ +static uint8_t +ncr53c8xx_get_msgbyte(ncr53c8xx_t *dev) +{ + uint8_t data; + DMAPageRead(dev->dnad, &data, 1); + dev->dnad++; + dev->dbc--; + return data; +} + + +/* Skip the next n bytes during a MSGOUT phase. */ +static void +ncr53c8xx_skip_msgbytes(ncr53c8xx_t *dev, unsigned int n) +{ + dev->dnad += n; + dev->dbc -= n; +} + + +static void +ncr53c8xx_bad_message(ncr53c8xx_t *dev, uint8_t msg) +{ + ncr53c8xx_log("Unimplemented message 0x%02x\n", msg); + ncr53c8xx_set_phase(dev, PHASE_MI); + ncr53c8xx_add_msg_byte(dev, 7); /* MESSAGE REJECT */ + dev->msg_action = 0; +} + + +static void +ncr53c8xx_do_msgout(ncr53c8xx_t *dev, uint8_t id) +{ + uint8_t msg; + int len, arg; +#ifdef ENABLE_NCR53C8XX_LOG + uint32_t current_tag; +#endif + scsi_device_t *sd; + + sd = &scsi_devices[id]; + +#ifdef ENABLE_NCR53C8XX_LOG + current_tag = id; +#endif + + ncr53c8xx_log("MSG out len=%d\n", dev->dbc); + while (dev->dbc) { + msg = ncr53c8xx_get_msgbyte(dev); + dev->sfbr = msg; + + switch (msg) { + case 0x04: + ncr53c8xx_log("MSG: Disconnect\n"); + ncr53c8xx_disconnect(dev); + break; + case 0x08: + ncr53c8xx_log("MSG: No Operation\n"); + ncr53c8xx_set_phase(dev, PHASE_CMD); + break; + case 0x01: + len = ncr53c8xx_get_msgbyte(dev); + msg = ncr53c8xx_get_msgbyte(dev); + arg = ncr53c8xx_get_msgbyte(dev); + (void) len; /* avoid a warning about unused variable*/ + ncr53c8xx_log("Extended message 0x%x (len %d)\n", msg, len); + switch (msg) { + case 1: + ncr53c8xx_log("SDTR (ignored)\n"); + ncr53c8xx_skip_msgbytes(dev, 1); + break; + case 3: + ncr53c8xx_log("WDTR (ignored)\n"); + if (arg > 0x01) { + ncr53c8xx_bad_message(dev, msg); + return; + } +#ifdef USE_WDTR + ncr53c8xx_set_phase(dev, PHASE_CMD); +#endif + break; + case 5: + ncr53c8xx_log("PPR (ignored)\n"); + ncr53c8xx_skip_msgbytes(dev, 4); + break; + default: + ncr53c8xx_bad_message(dev, msg); + return; + } + break; + case 0x20: /* SIMPLE queue */ + id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; + ncr53c8xx_log("SIMPLE queue tag=0x%x\n", id & 0xff); + break; + case 0x21: /* HEAD of queue */ + ncr53c8xx_log("HEAD queue not implemented\n"); + id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; + break; + case 0x22: /* ORDERED queue */ + ncr53c8xx_log("ORDERED queue not implemented\n"); + id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; + break; + case 0x0d: + /* The ABORT TAG message clears the current I/O process only. */ + ncr53c8xx_log("MSG: Abort Tag\n"); + scsi_device_command_stop(sd); + ncr53c8xx_disconnect(dev); + break; + case 0x06: + case 0x0e: + case 0x0c: + /* clear the current I/O process */ + scsi_device_command_stop(sd); + ncr53c8xx_disconnect(dev); + break; + default: + if ((msg & 0x80) == 0) { + ncr53c8xx_bad_message(dev, msg); + return; + } else { + /* 0x80 to 0xff are IDENTIFY messages. */ + ncr53c8xx_log("MSG: Identify\n"); + dev->current_lun = msg & 7; + ncr53c8xx_log("Select LUN %d\n", dev->current_lun); +#ifdef USE_WDTR + ncr53c8xx_do_wdtr(dev, 0x01); +#else + ncr53c8xx_set_phase(dev, PHASE_CMD); +#endif + } + break; + } + } +} + + +static void +ncr53c8xx_memcpy(ncr53c8xx_t *dev, uint32_t dest, uint32_t src, int count) +{ + int n; + uint8_t buf[NCR_BUF_SIZE]; + + ncr53c8xx_log("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); + while (count) { + n = (count > NCR_BUF_SIZE) ? NCR_BUF_SIZE : count; + ncr53c8xx_read(dev, src, buf, n); + ncr53c8xx_write(dev, dest, buf, n); + src += n; + dest += n; + count -= n; + } +} + + +static void +ncr53c8xx_process_script(ncr53c8xx_t *dev) +{ + uint32_t insn, addr, id, buf[2], dest; + int opcode, insn_processed = 0, reg, operator, cond, jmp, n, i, c; + int32_t offset; + uint8_t op0, op1, data8, mask, data[7]; +#ifdef ENABLE_NCR53C8XX_LOG + uint8_t *pp; +#endif + + dev->sstop = 0; +again: + insn_processed++; + insn = read_dword(dev, dev->dsp); + if (!insn) { + /* If we receive an empty opcode increment the DSP by 4 bytes + instead of 8 and execute the next opcode at that location */ + dev->dsp += 4; + if (insn_processed < 100) + goto again; + else { + timer_on_auto(&dev->timer, 10.0); + return; + } + } + addr = read_dword(dev, dev->dsp + 4); + ncr53c8xx_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr); + dev->dsps = addr; + dev->dcmd = insn >> 24; + dev->dsp += 8; + + switch (insn >> 30) { + case 0: /* Block move. */ + ncr53c8xx_log("00: Block move\n"); + if (dev->sist1 & NCR_SIST1_STO) { + ncr53c8xx_log("Delayed select timeout\n"); + dev->sstop = 1; + break; + } + ncr53c8xx_log("Block Move DBC=%d\n", dev->dbc); + dev->dbc = insn & 0xffffff; + ncr53c8xx_log("Block Move DBC=%d now\n", dev->dbc); + /* ??? Set ESA. */ + if (insn & (1 << 29)) { + /* Indirect addressing. */ + /* Should this respect SIOM? */ + addr = read_dword(dev, addr); + ncr53c8xx_log("Indirect Block Move address: %08X\n", addr); + } else if (insn & (1 << 28)) { + /* Table indirect addressing. */ + + /* 32-bit Table indirect */ + offset = sextract32(addr, 0, 24); + DMAPageRead(dev->dsa + offset, (uint8_t *)buf, 8); + /* byte count is stored in bits 0:23 only */ + dev->dbc = buf[0] & 0xffffff; + addr = buf[1]; + + /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of + * table, bits [31:24] */ + } + if ((dev->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { + ncr53c8xx_log("Wrong phase got %d expected %d\n", + dev->sstat1 & PHASE_MASK, (insn >> 24) & 7); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + break; + } + dev->dnad = addr; + switch (dev->sstat1 & 0x7) { + case PHASE_DO: + ncr53c8xx_log("Data Out Phase\n"); + dev->waiting = 0; + ncr53c8xx_do_dma(dev, 1, dev->sdid); + break; + case PHASE_DI: + ncr53c8xx_log("Data In Phase\n"); + dev->waiting = 0; + ncr53c8xx_do_dma(dev, 0, dev->sdid); + break; + case PHASE_CMD: + ncr53c8xx_log("Command Phase\n"); + c = ncr53c8xx_do_command(dev, dev->sdid); + + if (!c || dev->sstop || dev->waiting || ((dev->sstat1 & 0x7) == PHASE_ST)) + break; + + dev->dfifo = dev->dbc & 0xff; + dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); + + if (dev->dcntl & NCR_DCNTL_SSM) + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); + return; + case PHASE_ST: + ncr53c8xx_log("Status Phase\n"); + ncr53c8xx_do_status(dev); + break; + case PHASE_MO: + ncr53c8xx_log("MSG Out Phase\n"); + ncr53c8xx_do_msgout(dev, dev->sdid); + break; + case PHASE_MI: + ncr53c8xx_log("MSG In Phase\n"); + ncr53c8xx_do_msgin(dev); + break; + default: + ncr53c8xx_log("Unimplemented phase %d\n", dev->sstat1 & PHASE_MASK); + } + dev->dfifo = dev->dbc & 0xff; + dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); + break; + + case 1: /* IO or Read/Write instruction. */ + ncr53c8xx_log("01: I/O or Read/Write instruction\n"); + opcode = (insn >> 27) & 7; + if (opcode < 5) { + if (insn & (1 << 25)) + id = read_dword(dev, dev->dsa + sextract32(insn, 0, 24)); + else + id = insn; + id = (id >> 16) & 0xf; + if (insn & (1 << 26)) + addr = dev->dsp + sextract32(addr, 0, 24); + dev->dnad = addr; + switch (opcode) { + case 0: /* Select */ + dev->sdid = id; + if (dev->scntl1 & NCR_SCNTL1_CON) { + ncr53c8xx_log("Already reselected, jumping to alternative address\n"); + dev->dsp = dev->dnad; + break; + } + dev->sstat0 |= NCR_SSTAT0_WOA; + dev->scntl1 &= ~NCR_SCNTL1_IARB; + if (!scsi_device_present(&scsi_devices[id])) { + ncr53c8xx_bad_selection(dev, id); + break; + } + ncr53c8xx_log("Selected target %d%s\n", + id, insn & (1 << 24) ? " ATN" : ""); + dev->scntl1 |= NCR_SCNTL1_CON; + if (insn & (1 << 24)) + dev->socl |= NCR_SOCL_ATN; + ncr53c8xx_set_phase(dev, PHASE_MO); + dev->waiting = 0; + break; + case 1: /* Disconnect */ + ncr53c8xx_log("Wait Disconnect\n"); + dev->scntl1 &= ~NCR_SCNTL1_CON; + break; + case 2: /* Wait Reselect */ + ncr53c8xx_log("Wait Reselect\n"); + if (dev->istat & NCR_ISTAT_SIGP) + dev->dsp = dev->dnad; /* If SIGP is set, this command causes an immediate jump to DNAD. */ + else { + if (!ncr53c8xx_irq_on_rsl(dev)) + dev->waiting = 1; + } + break; + case 3: /* Set */ + ncr53c8xx_log("Set%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) { + dev->socl |= NCR_SOCL_ATN; + ncr53c8xx_set_phase(dev, PHASE_MO); + } + if (insn & (1 << 9)) + ncr53c8xx_log("Target mode not implemented\n"); + if (insn & (1 << 10)) + dev->carry = 1; + break; + case 4: /* Clear */ + ncr53c8xx_log("Clear%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) + dev->socl &= ~NCR_SOCL_ATN; + if (insn & (1 << 10)) + dev->carry = 0; + break; + } + } else { + reg = ((insn >> 16) & 0x7f) | (insn & 0x80); + data8 = (insn >> 8) & 0xff; + opcode = (insn >> 27) & 7; + operator = (insn >> 24) & 7; + op0 = op1 = 0; + switch (opcode) { + case 5: /* From SFBR */ + op0 = dev->sfbr; + op1 = data8; + break; + case 6: /* To SFBR */ + if (operator) + op0 = ncr53c8xx_reg_readb(dev, reg); + op1 = data8; + break; + case 7: /* Read-modify-write */ + if (operator) + op0 = ncr53c8xx_reg_readb(dev, reg); + if (insn & (1 << 23)) + op1 = dev->sfbr; + else + op1 = data8; + break; + } + + switch (operator) { + case 0: /* move */ + op0 = op1; + break; + case 1: /* Shift left */ + op1 = op0 >> 7; + op0 = (op0 << 1) | dev->carry; + dev->carry = op1; + break; + case 2: /* OR */ + op0 |= op1; + break; + case 3: /* XOR */ + op0 ^= op1; + break; + case 4: /* AND */ + op0 &= op1; + break; + case 5: /* SHR */ + op1 = op0 & 1; + op0 = (op0 >> 1) | (dev->carry << 7); + dev->carry = op1; + break; + case 6: /* ADD */ + op0 += op1; + dev->carry = op0 < op1; + break; + case 7: /* ADC */ + op0 += op1 + dev->carry; + if (dev->carry) + dev->carry = op0 <= op1; + else + dev->carry = op0 < op1; + break; + } + + switch (opcode) { + case 5: /* From SFBR */ + case 7: /* Read-modify-write */ + ncr53c8xx_reg_writeb(dev, reg, op0); + break; + case 6: /* To SFBR */ + dev->sfbr = op0; + break; + } + } + break; + + case 2: /* Transfer Control. */ + ncr53c8xx_log("02: Transfer Control\n"); + if ((insn & 0x002e0000) == 0) { + ncr53c8xx_log("NOP\n"); + break; + } + if (dev->sist1 & NCR_SIST1_STO) { + ncr53c8xx_log("Delayed select timeout\n"); + dev->sstop = 1; + break; + } + cond = jmp = (insn & (1 << 19)) != 0; + if (cond == jmp && (insn & (1 << 21))) { + ncr53c8xx_log("Compare carry %d\n", dev->carry == jmp); + cond = dev->carry != 0; + } + if (cond == jmp && (insn & (1 << 17))) { + ncr53c8xx_log("Compare phase %d %c= %d\n", (dev->sstat1 & PHASE_MASK), + jmp ? '=' : '!', ((insn >> 24) & 7)); + cond = (dev->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); + } + if (cond == jmp && (insn & (1 << 18))) { + mask = (~insn >> 8) & 0xff; + ncr53c8xx_log("Compare data 0x%x & 0x%x %c= 0x%x\n", dev->sfbr, mask, + jmp ? '=' : '!', insn & mask); + cond = (dev->sfbr & mask) == (insn & mask); + } + if (cond == jmp) { + if (insn & (1 << 23)) { + /* Relative address. */ + addr = dev->dsp + sextract32(addr, 0, 24); + } + switch ((insn >> 27) & 7) { + case 0: /* Jump */ + ncr53c8xx_log("Jump to 0x%08x\n", addr); + dev->adder = addr; + dev->dsp = addr; + break; + case 1: /* Call */ + ncr53c8xx_log("Call 0x%08x\n", addr); + dev->temp = dev->dsp; + dev->dsp = addr; + break; + case 2: /* Return */ + ncr53c8xx_log("Return to 0x%08x\n", dev->temp); + dev->dsp = dev->temp; + break; + case 3: /* Interrupt */ + ncr53c8xx_log("Interrupt 0x%08x\n", dev->dsps); + if ((insn & (1 << 20)) != 0) { + dev->istat |= NCR_ISTAT_INTF; + ncr53c8xx_update_irq(dev); + } else + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SIR); + break; + default: + ncr53c8xx_log("Illegal transfer control\n"); + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_IID); + break; + } + } else + ncr53c8xx_log("Control condition failed\n"); + break; + + case 3: + ncr53c8xx_log("00: Memory move\n"); + if ((insn & (1 << 29)) == 0) { + /* Memory move. */ + /* ??? The docs imply the destination address is loaded into + the TEMP register. However the Linux drivers rely on + the value being presrved. */ + dest = read_dword(dev, dev->dsp); + dev->dsp += 4; + ncr53c8xx_memcpy(dev, dest, addr, insn & 0xffffff); + } else { +#ifdef ENABLE_NCR53C8XX_LOG + pp = data; +#endif + + if (insn & (1 << 28)) + addr = dev->dsa + sextract32(addr, 0, 24); + n = (insn & 7); + reg = (insn >> 16) & 0xff; + if (insn & (1 << 24)) { + DMAPageRead(addr, data, n); + for (i = 0; i < n; i++) + ncr53c8xx_reg_writeb(dev, reg + i, data[i]); + } else { + ncr53c8xx_log("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + for (i = 0; i < n; i++) + data[i] = ncr53c8xx_reg_readb(dev, reg + i); + DMAPageWrite(addr, data, n); + } + } + break; + + default: + ncr53c8xx_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); + } + + ncr53c8xx_log("instructions processed %i\n", insn_processed); + if (insn_processed > 10000 && !dev->waiting) { + /* Some windows drivers make the device spin waiting for a memory + location to change. If we have been executed a lot of code then + assume this is the case and force an unexpected device disconnect. + This is apparently sufficient to beat the drivers into submission. + */ + ncr53c8xx_log("Some windows drivers make the device spin...\n"); + if (!(dev->sien0 & NCR_SIST0_UDC)) + ncr53c8xx_log("inf. loop with UDC masked\n"); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_UDC, 0); + ncr53c8xx_disconnect(dev); + } else if (!dev->sstop && !dev->waiting) { + if (dev->dcntl & NCR_DCNTL_SSM) { + ncr53c8xx_log("NCR 810: SCRIPTS: Single-step mode\n"); + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); + } else { + ncr53c8xx_log("NCR 810: SCRIPTS: Normal mode\n"); + if (insn_processed < 100) + goto again; + } + } else { + if (dev->sstop) + ncr53c8xx_log("NCR 810: SCRIPTS: Stopped\n"); + if (dev->waiting) + ncr53c8xx_log("NCR 810: SCRIPTS: Waiting\n"); + } + + timer_on_auto(&dev->timer, 40.0); + + ncr53c8xx_log("SCRIPTS execution stopped\n"); +} + + +static void +ncr53c8xx_execute_script(ncr53c8xx_t *dev) +{ + dev->sstop = 0; + timer_on_auto(&dev->timer, 40.0); +} + + +static void +ncr53c8xx_callback(void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *) p; + + if (!dev->sstop) { + if (dev->waiting) + timer_on_auto(&dev->timer, 40.0); + else + ncr53c8xx_process_script(dev); + } + + if (dev->sstop) + timer_stop(&dev->timer); +} + + +#ifdef USE_NVRAM +static void +ncr53c8xx_eeprom(ncr53c8xx_t *dev, int save) +{ + FILE *f; + + if (save) + f = nvr_fopen(dev->nvr_path, L"wb"); + else + f = nvr_fopen(dev->nvr_path, L"rb"); + if (f) + { + if (save) { + fwrite((uint8_t *) &dev->nvram, 1, 1, f); + fwrite(((uint8_t *) &dev->nvram) + 1, 1, 1, f); + } else { + fread((uint8_t *) &dev->nvram, 1, 1, f); + fread(((uint8_t *) &dev->nvram) + 1, 1, 1, f); + } + fclose(f); + f = NULL; + } +} + + +#define ADDRESS_LENGTH 9 +#define ADDRESS_END (ADDRESS_LENGTH + 2) +#define ADDRESS_SHIFT (ADDRESS_LENGTH - 2) +#define ADDRESS_MASK 0x3f +#define DATA_LENGTH 8 +#define DATA_START (ADDRESS_END + 1) +#define DATA_END (ADDRESS_END + DATA_LENGTH) + + +static void +ncr53c8xx_serial_eeprom_write(ncr53c8xx_t *dev, uint8_t val) +{ + uint8_t temp, old = dev->nvram_t; + dev->nvram_t = val & 0x03; + + if (val & 0x02) { + if (!dev->nvram_index) { + /* First signal clocked in after clock is high, start bit. */ + dev->nvram_start = 1; + ncr53c8xx_log("[W] Serial EEPROM: Start bit\n"); + dev->nvram_op = 0; + } else if ((dev->nvram_index == 1) || (dev->nvram_index == 2)) { + if (!dev->nvram_start) + return; + + dev->nvram_op = (val & 0x01) << (dev->nvram_index - 1); + if (dev->nvram_index == 2) { + // ncr53c8xx_log("[W] Serial EEPROM: Opcode: %01X\n", dev->nvram_op); + dev->nvram_param = 0; + } + } else if ((dev->nvram_index >= 3) && (dev->nvram_index <= ADDRESS_END)) { + if (!dev->nvram_start) + return; + + dev->nvram_param = (val & 0x01) << (dev->nvram_index - 3); + if (dev->nvram_index < ADDRESS_END) { + dev->nvram_index++; + return; + } + + switch (dev->nvram_op) { + case 0x00: + temp = dev->nvram_param >> ADDRESS_SHIFT; + switch(temp) { + case 0x00: + ncr53c8xx_log("[W] Serial EEPROM: EWDS\n"); + break; + case 0x01: + ncr53c8xx_log("[W] Serial EEPROM: WRAL\n"); + break; + case 0x02: + ncr53c8xx_log("[W] Serial EEPROM: ERAL\n"); + break; + case 0x03: + ncr53c8xx_log("[W] Serial EEPROM: EWEN\n"); + break; + default: + ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN 00\n"); + break; + } + dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; + return; + case 0x01: + ncr53c8xx_log("[W] Serial EEPROM: WRITE\n"); + break; + case 0x02: + ncr53c8xx_log("[W] Serial EEPROM: READ\n"); + break; + case 0x03: + ncr53c8xx_log("[W] Serial EEPROM: ERASE\n"); + break; + default: + ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN\n"); + break; + } + } else if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { + if (!dev->nvram_start) + return; + + if (dev->nvram_index == DATA_END) { + ncr53c8xx_log("[W] Serial EEPROM: Data end\n"); + dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; + return; + } + } + dev->nvram_index++; + } +} + + +static uint8_t +ncr53c8xx_serial_eeprom_read(ncr53c8xx_t *dev) +{ + uint8_t temp = 0; + + if (dev->gpreg & 0x02) { + if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { + if (!dev->nvram_start) + return temp; + + dev->nvram_index++; + + if (dev->nvram_index == DATA_END) { + ncr53c8xx_log("[R] Serial EEPROM: Data end\n"); + dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; + return temp; + } + } + } + + return temp; +} +#endif + + +static void +ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) +{ + uint8_t tmp = 0; + +#define CASE_SET_REG24(name, addr) \ + case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ + case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ + case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; + +#define CASE_SET_REG32(name, addr) \ + case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ + case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ + case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; \ + case addr + 3: dev->name &= 0x00ffffff; dev->name |= val << 24; break; + +#ifdef DEBUG_NCR_REG + ncr53c8xx_log("Write reg %02x = %02x\n", offset, val); +#endif + + dev->regop = 1; + + switch (offset) { + case 0x00: /* SCNTL0 */ + dev->scntl0 = val; + if (val & NCR_SCNTL0_START) { + /* Looks like this (turn on bit 4 of SSTAT0 to mark arbitration in progress) + is enough to make BIOS v4.x happy. */ + ncr53c8xx_log("NCR 810: Selecting SCSI ID %i\n", dev->sdid); + dev->sstat0 |= 0x10; + } + break; + case 0x01: /* SCNTL1 */ + dev->scntl1 = val & ~NCR_SCNTL1_SST; + if (val & NCR_SCNTL1_IARB) { + ncr53c8xx_log("Arbitration lost\n"); + dev->sstat0 |= 0x08; + dev->waiting = 0; + } + if (val & NCR_SCNTL1_RST) { + if (!(dev->sstat0 & NCR_SSTAT0_RST)) { + dev->sstat0 |= NCR_SSTAT0_RST; + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_RST, 0); + } + } else + dev->sstat0 &= ~NCR_SSTAT0_RST; + break; + case 0x02: /* SCNTL2 */ + val &= ~(NCR_SCNTL2_WSR | NCR_SCNTL2_WSS); + dev->scntl2 = val; + break; + case 0x03: /* SCNTL3 */ + dev->scntl3 = val; + break; + case 0x04: /* SCID */ + dev->scid = val; + break; + case 0x05: /* SXFER */ + dev->sxfer = val; + break; + case 0x06: /* SDID */ + if ((dev->ssid & 0x80) && (val & 0xf) != (dev->ssid & 0xf)) + ncr53c8xx_log("Destination ID does not match SSID\n"); + dev->sdid = val & 0xf; + break; + case 0x07: /* GPREG */ + ncr53c8xx_log("NCR 810: GPREG write %02X\n", val); + tmp = dev->gpreg; + dev->gpreg = val & 0xfe; +#ifdef USE_NVRAM + if ((dev->gpcntl & 0xc3) == 0x00) + ncr53c8xx_serial_eeprom_write(dev, val & 0x03); +#endif + break; + case 0x08: /* SFBR */ + /* The CPU is not allowed to write to this register. However the + SCRIPTS register move instructions are. */ + dev->sfbr = val; + break; + case 0x09: /* SOCL */ + ncr53c8xx_log("NCR 810: SOCL write %02X\n", val); + dev->socl = val; + break; + case 0x0a: case 0x0b: + /* Openserver writes to these readonly registers on startup */ + return; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + /* Linux writes to these readonly registers on startup. */ + return; + CASE_SET_REG32(dsa, 0x10) + case 0x14: /* ISTAT */ + ncr53c8xx_log("ISTAT write: %02X\n", val); + tmp = dev->istat; + dev->istat = (dev->istat & 0x0f) | (val & 0xf0); + if ((val & NCR_ISTAT_ABRT) && !(val & NCR_ISTAT_SRST)) + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_ABRT); + if (val & NCR_ISTAT_INTF) { + dev->istat &= ~NCR_ISTAT_INTF; + ncr53c8xx_update_irq(dev); + } + + if ((dev->waiting == 1) && (val & NCR_ISTAT_SIGP)) { + ncr53c8xx_log("Woken by SIGP\n"); + dev->waiting = 0; + dev->dsp = dev->dnad; + /* ncr53c8xx_execute_script(dev); */ + } + if ((val & NCR_ISTAT_SRST) && !(tmp & NCR_ISTAT_SRST)) { + ncr53c8xx_soft_reset(dev); + ncr53c8xx_update_irq(dev); + dev->istat = 0; + } + break; + case 0x16: /* MBOX0 */ + dev->mbox0 = val; + break; + case 0x17: /* MBOX1 */ + dev->mbox1 = val; + break; + case 0x18: /* CTEST0 */ + /* nothing to do */ + break; + case 0x19: /* CTEST1 */ + /* nothing to do */ + break; + case 0x1a: /* CTEST2 */ + dev->ctest2 = val & NCR_CTEST2_PCICIE; + break; + case 0x1b: /* CTEST3 */ + dev->ctest3 = val & 0x0f; + break; + CASE_SET_REG32(temp, 0x1c) + case 0x21: /* CTEST4 */ + if (val & 7) + ncr53c8xx_log("Unimplemented CTEST4-FBL 0x%x\n", val); + dev->ctest4 = val; + break; + case 0x22: /* CTEST5 */ + if (val & (NCR_CTEST5_ADCK | NCR_CTEST5_BBCK)) + ncr53c8xx_log("CTEST5 DMA increment not implemented\n"); + dev->ctest5 = val; + break; + CASE_SET_REG24(dbc, 0x24) + CASE_SET_REG32(dnad, 0x28) + case 0x2c: /* DSP[0:7] */ + dev->dsp &= 0xffffff00; + dev->dsp |= val; + break; + case 0x2d: /* DSP[8:15] */ + dev->dsp &= 0xffff00ff; + dev->dsp |= val << 8; + break; + case 0x2e: /* DSP[16:23] */ + dev->dsp &= 0xff00ffff; + dev->dsp |= val << 16; + break; + case 0x2f: /* DSP[24:31] */ + dev->dsp &= 0x00ffffff; + dev->dsp |= val << 24; + if (!(dev->dmode & NCR_DMODE_MAN) && dev->sstop) + ncr53c8xx_execute_script(dev); + break; + CASE_SET_REG32(dsps, 0x30) + CASE_SET_REG32(scratcha, 0x34) + case 0x38: /* DMODE */ + dev->dmode = val; + break; + case 0x39: /* DIEN */ + ncr53c8xx_log("DIEN write: %02X\n", val); + dev->dien = val; + ncr53c8xx_update_irq(dev); + break; + case 0x3a: /* SBR */ + dev->sbr = val; + break; + case 0x3b: /* DCNTL */ + dev->dcntl = val & ~(NCR_DCNTL_PFF | NCR_DCNTL_STD); + if ((val & NCR_DCNTL_STD) && dev->sstop) + ncr53c8xx_execute_script(dev); + break; + case 0x40: /* SIEN0 */ + dev->sien0 = val; + ncr53c8xx_update_irq(dev); + break; + case 0x41: /* SIEN1 */ + dev->sien1 = val; + ncr53c8xx_update_irq(dev); + break; + case 0x47: /* GPCNTL */ + ncr53c8xx_log("GPCNTL write: %02X\n", val); + dev->gpcntl = val; + break; + case 0x48: /* STIME0 */ + dev->stime0 = val; + break; + case 0x49: /* STIME1 */ + if (val & 0xf) { + ncr53c8xx_log("General purpose timer not implemented\n"); + /* ??? Raising the interrupt immediately seems to be sufficient + to keep the FreeBSD driver happy. */ + ncr53c8xx_script_scsi_interrupt(dev, 0, NCR_SIST1_GEN); + } + break; + case 0x4a: /* RESPID0 */ + dev->respid0 = val; + break; + case 0x4b: /* RESPID1 */ + if (dev->chip >= CHIP_825) + dev->respid1 = val; + break; + case 0x4d: /* STEST1 */ + dev->stest1 = val; + break; + case 0x4e: /* STEST2 */ + if (val & 1) + ncr53c8xx_log("Low level mode not implemented\n"); + dev->stest2 = val; + break; + case 0x4f: /* STEST3 */ + if (val & 0x41) + ncr53c8xx_log("SCSI FIFO test mode not implemented\n"); + dev->stest3 = val; + break; + case 0x54: + case 0x55: + break; + CASE_SET_REG32(scratchb, 0x5c) + CASE_SET_REG32(scratchc, 0x60) + CASE_SET_REG32(scratchd, 0x64) + CASE_SET_REG32(scratche, 0x68) + CASE_SET_REG32(scratchf, 0x6c) + CASE_SET_REG32(scratchg, 0x70) + CASE_SET_REG32(scratchh, 0x74) + CASE_SET_REG32(scratchi, 0x78) + CASE_SET_REG32(scratchj, 0x7c) + default: + ncr53c8xx_log("Unhandled writeb 0x%x = 0x%x\n", offset, val); + } +#undef CASE_SET_REG24 +#undef CASE_SET_REG32 +} + + +static uint8_t +ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) +{ + uint8_t tmp; +#define CASE_GET_REG24(name, addr) \ + case addr: return dev->name & 0xff; \ + case addr + 1: return (dev->name >> 8) & 0xff; \ + case addr + 2: return (dev->name >> 16) & 0xff; + +#define CASE_GET_REG32(name, addr) \ + case addr: return dev->name & 0xff; \ + case addr + 1: return (dev->name >> 8) & 0xff; \ + case addr + 2: return (dev->name >> 16) & 0xff; \ + case addr + 3: return (dev->name >> 24) & 0xff; + +#define CASE_GET_REG32_COND(name, addr) \ + case addr: if (dev->chip >= CHIP_825) \ + return dev->name & 0xff; \ + else \ + return 0x00; \ + case addr + 1: if (dev->chip >= CHIP_825) \ + return (dev->name >> 8) & 0xff; \ + else \ + return 0x00; \ + case addr + 2: if (dev->chip >= CHIP_825) \ + return (dev->name >> 16) & 0xff; \ + else \ + return 0x00; \ + case addr + 3: if (dev->chip >= CHIP_825) \ + return (dev->name >> 24) & 0xff; \ + else \ + return 0x00; + + dev->regop = 1; + + switch (offset) { + case 0x00: /* SCNTL0 */ + ncr53c8xx_log("NCR 810: Read SCNTL0 %02X\n", dev->scntl0); + return dev->scntl0; + case 0x01: /* SCNTL1 */ + ncr53c8xx_log("NCR 810: Read SCNTL1 %02X\n", dev->scntl1); + return dev->scntl1; + case 0x02: /* SCNTL2 */ + ncr53c8xx_log("NCR 810: Read SCNTL2 %02X\n", dev->scntl2); + return dev->scntl2; + case 0x03: /* SCNTL3 */ + ncr53c8xx_log("NCR 810: Read SCNTL3 %02X\n", dev->scntl3); + return dev->scntl3; + case 0x04: /* SCID */ + ncr53c8xx_log("NCR 810: Read SCID %02X\n", dev->scid); + return dev->scid & ~0x40; + case 0x05: /* SXFER */ + ncr53c8xx_log("NCR 810: Read SXFER %02X\n", dev->sxfer); + return dev->sxfer; + case 0x06: /* SDID */ + ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid); + return dev->sdid; + case 0x07: /* GPREG */ +#ifdef USE_NVRAM + tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e; + if ((dev->gpcntl & 0xc3) == 0x01) + tmp |= ncr53c8xx_serial_eeprom_read(dev); +#else + tmp = ((dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e) | 0x01; +#endif + ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp); + return tmp; + case 0x08: /* Revision ID */ + ncr53c8xx_log("NCR 810: Read REVID 00\n"); + return 0x00; + case 0xa: /* SSID */ + ncr53c8xx_log("NCR 810: Read SSID %02X\n", dev->ssid); + return dev->ssid; + case 0xb: /* SBCL */ + /* Bit 7 = REQ (SREQ/ status) + Bit 6 = ACK (SACK/ status) + Bit 5 = BSY (SBSY/ status) + Bit 4 = SEL (SSEL/ status) + Bit 3 = ATN (SATN/ status) + Bit 2 = MSG (SMSG/ status) + Bit 1 = C/D (SC_D/ status) + Bit 0 = I/O (SI_O/ status) */ + tmp = (dev->sstat1 & 7); + ncr53c8xx_log("NCR 810: Read SBCL %02X\n", tmp); + return tmp; /* For now, return the MSG, C/D, and I/O bits from SSTAT1. */ + case 0xc: /* DSTAT */ + tmp = dev->dstat | NCR_DSTAT_DFE; + if ((dev->istat & NCR_ISTAT_INTF) == 0) + dev->dstat = 0; + ncr53c8xx_update_irq(dev); + ncr53c8xx_log("NCR 810: Read DSTAT %02X\n", tmp); + return tmp; + case 0x0d: /* SSTAT0 */ + ncr53c8xx_log("NCR 810: Read SSTAT0 %02X\n", dev->sstat0); + return dev->sstat0; + case 0x0e: /* SSTAT1 */ + ncr53c8xx_log("NCR 810: Read SSTAT1 %02X\n", dev->sstat1); + return dev->sstat1; + case 0x0f: /* SSTAT2 */ + ncr53c8xx_log("NCR 810: Read SSTAT2 %02X\n", dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2); + return dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2; + CASE_GET_REG32(dsa, 0x10) + case 0x14: /* ISTAT */ + ncr53c8xx_log("NCR 810: Read ISTAT %02X\n", dev->istat); + tmp = dev->istat; + return tmp; + case 0x16: /* MBOX0 */ + if (dev->chip >= CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read MBOX0 %02X\n", dev->mbox0); + return dev->mbox0; + case 0x17: /* MBOX1 */ + if (dev->chip >= CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read MBOX1 %02X\n", dev->mbox1); + return dev->mbox1; + case 0x18: /* CTEST0 */ + ncr53c8xx_log("NCR 810: Read CTEST0 FF\n"); + return 0xff; + case 0x19: /* CTEST1 */ + ncr53c8xx_log("NCR 810: Read CTEST1 F0\n"); + return 0xf0; /* dma fifo empty */ + case 0x1a: /* CTEST2 */ + tmp = dev->ctest2 | NCR_CTEST2_DACK | NCR_CTEST2_CM; + if (dev->istat & NCR_ISTAT_SIGP) { + dev->istat &= ~NCR_ISTAT_SIGP; + tmp |= NCR_CTEST2_SIGP; + } + ncr53c8xx_log("NCR 810: Read CTEST2 %02X\n", tmp); + return tmp; + case 0x1b: /* CTEST3 */ + ncr53c8xx_log("NCR 810: Read CTEST3 %02X\n", + (dev->ctest3 & (0x08 | 0x02 | 0x01)) | ((dev->chip_rev & 0x0f) << 4)); + return (dev->ctest3 & (0x08 | 0x02 | 0x01)) | ((dev->chip_rev & 0x0f) << 4); + CASE_GET_REG32(temp, 0x1c) + case 0x20: /* DFIFO */ + ncr53c8xx_log("NCR 810: Read DFIFO 00\n"); + return 0; + case 0x21: /* CTEST4 */ + ncr53c8xx_log("NCR 810: Read CTEST4 %02X\n", dev->ctest4); + return dev->ctest4; + case 0x22: /* CTEST5 */ + ncr53c8xx_log("NCR 810: Read CTEST5 %02X\n", dev->ctest5); + return dev->ctest5; + case 0x23: /* CTEST6 */ + ncr53c8xx_log("NCR 810: Read CTEST6 00\n"); + return 0; + CASE_GET_REG24(dbc, 0x24) + case 0x27: /* DCMD */ + ncr53c8xx_log("NCR 810: Read DCMD %02X\n", dev->dcmd); + return dev->dcmd; + CASE_GET_REG32(dnad, 0x28) + CASE_GET_REG32(dsp, 0x2c) + CASE_GET_REG32(dsps, 0x30) + CASE_GET_REG32(scratcha, 0x34) + case 0x38: /* DMODE */ + ncr53c8xx_log("NCR 810: Read DMODE %02X\n", dev->dmode); + return dev->dmode; + case 0x39: /* DIEN */ + ncr53c8xx_log("NCR 810: Read DIEN %02X\n", dev->dien); + return dev->dien; + case 0x3a: /* SBR */ + ncr53c8xx_log("NCR 810: Read SBR %02X\n", dev->sbr); + return dev->sbr; + case 0x3b: /* DCNTL */ + ncr53c8xx_log("NCR 810: Read DCNTL %02X\n", dev->dcntl); + return dev->dcntl; + CASE_GET_REG32(adder, 0x3c) /* ADDER Output (Debug of relative jump address) */ + case 0x40: /* SIEN0 */ + ncr53c8xx_log("NCR 810: Read SIEN0 %02X\n", dev->sien0); + return dev->sien0; + case 0x41: /* SIEN1 */ + ncr53c8xx_log("NCR 810: Read SIEN1 %02X\n", dev->sien1); + return dev->sien1; + case 0x42: /* SIST0 */ + tmp = dev->sist0; + dev->sist0 = 0x00; + ncr53c8xx_update_irq(dev); + ncr53c8xx_log("NCR 810: Read SIST0 %02X\n", tmp); + return tmp; + case 0x43: /* SIST1 */ + tmp = dev->sist1; + dev->sist1 = 0x00; + ncr53c8xx_update_irq(dev); + ncr53c8xx_log("NCR 810: Read SIST1 %02X\n", tmp); + return tmp; + case 0x44: /* SLPAR */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read SLPAR %02X\n", dev->stime0); + return dev->slpar; + case 0x45: /* SWIDE */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read SWIDE %02X\n", dev->stime0); + return dev->swide; + case 0x46: /* MACNTL */ + ncr53c8xx_log("NCR 810: Read MACNTL 4F\n"); + return 0x4f; + case 0x47: /* GPCNTL */ + ncr53c8xx_log("NCR 810: Read GPCNTL %02X\n", dev->gpcntl); + return dev->gpcntl; + case 0x48: /* STIME0 */ + ncr53c8xx_log("NCR 810: Read STIME0 %02X\n", dev->stime0); + return dev->stime0; + case 0x4a: /* RESPID0 */ + if (dev->chip >= CHIP_825) + ncr53c8xx_log("NCR 810: Read RESPID0 %02X\n", dev->respid0); + else + ncr53c8xx_log("NCR 810: Read RESPID %02X\n", dev->respid0); + return dev->respid0; + case 0x4b: /* RESPID1 */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read RESPID1 %02X\n", dev->respid1); + return dev->respid1; + case 0x4c: /* STEST0 */ + ncr53c8xx_log("NCR 810: Read STEST0 %02X\n", dev->stest1); + return 0x00; + case 0x4d: /* STEST1 */ + ncr53c8xx_log("NCR 810: Read STEST1 %02X\n", dev->stest1); + return dev->stest1; + case 0x4e: /* STEST2 */ + ncr53c8xx_log("NCR 810: Read STEST2 %02X\n", dev->stest2); + return dev->stest2; + case 0x4f: /* STEST3 */ + ncr53c8xx_log("NCR 810: Read STEST3 %02X\n", dev->stest3); + return dev->stest3; + case 0x50: /* SIDL0 */ + /* This is needed by the linux drivers. We currently only update it + during the MSG IN phase. */ + if (dev->chip >= CHIP_825) + ncr53c8xx_log("NCR 810: Read SIDL0 %02X\n", dev->sidl0); + else + ncr53c8xx_log("NCR 810: Read SIDL %02X\n", dev->sidl0); + return dev->sidl0; + case 0x51: /* SIDL1 */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read SIDL1 %02X\n", dev->sidl1); + return dev->sidl1; + case 0x52: /* STEST4 */ + ncr53c8xx_log("NCR 810: Read STEST4 E0\n"); + return 0xe0; + case 0x58: /* SBDL */ + /* Some drivers peek at the data bus during the MSG IN phase. */ + if ((dev->sstat1 & PHASE_MASK) == PHASE_MI) { + ncr53c8xx_log("NCR 810: Read SBDL %02X\n", dev->msg[0]); + return dev->msg[0]; + } + ncr53c8xx_log("NCR 810: Read SBDL 00\n"); + return 0; + case 0x59: /* SBDL high */ + ncr53c8xx_log("NCR 810: Read SBDLH 00\n"); + return 0; + CASE_GET_REG32(scratchb, 0x5c) + CASE_GET_REG32_COND(scratchc, 0x60) + CASE_GET_REG32_COND(scratchd, 0x64) + CASE_GET_REG32_COND(scratche, 0x68) + CASE_GET_REG32_COND(scratchf, 0x6c) + CASE_GET_REG32_COND(scratchg, 0x70) + CASE_GET_REG32_COND(scratchh, 0x74) + CASE_GET_REG32_COND(scratchi, 0x78) + CASE_GET_REG32_COND(scratchj, 0x7c) + } + ncr53c8xx_log("readb 0x%x\n", offset); + return 0; + +#undef CASE_GET_REG24 +#undef CASE_GET_REG32 +} + + +static uint8_t +ncr53c8xx_io_readb(uint16_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + return ncr53c8xx_reg_readb(dev, addr & 0xff); +} + + +static uint16_t +ncr53c8xx_io_readw(uint16_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint16_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + return val; +} + + +static uint32_t +ncr53c8xx_io_readl(uint16_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint32_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + val |= ncr53c8xx_reg_readb(dev, addr + 2) << 16; + val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; + return val; +} + + +static void +ncr53c8xx_io_writeb(uint16_t addr, uint8_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + ncr53c8xx_reg_writeb(dev, addr & 0xff, val); +} + + +static void +ncr53c8xx_io_writew(uint16_t addr, uint16_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); +} + + +static void +ncr53c8xx_io_writel(uint16_t addr, uint32_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); +} + + +static void +ncr53c8xx_mmio_writeb(uint32_t addr, uint8_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + ncr53c8xx_reg_writeb(dev, addr & 0xff, val); +} + + +static void +ncr53c8xx_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); +} + + +static void +ncr53c8xx_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); +} + + +static uint8_t +ncr53c8xx_mmio_readb(uint32_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + return ncr53c8xx_reg_readb(dev, addr & 0xff); +} + + +static uint16_t +ncr53c8xx_mmio_readw(uint32_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint16_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + return val; +} + + +static uint32_t +ncr53c8xx_mmio_readl(uint32_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint32_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + val |= ncr53c8xx_reg_readb(dev, addr + 2) << 16; + val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; + + return val; +} + + +static void +ncr53c8xx_ram_writeb(uint32_t addr, uint8_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + dev->ram[addr & 0x0fff] = val; +} + + +static void +ncr53c8xx_ram_writew(uint32_t addr, uint16_t val, void *p) +{ + ncr53c8xx_ram_writeb(addr, val & 0xff, p); + ncr53c8xx_ram_writeb(addr + 1, (val >> 8) & 0xff, p); +} + + +static void +ncr53c8xx_ram_writel(uint32_t addr, uint32_t val, void *p) +{ + ncr53c8xx_ram_writeb(addr, val & 0xff, p); + ncr53c8xx_ram_writeb(addr + 1, (val >> 8) & 0xff, p); + ncr53c8xx_ram_writeb(addr + 2, (val >> 16) & 0xff, p); + ncr53c8xx_ram_writeb(addr + 3, (val >> 24) & 0xff, p); +} + + +static uint8_t +ncr53c8xx_ram_readb(uint32_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + return dev->ram[addr & 0x0fff]; +} + + +static uint16_t +ncr53c8xx_ram_readw(uint32_t addr, void *p) +{ + uint16_t val; + + val = ncr53c8xx_ram_readb(addr, p); + val |= ncr53c8xx_ram_readb(addr + 1, p) << 8; + + return val; +} + + +static uint32_t +ncr53c8xx_ram_readl(uint32_t addr, void *p) +{ + uint32_t val; + + val = ncr53c8xx_ram_readb(addr, p); + val |= ncr53c8xx_ram_readb(addr + 1, p) << 8; + val |= ncr53c8xx_ram_readb(addr + 2, p) << 16; + val |= ncr53c8xx_ram_readb(addr + 3, p) << 24; + + return val; +} + + +static void +ncr53c8xx_io_set(ncr53c8xx_t *dev, uint32_t base, uint16_t len) +{ + ncr53c8xx_log("NCR53c8xx: [PCI] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + ncr53c8xx_io_readb, ncr53c8xx_io_readw, ncr53c8xx_io_readl, + ncr53c8xx_io_writeb, ncr53c8xx_io_writew, ncr53c8xx_io_writel, dev); +} + + +static void +ncr53c8xx_io_remove(ncr53c8xx_t *dev, uint32_t base, uint16_t len) +{ + ncr53c8xx_log("NCR53c8xx: Removing I/O handler at %04X\n", base); + io_removehandler(base, len, + ncr53c8xx_io_readb, ncr53c8xx_io_readw, ncr53c8xx_io_readl, + ncr53c8xx_io_writeb, ncr53c8xx_io_writew, ncr53c8xx_io_writel, dev); +} + + +static void +ncr53c8xx_mem_init(ncr53c8xx_t *dev, uint32_t addr) +{ + mem_mapping_add(&dev->mmio_mapping, addr, 0x100, + ncr53c8xx_mmio_readb, ncr53c8xx_mmio_readw, ncr53c8xx_mmio_readl, + ncr53c8xx_mmio_writeb, ncr53c8xx_mmio_writew, ncr53c8xx_mmio_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +ncr53c8xx_ram_init(ncr53c8xx_t *dev, uint32_t addr) +{ + mem_mapping_add(&dev->ram_mapping, addr, 0x1000, + ncr53c8xx_ram_readb, ncr53c8xx_ram_readw, ncr53c8xx_ram_readl, + ncr53c8xx_ram_writeb, ncr53c8xx_ram_writew, ncr53c8xx_ram_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +ncr53c8xx_mem_set_addr(ncr53c8xx_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->mmio_mapping, base, 0x100); +} + + +static void +ncr53c8xx_ram_set_addr(ncr53c8xx_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->ram_mapping, base, 0x1000); +} + + +#ifdef USE_BIOS_BAR +static void +ncr53c8xx_bios_set_addr(ncr53c8xx_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->bios.mapping, base, 0x10000); +} +#endif + + +static void +ncr53c8xx_mem_disable(ncr53c8xx_t *dev) +{ + mem_mapping_disable(&dev->mmio_mapping); +} + + +static void +ncr53c8xx_ram_disable(ncr53c8xx_t *dev) +{ + mem_mapping_disable(&dev->ram_mapping); +} + + +#ifdef USE_BIOS_BAR +static void +ncr53c8xx_bios_disable(ncr53c8xx_t *dev) +{ + mem_mapping_disable(&dev->bios.mapping); +} +#endif + + +uint8_t ncr53c8xx_pci_regs[256]; +bar_t ncr53c8xx_pci_bar[4]; + + +static uint8_t +ncr53c8xx_pci_read(int func, int addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + ncr53c8xx_log("NCR53c8xx: Reading register %02X\n", addr & 0xff); + + if ((addr >= 0x80) && (addr <= 0xFF)) + return ncr53c8xx_reg_readb(dev, addr & 0x7F); + + switch (addr) { + case 0x00: + return 0x00; + case 0x01: + return 0x10; + case 0x02: + return dev->chip; + case 0x03: + return 0x00; + case 0x04: + return ncr53c8xx_pci_regs[0x04] & 0x57; /*Respond to IO and memory accesses*/ + case 0x05: + return ncr53c8xx_pci_regs[0x05] & 0x01; + case 0x07: + return 2; + case 0x08: + return dev->chip_rev; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*devubclass*/ + case 0x0B: + return 1; /*Class code*/ + case 0x0C: + case 0x0D: + return ncr53c8xx_pci_regs[addr]; + case 0x0E: + return 0; /*Header type */ + case 0x10: + return 1; /*I/O space*/ + case 0x11: + return ncr53c8xx_pci_bar[0].addr_regs[1]; + case 0x12: + return ncr53c8xx_pci_bar[0].addr_regs[2]; + case 0x13: + return ncr53c8xx_pci_bar[0].addr_regs[3]; + case 0x14: + return 0; /*Memory space*/ + case 0x15: + return ncr53c8xx_pci_bar[1].addr_regs[1]; + case 0x16: + return ncr53c8xx_pci_bar[1].addr_regs[2]; + case 0x17: + return ncr53c8xx_pci_bar[1].addr_regs[3]; + case 0x18: + return 0; /*Memory space*/ + case 0x19: + if (dev->chip < CHIP_825) + return 0; + return ncr53c8xx_pci_bar[2].addr_regs[1]; + case 0x1A: + if (dev->chip < CHIP_825) + return 0; + return ncr53c8xx_pci_bar[2].addr_regs[2]; + case 0x1B: + if (dev->chip < CHIP_825) + return 0; + return ncr53c8xx_pci_bar[2].addr_regs[3]; + case 0x2C: + return 0x00; + case 0x2D: + if (dev->chip >= CHIP_825) + return 0; + return 0x10; + case 0x2E: + if (dev->chip >= CHIP_825) + return 0; + return 0x01; + case 0x2F: + return 0x00; +#ifdef USE_BIOS_BAR + case 0x30: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[0]; + case 0x31: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[1]; + case 0x32: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[2]; + case 0x33: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[3]; +#endif + case 0x3C: + return dev->irq; + case 0x3D: + return PCI_INTA; + case 0x3E: + return 0x11; + case 0x3F: + return 0x40; + } + + return(0); +} + + +static void +ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint8_t valxor; + + ncr53c8xx_log("NCR53c8xx: Write value %02X to register %02X\n", val, addr & 0xff); + + if ((addr >= 0x80) && (addr <= 0xFF)) { + ncr53c8xx_reg_writeb(dev, addr & 0x7F, val); + return; + } + + switch (addr) + { + case 0x04: + valxor = (val & 0x57) ^ ncr53c8xx_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + ncr53c8xx_io_remove(dev, dev->PCIBase, 0x0100); + if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) + ncr53c8xx_io_set(dev, dev->PCIBase, 0x0100); + } + if (valxor & PCI_COMMAND_MEM) { + ncr53c8xx_mem_disable(dev); + if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) + ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); + if (dev->chip >= CHIP_825) { + ncr53c8xx_ram_disable(dev); + if ((dev->RAMBase != 0) && (val & PCI_COMMAND_MEM)) + ncr53c8xx_ram_set_addr(dev, dev->RAMBase); + } + } + ncr53c8xx_pci_regs[addr] = val & 0x57; + break; + + case 0x05: + ncr53c8xx_pci_regs[addr] = val & 0x01; + break; + + case 0x0C: + case 0x0D: + ncr53c8xx_pci_regs[addr] = val; + break; + + case 0x10: case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_io_remove(dev, dev->PCIBase, 0x0100); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[0].addr &= 0xff00; + dev->PCIBase = ncr53c8xx_pci_bar[0].addr; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New I/O base is %04X\n" , dev->PCIBase); + /* We're done, so get out of the here. */ + if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_IO) { + if (dev->PCIBase != 0) { + ncr53c8xx_io_set(dev, dev->PCIBase, 0x0100); + } + } + return; + + case 0x15: case 0x16: case 0x17: + /* MMIO Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_mem_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[1].addr &= 0xffffc000; + dev->MMIOBase = ncr53c8xx_pci_bar[1].addr & 0xffffc000; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New MMIO base is %08X\n" , dev->MMIOBase); + /* We're done, so get out of the here. */ + if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_MEM) { + if (dev->MMIOBase != 0) + ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); + } + return; + + case 0x19: case 0x1A: case 0x1B: + if (dev->chip < CHIP_825) + return; + /* RAM Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_ram_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[2].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[2].addr &= 0xffffc000; + dev->RAMBase = ncr53c8xx_pci_bar[2].addr & 0xffffc000; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New RAM base is %08X\n" , dev->RAMBase); + /* We're done, so get out of the here. */ + if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_MEM) { + if (dev->RAMBase != 0) + ncr53c8xx_ram_set_addr(dev, dev->RAMBase); + } + return; + +#ifdef USE_BIOS_BAR + case 0x30: case 0x31: case 0x32: case 0x33: + return; + if ((dev->chip < CHIP_825) || !dev->has_bios) + return; + /* BIOS Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_bios_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[3].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[3].addr &= 0xffff0001; + dev->BIOSBase = ncr53c8xx_pci_bar[3].addr & 0xffff0000; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New BIOS base is %08X\n" , dev->BIOSBase); + /* We're done, so get out of the here. */ + if (ncr53c8xx_pci_bar[3].addr & 0x00000001) + ncr53c8xx_bios_set_addr(dev, dev->BIOSBase); + return; +#endif + + case 0x3C: + ncr53c8xx_pci_regs[addr] = val; + dev->irq = val; + return; + } +} + + +static void * +ncr53c8xx_init(const device_t *info) +{ + ncr53c8xx_t *dev; + + dev = malloc(sizeof(ncr53c8xx_t)); + memset(dev, 0x00, sizeof(ncr53c8xx_t)); + + dev->chip_rev = 0; + // dev->pci_slot = pci_add_card(PCI_ADD_SCSI, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); + + ncr53c8xx_pci_bar[0].addr_regs[0] = 1; + ncr53c8xx_pci_bar[1].addr_regs[0] = 0; + dev->chip = info->local; + ncr53c8xx_pci_regs[0x04] = 3; + + ncr53c8xx_mem_init(dev, 0x0fffff00); + ncr53c8xx_mem_disable(dev); + + dev->has_bios = device_get_config_int("bios"); + if (dev->has_bios) + rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + if (dev->chip >= CHIP_825) { + + if (dev->chip == CHIP_875) { + dev->chip_rev = 0x04; + dev->nvr_path = L"ncr53c875.nvr"; + } else { + dev->chip_rev = 0x26; + dev->nvr_path = L"ncr53c825a.nvr"; + } + ncr53c8xx_pci_bar[2].addr_regs[0] = 0; + ncr53c8xx_pci_bar[3].addr = 0xffff0000; + /* Need to make it align on a 16k boundary as that's this emulator's + memory mapping granularity. */ + ncr53c8xx_ram_init(dev, 0x0fffc000); + ncr53c8xx_ram_disable(dev); + +#ifdef USE_BIOS_BAR + if (dev->has_bios) + ncr53c8xx_bios_disable(dev); +#endif + } else { + if (dev->has_bios) + rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + dev->nvr_path = L"ncr53c810.nvr"; + } + +#ifdef USE_NVRAM + /* Load the serial EEPROM. */ + ncr53c8xx_eeprom(dev, 0); +#endif + + ncr53c8xx_soft_reset(dev); + + timer_add(&dev->timer, ncr53c8xx_callback, dev, 0); + + return(dev); +} + + +static void +ncr53c8xx_close(void *priv) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; + + if (dev) { + free(dev); + dev = NULL; + } +} + + +static const device_config_t ncr53c8xx_pci_config[] = { + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + + +const device_t ncr53c810_pci_device = +{ + "NCR 53c810 (SCSI)", + DEVICE_PCI, + 0x01, + ncr53c8xx_init, ncr53c8xx_close, NULL, + NULL, NULL, NULL, + ncr53c8xx_pci_config +}; + +const device_t ncr53c825a_pci_device = +{ + "NCR 53c825A (SCSI)", + DEVICE_PCI, + CHIP_825, + ncr53c8xx_init, ncr53c8xx_close, NULL, + NULL, NULL, NULL, + ncr53c8xx_pci_config +}; + +const device_t ncr53c875_pci_device = +{ + "NCR 53c875 (SCSI)", + DEVICE_PCI, + CHIP_875, + ncr53c8xx_init, ncr53c8xx_close, NULL, + NULL, NULL, NULL, + ncr53c8xx_pci_config +}; diff --git a/src/scsi/scsi_ncr53c810.h b/src/scsi/scsi_ncr53c8xx.h similarity index 61% rename from src/scsi/scsi_ncr53c810.h rename to src/scsi/scsi_ncr53c8xx.h index 29666e935..e50e6d954 100644 --- a/src/scsi/scsi_ncr53c810.h +++ b/src/scsi/scsi_ncr53c8xx.h @@ -6,11 +6,11 @@ * * This file is part of the 86Box distribution. * - * Implementation of the NCR 53C810 SCSI Host Adapter made by - * NCR and later Symbios and LSI. This controller was designed - * for the PCI bus. + * Implementation of the NCR 53C810 and 53C875 SCSI Host + * Adapters made by NCR and later Symbios and LSI. These + * controllers were designed for the PCI bus. * - * Version: @(#)scsi_ncr53c810.c 1.0.1 2018/03/18 + * Version: @(#)scsi_ncr53c8xx.c 1.0.2 2018/10/30 * * Authors: TheCollector1995, * Miran Grca, @@ -21,11 +21,13 @@ * Copyright 2009-2018 Artyom Tarasenko. * Copyright 2017,2018 Miran Grca. */ -#ifndef SCSI_NCR5C3810_H -# define SCSI_NCR53C810_H +#ifndef SCSI_NCR53C8XX_H +# define SCSI_NCR53C8XX_H extern const device_t ncr53c810_pci_device; +extern const device_t ncr53c825a_pci_device; +extern const device_t ncr53c875_pci_device; -#endif /*SCSI_NCR53C810_H*/ +#endif /*SCSI_NCR53C8XX_H*/ diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index e8c334eab..cd4edbf79 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -11,7 +11,7 @@ * series of SCSI Host Adapters made by Mylex. * These controllers were designed for various buses. * - * Version: @(#)scsi_x54x.c 1.0.21 2018/06/12 + * Version: @(#)scsi_x54x.c 1.0.29 2019/05/16 * * Authors: TheCollector1995, * Miran Grca, @@ -30,6 +30,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../dma.h" #include "../pic.h" #include "../pci.h" @@ -38,9 +39,7 @@ #include "../rom.h" #include "../device.h" #include "../nvr.h" -#include "../timer.h" #include "../plat.h" -#include "../cpu/cpu.h" #include "scsi.h" #include "scsi_device.h" #include "scsi_aha154x.h" @@ -52,29 +51,25 @@ static void x54x_cmd_callback(void *priv); -static volatile -x54x_t *x54x_dev; - #ifdef ENABLE_X54X_LOG int x54x_do_log = ENABLE_X54X_LOG; -#endif static void x54x_log(const char *fmt, ...) { -#ifdef ENABLE_X54X_LOG va_list ap; if (x54x_do_log) { - pclog("In %s mode: ",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define x54x_log(fmt, ...) +#endif static void @@ -113,6 +108,8 @@ static void raise_irq(x54x_t *dev, int suppress, uint8_t Interrupt) { if (Interrupt & (INTR_MBIF | INTR_MBOA)) { + x54x_log("%s: RaiseInterrupt(): Interrupt=%02X %s\n", + dev->name, Interrupt, (! (dev->Interrupt & INTR_HACC)) ? "Immediate" : "Pending"); if (! (dev->Interrupt & INTR_HACC)) { dev->Interrupt |= Interrupt; /* Report now. */ } else { @@ -156,40 +153,56 @@ clear_irq(x54x_t *dev) static void target_check(uint8_t id) { - if (! scsi_device_valid(id)) { + if (! scsi_device_valid(&scsi_devices[id])) fatal("BIOS INT13 device on ID %02i has disappeared\n", id); - } } static uint8_t completion_code(uint8_t *sense) { - switch (sense[12]) { - case 0x00: - return(0x00); + uint8_t ret = 0xff; - case 0x20: - return(0x01); + switch (sense[12]) { + case ASC_NONE: + ret = 0x00; + break; + + case ASC_ILLEGAL_OPCODE: + case ASC_INV_FIELD_IN_CMD_PACKET: + case ASC_INV_FIELD_IN_PARAMETER_LIST: + case ASC_DATA_PHASE_ERROR: + ret = 0x01; + break; case 0x12: - case 0x21: - return(0x02); + case ASC_LBA_OUT_OF_RANGE: + ret = 0x02; + break; - case 0x27: - return(0x03); + case ASC_WRITE_PROTECTED: + ret = 0x03; + break; case 0x14: case 0x16: - return(0x04); + ret = 0x04; + break; + + case ASC_INCOMPATIBLE_FORMAT: + case ASC_ILLEGAL_MODE_FOR_THIS_TRACK: + ret = 0x0c; + break; case 0x10: case 0x11: - return(0x10); + ret = 0x10; + break; case 0x17: case 0x18: - return(0x11); + ret = 0x11; + break; case 0x01: case 0x03: @@ -211,37 +224,115 @@ completion_code(uint8_t *sense) case 0x47: case 0x48: case 0x49: - return(0x20); + ret = 0x20; + break; case 0x15: case 0x02: - return(0x40); + ret = 0x40; + break; - case 0x04: - case 0x28: + case 0x25: + ret = 0x80; + break; + + case ASC_NOT_READY: + case ASC_MEDIUM_MAY_HAVE_CHANGED: case 0x29: - case 0x2a: - return(0xaa); - - default: + case ASC_CAPACITY_DATA_CHANGED: + case ASC_MEDIUM_NOT_PRESENT: + ret = 0xaa; break; }; - return(0xff); + return(ret); } static uint8_t -x54x_bios_command_08(uint8_t id, uint8_t *buffer) +x54x_bios_scsi_command(scsi_device_t *dev, uint8_t *cdb, uint8_t *buf, int len, uint32_t addr) { - uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; - uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; - uint32_t len = 0; - int i, ret, sc; + dev->buffer_length = -1; - ret = scsi_device_read_capacity(id, cdb, rcbuf, &len); - sc = completion_code(scsi_device_sense(id)); - if (ret == 0) return(sc); + scsi_device_command_phase0(dev, cdb); + + if (dev->phase == SCSI_PHASE_STATUS) + return(completion_code(scsi_device_sense(dev))); + + if (len > 0) { + if (dev->phase == SCSI_PHASE_DATA_IN) { + if (buf) + memcpy(buf, dev->sc->temp_buffer, dev->buffer_length); + else + DMAPageWrite(addr, dev->sc->temp_buffer, dev->buffer_length); + } else if (dev->phase == SCSI_PHASE_DATA_OUT) { + if (buf) + memcpy(dev->sc->temp_buffer, buf, dev->buffer_length); + else + DMAPageRead(addr, dev->sc->temp_buffer, dev->buffer_length); + } + } + + scsi_device_command_phase1(dev); + + return (completion_code(scsi_device_sense(dev))); +} + + +static uint8_t +x54x_bios_read_capacity(scsi_device_t *sd, uint8_t *buf) +{ + uint8_t *cdb; + uint8_t ret; + + cdb = (uint8_t *) malloc(12); + memset(cdb, 0, 12); + cdb[0] = GPCMD_READ_CDROM_CAPACITY; + + memset(buf, 0, 8); + ret = x54x_bios_scsi_command(sd, cdb, buf, 8, 0); + + free(cdb); + + return(ret); +} + + +static uint8_t +x54x_bios_inquiry(scsi_device_t *sd, uint8_t *buf) +{ + uint8_t *cdb; + uint8_t ret; + + cdb = (uint8_t *) malloc(12); + memset(cdb, 0, 12); + cdb[0] = GPCMD_INQUIRY; + cdb[4] = 36; + + memset(buf, 0, 36); + ret = x54x_bios_scsi_command(sd, cdb, buf, 36, 0); + + free(cdb); + + return(ret); +} + + +static uint8_t +x54x_bios_command_08(scsi_device_t *sd, uint8_t *buffer) +{ + uint8_t *rcbuf; + uint8_t ret; + int i; + + memset(buffer, 0x00, 6); + + rcbuf = (uint8_t *) malloc(8); + ret = x54x_bios_read_capacity(sd, rcbuf); + if (ret) { + free(rcbuf); + return(ret); + } memset(buffer, 0x00, 6); for (i=0; i<4; i++) @@ -251,31 +342,49 @@ x54x_bios_command_08(uint8_t id, uint8_t *buffer) x54x_log("BIOS Command 0x08: %02X %02X %02X %02X %02X %02X\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + free(rcbuf); + return(0); } static int -x54x_bios_command_15(uint8_t id, uint8_t *buffer) +x54x_bios_command_15(scsi_device_t *sd, uint8_t *buffer) { - uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; - uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; - uint32_t len = 0; - int i, ret, sc; - - ret = scsi_device_read_capacity(id, cdb, rcbuf, &len); - sc = completion_code(scsi_device_sense(id)); + uint8_t *inqbuf, *rcbuf; + uint8_t ret; + int i; memset(buffer, 0x00, 6); - for (i=0; i<4; i++) - buffer[i] = (ret == 0) ? 0 : rcbuf[i]; - scsi_device_type_data(id, &(buffer[4]), &(buffer[5])); + inqbuf = (uint8_t *) malloc(36); + ret = x54x_bios_inquiry(sd, inqbuf); + if (ret) { + free(inqbuf); + return(ret); + } + + buffer[4] = inqbuf[0]; + buffer[5] = inqbuf[1]; + + rcbuf = (uint8_t *) malloc(8); + ret = x54x_bios_read_capacity(sd, rcbuf); + if (ret) { + free(rcbuf); + free(inqbuf); + return(ret); + } + + for (i = 0; i < 4; i++) + buffer[i] = rcbuf[i]; x54x_log("BIOS Command 0x15: %02X %02X %02X %02X %02X %02X\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); - return(sc); + free(rcbuf); + free(inqbuf); + + return(0); } @@ -283,12 +392,16 @@ x54x_bios_command_15(uint8_t id, uint8_t *buffer) static uint8_t x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) { - uint8_t cdb[12] = { 0,0,0,0,0,0,0,0,0,0,0,0 }; - scsi_device_t *dev; - uint32_t dma_address; + const int bios_cmd_to_scsi[18] = { 0, 0, GPCMD_READ_10, GPCMD_WRITE_10, GPCMD_VERIFY_10, 0, 0, + GPCMD_FORMAT_UNIT, 0, 0, 0, 0, GPCMD_SEEK_10, 0, 0, 0, + GPCMD_TEST_UNIT_READY, GPCMD_REZERO_UNIT }; + uint8_t cdb[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t *buf; + scsi_device_t *dev = NULL; + uint32_t dma_address = 0; uint32_t lba; int sector_len = cmd->secount; - uint8_t ret; + uint8_t ret = 0x00; if (islba) lba = lba32_blk(cmd); @@ -300,41 +413,39 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) if ((cmd->id > max_id) || (cmd->lun > 7)) { x54x_log("BIOS Target ID %i or LUN %i are above maximum\n", cmd->id, cmd->lun); - return(0x80); + ret = 0x80; } if (cmd->lun) { x54x_log("BIOS Target LUN is not 0\n"); - return(0x80); + ret = 0x80; } - /* Get pointer to selected device. */ - dev = &SCSIDevices[cmd->id]; - dev->BufferLength = 0; + if (!ret) { + /* Get pointer to selected device. */ + dev = &scsi_devices[cmd->id]; + dev->buffer_length = 0; - if (! scsi_device_present(cmd->id)) { - x54x_log("BIOS Target ID %i has no device attached\n", cmd->id); - return(0x80); + if (! scsi_device_present(dev)) { + x54x_log("BIOS Target ID %i has no device attached\n", cmd->id); + ret = 0x80; + } else { + if ((dev->type == SCSI_REMOVABLE_CDROM) && !(x54x->flags & X54X_CDROM_BOOT)) { + x54x_log("BIOS Target ID %i is CD-ROM on unsupported BIOS\n", cmd->id); + return(0x80); + } else { + dma_address = ADDR_TO_U32(cmd->dma_address); + + x54x_log("BIOS Data Buffer write: length %d, pointer 0x%04X\n", + sector_len, dma_address); + } + } } - if ((dev->LunType == SCSI_CDROM) && !x54x->cdrom_boot) { - x54x_log("BIOS Target ID %i is CD-ROM on unsupported BIOS\n", cmd->id); - return(0x80); - } - - dma_address = ADDR_TO_U32(cmd->dma_address); - - x54x_log("BIOS Data Buffer write: length %d, pointer 0x%04X\n", - sector_len, dma_address); - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - switch(cmd->command) { + if (!ret) switch(cmd->command) { case 0x00: /* Reset Disk System, in practice it's a nop */ - return(0); + ret = 0x00; + break; case 0x01: /* Read Status of Last Operation */ target_check(cmd->id); @@ -344,231 +455,89 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) * length for SCSI sense, and no command-specific * indication is given. */ - dev->BufferLength = 14; - dev->CmdBuffer = (uint8_t *)malloc(14); - memset(dev->CmdBuffer, 0x00, 14); - if (sector_len > 0) { x54x_log("BIOS DMA: Reading 14 bytes at %08X\n", dma_address); DMAPageWrite(dma_address, - scsi_device_sense(cmd->id), 14); - } - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + scsi_device_sense(dev), 14); } return(0); + break; case 0x02: /* Read Desired Sectors to Memory */ - target_check(cmd->id); - - dev->BufferLength = -1; - - cdb[0] = GPCMD_READ_10; - cdb[1] = (cmd->lun & 7) << 5; - cdb[2] = (lba >> 24) & 0xff; - cdb[3] = (lba >> 16) & 0xff; - cdb[4] = (lba >> 8) & 0xff; - cdb[5] = lba & 0xff; - cdb[7] = 0; - cdb[8] = sector_len; -#if 0 - x54x_log("BIOS CMD(READ, %08lx, %d)\n", lba, cmd->secount); -#endif - - scsi_device_command_phase0(cmd->id, cdb); - - if (dev->Phase == SCSI_PHASE_STATUS) - goto skip_read_phase1; - - dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); - - scsi_device_command_phase1(cmd->id); - if (sector_len > 0) { - x54x_log("BIOS DMA: Reading %i bytes at %08X\n", - dev->BufferLength, dma_address); - DMAPageWrite(dma_address, - dev->CmdBuffer, dev->BufferLength); - } - -skip_read_phase1: - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - return(completion_code(scsi_device_sense(cmd->id))); - case 0x03: /* Write Desired Sectors from Memory */ - target_check(cmd->id); - - dev->BufferLength = -1; - - cdb[0] = GPCMD_WRITE_10; - cdb[1] = (cmd->lun & 7) << 5; - cdb[2] = (lba >> 24) & 0xff; - cdb[3] = (lba >> 16) & 0xff; - cdb[4] = (lba >> 8) & 0xff; - cdb[5] = lba & 0xff; - cdb[7] = 0; - cdb[8] = sector_len; -#if 0 - x54x_log("BIOS CMD(WRITE, %08lx, %d)\n", lba, cmd->secount); -#endif - - scsi_device_command_phase0(cmd->id, cdb); - - if (dev->Phase == SCSI_PHASE_STATUS) - goto skip_write_phase1; - - dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); - - if (sector_len > 0) { - x54x_log("BIOS DMA: Reading %i bytes at %08X\n", - dev->BufferLength, dma_address); - DMAPageRead(dma_address, - dev->CmdBuffer, dev->BufferLength); - } - - scsi_device_command_phase1(cmd->id); - -skip_write_phase1: - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - return(completion_code(scsi_device_sense(cmd->id))); - case 0x04: /* Verify Desired Sectors */ - target_check(cmd->id); - - cdb[0] = GPCMD_VERIFY_10; - cdb[1] = (cmd->lun & 7) << 5; - cdb[2] = (lba >> 24) & 0xff; - cdb[3] = (lba >> 16) & 0xff; - cdb[4] = (lba >> 8) & 0xff; - cdb[5] = lba & 0xff; - cdb[7] = 0; - cdb[8] = sector_len; - - scsi_device_command_phase0(cmd->id, cdb); - - return(completion_code(scsi_device_sense(cmd->id))); - - case 0x05: /* Format Track, invalid since SCSI has no tracks */ -//FIXME: add a longer delay here --FvK - return(1); - - case 0x06: /* Identify SCSI Devices, in practice it's a nop */ -//FIXME: add a longer delay here --FvK - return(0); - - case 0x07: /* Format Unit */ - target_check(cmd->id); - - cdb[0] = GPCMD_FORMAT_UNIT; - cdb[1] = (cmd->lun & 7) << 5; - - scsi_device_command_phase0(cmd->id, cdb); - - return(completion_code(scsi_device_sense(cmd->id))); - - case 0x08: /* Read Drive Parameters */ - target_check(cmd->id); - - dev->BufferLength = 6; - dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); - memset(dev->CmdBuffer, 0x00, dev->BufferLength); - - ret = x54x_bios_command_08(cmd->id, dev->CmdBuffer); - - x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); - DMAPageWrite(dma_address, - dev->CmdBuffer, 4 /* dev->BufferLength */); - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - return(ret); - - case 0x09: /* Initialize Drive Pair Characteristics, in practice it's a nop */ -//FIXME: add a longer delay here --FvK - return(0); - case 0x0c: /* Seek */ target_check(cmd->id); - cdb[0] = GPCMD_SEEK_10; + cdb[0] = bios_cmd_to_scsi[cmd->command]; cdb[1] = (cmd->lun & 7) << 5; cdb[2] = (lba >> 24) & 0xff; cdb[3] = (lba >> 16) & 0xff; cdb[4] = (lba >> 8) & 0xff; cdb[5] = lba & 0xff; + if (cmd->command != 0x0c) + cdb[8] = sector_len; - scsi_device_command_phase0(cmd->id, cdb); - - return((dev->Status == SCSI_STATUS_OK) ? 1 : 0); - - case 0x0d: /* Alternate Disk Reset, in practice it's a nop */ -//FIXME: add a longer delay here --FvK - return(0); - - case 0x10: /* Test Drive Ready */ - target_check(cmd->id); - - cdb[0] = GPCMD_TEST_UNIT_READY; - cdb[1] = (cmd->lun & 7) << 5; - - scsi_device_command_phase0(cmd->id, cdb); - - return(completion_code(scsi_device_sense(cmd->id))); - - case 0x11: /* Recalibrate */ - target_check(cmd->id); - - cdb[0] = GPCMD_REZERO_UNIT; - cdb[1] = (cmd->lun & 7) << 5; - - scsi_device_command_phase0(cmd->id, cdb); - - return(completion_code(scsi_device_sense(cmd->id))); - - case 0x14: /* Controller Diagnostic */ -//FIXME: add a longer delay here --FvK - return(0); - - case 0x15: /* Read DASD Type */ - target_check(cmd->id); - - dev->BufferLength = 6; - dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); - memset(dev->CmdBuffer, 0x00, dev->BufferLength); - - ret = x54x_bios_command_15(cmd->id, dev->CmdBuffer); - - x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); - DMAPageWrite(dma_address, - dev->CmdBuffer, 4 /* dev->BufferLength */); - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - return(ret); + ret = x54x_bios_scsi_command(dev, cdb, NULL, sector_len, dma_address); + if (cmd->command == 0x0c) + ret = !!ret; + break; default: x54x_log("BIOS: Unimplemented command: %02X\n", cmd->command); - return(1); + case 0x05: /* Format Track, invalid since SCSI has no tracks */ + case 0x0a: /* ???? */ + case 0x0b: /* ???? */ + case 0x12: /* ???? */ + case 0x13: /* ???? */ +//FIXME: add a longer delay here --FvK + ret = 0x01; + break; + + case 0x06: /* Identify SCSI Devices, in practice it's a nop */ + case 0x09: /* Initialize Drive Pair Characteristics, in practice it's a nop */ + case 0x0d: /* Alternate Disk Reset, in practice it's a nop */ + case 0x0e: /* Read Sector Buffer */ + case 0x0f: /* Write Sector Buffer */ + case 0x14: /* Controller Diagnostic */ +//FIXME: add a longer delay here --FvK + ret = 0x00; + break; + + case 0x07: /* Format Unit */ + case 0x10: /* Test Drive Ready */ + case 0x11: /* Recalibrate */ + target_check(cmd->id); + + cdb[0] = bios_cmd_to_scsi[cmd->command]; + cdb[1] = (cmd->lun & 7) << 5; + + ret = x54x_bios_scsi_command(dev, cdb, NULL, sector_len, dma_address); + break; + + case 0x08: /* Read Drive Parameters */ + case 0x15: /* Read DASD Type */ + target_check(cmd->id); + + dev->buffer_length = 6; + + buf = (uint8_t *) malloc(6); + if (cmd->command == 0x08) + ret = x54x_bios_command_08(dev, buf); + else + ret = x54x_bios_command_15(dev, buf); + + x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); + DMAPageWrite(dma_address, buf, 4); + free(buf); + + break; } - x54x_log("BIOS Request complete\n"); + x54x_log("BIOS Request %02X complete: %02X\n", cmd->command, ret); + return(ret); } @@ -596,9 +565,9 @@ x54x_cmd_done(x54x_t *dev, int suppress) static void -x54x_add_to_period(int TransferLength) +x54x_add_to_period(x54x_t *dev, int TransferLength) { - x54x_dev->temp_period += (int64_t) TransferLength; + dev->temp_period += (uint64_t) TransferLength; } @@ -610,7 +579,7 @@ x54x_mbi_setup(x54x_t *dev, uint32_t CCBPointer, CCBU *CmdBlock, req->CCBPointer = CCBPointer; memcpy(&(req->CmdBlock), CmdBlock, sizeof(CCB32)); - req->Is24bit = dev->Mbx24bit; + req->Is24bit = !!(dev->flags & X54X_MBX_24BIT); req->HostStatus = HostStatus; req->TargetStatus = TargetStatus; req->MailboxCompletionCode = mbcc; @@ -629,7 +598,7 @@ x54x_ccb(x54x_t *dev) DMAPageWrite(req->CCBPointer + 0x000D, &(req->MailboxCompletionCode), 1); DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); - x54x_add_to_period(3); + x54x_add_to_period(dev, 3); if (dev->MailboxOutInterrupts) dev->ToRaise = INTR_MBOA | INTR_ANY; @@ -650,7 +619,7 @@ x54x_mbi(x54x_t *dev) uint32_t MailboxCompletionCode = req->MailboxCompletionCode; uint32_t Incoming; - Incoming = dev->MailboxInAddr + (dev->MailboxInPosCur * (dev->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); + Incoming = dev->MailboxInAddr + (dev->MailboxInPosCur * ((dev->flags & X54X_MBX_24BIT) ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); if (MailboxCompletionCode != MBI_NOT_FOUND) { CmdBlock->common.HostStatus = HostStatus; @@ -660,19 +629,19 @@ x54x_mbi(x54x_t *dev) x54x_log("CCB statuses rewritten (pointer %08X)\n", req->CCBPointer); DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); - x54x_add_to_period(2); + x54x_add_to_period(dev, 2); } else { x54x_log("Mailbox not found!\n"); } x54x_log("Host Status 0x%02X, Target Status 0x%02X\n",HostStatus,TargetStatus); - if (dev->Mbx24bit) { + if (dev->flags & X54X_MBX_24BIT) { U32_TO_ADDR(CCBPointer, req->CCBPointer); x54x_log("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); DMAPageWrite(Incoming, &(req->MailboxCompletionCode), 1); DMAPageWrite(Incoming + 1, (uint8_t *)&CCBPointer, 3); - x54x_add_to_period(4); + x54x_add_to_period(dev, 4); x54x_log("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); } else { x54x_log("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); @@ -680,7 +649,7 @@ x54x_mbi(x54x_t *dev) DMAPageWrite(Incoming + 4, &(req->HostStatus), 1); DMAPageWrite(Incoming + 5, &(req->TargetStatus), 1); DMAPageWrite(Incoming + 7, &(req->MailboxCompletionCode), 1); - x54x_add_to_period(7); + x54x_add_to_period(dev, 7); x54x_log("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); } @@ -695,13 +664,13 @@ x54x_mbi(x54x_t *dev) static void -x54x_rd_sge(int Is24bit, uint32_t Address, SGE32 *SG) +x54x_rd_sge(x54x_t *dev, int Is24bit, uint32_t Address, SGE32 *SG) { SGE SGE24; if (Is24bit) { DMAPageRead(Address, (uint8_t *)&SGE24, sizeof(SGE)); - x54x_add_to_period(sizeof(SGE)); + x54x_add_to_period(dev, sizeof(SGE)); /* Convert the 24-bit entries into 32-bit entries. */ x54x_log("Read S/G block: %06X, %06X\n", SGE24.Segment, SGE24.SegmentPointer); @@ -709,13 +678,13 @@ x54x_rd_sge(int Is24bit, uint32_t Address, SGE32 *SG) SG->SegmentPointer = ADDR_TO_U32(SGE24.SegmentPointer); } else { DMAPageRead(Address, (uint8_t *)SG, sizeof(SGE32)); - x54x_add_to_period(sizeof(SGE32)); + x54x_add_to_period(dev, sizeof(SGE32)); } } static int -x54x_get_length(Req_t *req, int Is24bit) +x54x_get_length(x54x_t *dev, Req_t *req, int Is24bit) { uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); @@ -740,7 +709,7 @@ x54x_get_length(Req_t *req, int Is24bit) if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { for (i = 0; i < DataLength; i += SGEntryLength) { - x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + x54x_rd_sge(dev, Is24bit, DataPointer + i, &SGBuffer); DataToTransfer += SGBuffer.Segment; } @@ -758,11 +727,11 @@ x54x_get_length(Req_t *req, int Is24bit) static void -x54x_set_residue(Req_t *req, int32_t TransferLength) +x54x_set_residue(x54x_t *dev, Req_t *req, int32_t TransferLength) { uint32_t Residue = 0; addr24 Residue24; - int32_t BufLen = SCSIDevices[req->TargetID].BufferLength; + int32_t BufLen = scsi_devices[req->TargetID].buffer_length; if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { @@ -776,11 +745,11 @@ x54x_set_residue(Req_t *req, int32_t TransferLength) if (req->Is24bit) { U32_TO_ADDR(Residue24, Residue); DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue24, 3); - x54x_add_to_period(3); + x54x_add_to_period(dev, 3); x54x_log("24-bit Residual data length for reading: %d\n", Residue); } else { DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue, 4); - x54x_add_to_period(4); + x54x_add_to_period(dev, 4); x54x_log("32-bit Residual data length for reading: %d\n", Residue); } } @@ -788,12 +757,12 @@ x54x_set_residue(Req_t *req, int32_t TransferLength) static void -x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) +x54x_buf_dma_transfer(x54x_t *dev, Req_t *req, int Is24bit, int TransferLength, int dir) { uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); uint32_t Address, i; - int32_t BufLen = SCSIDevices[req->TargetID].BufferLength; + int32_t BufLen = scsi_devices[req->TargetID].buffer_length; uint8_t read_from_host = (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))); uint8_t write_to_host = (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))); int sg_pos = 0; @@ -818,18 +787,18 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) checking its length, so do this procedure for both no read/write commands. */ if ((DataLength > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { for (i = 0; i < DataLength; i += SGEntryLength) { - x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + x54x_rd_sge(dev, Is24bit, DataPointer + i, &SGBuffer); Address = SGBuffer.SegmentPointer; DataToTransfer = MIN((int) SGBuffer.Segment, BufLen); if (read_from_host && DataToTransfer) { x54x_log("Reading S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); - DMAPageRead(Address, &(SCSIDevices[req->TargetID].CmdBuffer[sg_pos]), DataToTransfer); + DMAPageRead(Address, &(scsi_devices[req->TargetID].sc->temp_buffer[sg_pos]), DataToTransfer); } else if (write_to_host && DataToTransfer) { x54x_log("Writing S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); - DMAPageWrite(Address, &(SCSIDevices[req->TargetID].CmdBuffer[sg_pos]), DataToTransfer); + DMAPageWrite(Address, &(scsi_devices[req->TargetID].sc->temp_buffer[sg_pos]), DataToTransfer); } else x54x_log("No action on S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); @@ -849,39 +818,15 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { if (read_from_host) - DMAPageRead(Address, SCSIDevices[req->TargetID].CmdBuffer, MIN(BufLen, (int) DataLength)); + DMAPageRead(Address, scsi_devices[req->TargetID].sc->temp_buffer, MIN(BufLen, (int) DataLength)); else if (write_to_host) - DMAPageWrite(Address, SCSIDevices[req->TargetID].CmdBuffer, MIN(BufLen, (int) DataLength)); + DMAPageWrite(Address, scsi_devices[req->TargetID].sc->temp_buffer, MIN(BufLen, (int) DataLength)); } } } } -void -x54x_buf_alloc(uint8_t id, int length) -{ - if (SCSIDevices[id].CmdBuffer != NULL) { - free(SCSIDevices[id].CmdBuffer); - SCSIDevices[id].CmdBuffer = NULL; - } - - x54x_log("Allocating data buffer (%i bytes)\n", length); - SCSIDevices[id].CmdBuffer = (uint8_t *) malloc(length); - memset(SCSIDevices[id].CmdBuffer, 0, length); -} - - -void -x54x_buf_free(uint8_t id) -{ - if (SCSIDevices[id].CmdBuffer != NULL) { - free(SCSIDevices[id].CmdBuffer); - SCSIDevices[id].CmdBuffer = NULL; - } -} - - static uint8_t ConvertSenseLength(uint8_t RequestSenseLength) { @@ -914,14 +859,14 @@ SenseBufferPointer(Req_t *req) static void -SenseBufferFree(Req_t *req, int Copy) +SenseBufferFree(x54x_t *dev, Req_t *req, int Copy) { uint8_t SenseLength = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); uint32_t SenseBufferAddress; uint8_t temp_sense[256]; if (SenseLength && Copy) { - scsi_device_request_sense(req->TargetID, temp_sense, SenseLength); + scsi_device_request_sense(&scsi_devices[req->TargetID], temp_sense, SenseLength); /* * The sense address, in 32-bit mode, is located in the @@ -935,7 +880,7 @@ SenseBufferFree(Req_t *req, int Copy) x54x_log("SenseBufferFree(): Writing %i bytes at %08X\n", SenseLength, SenseBufferAddress); DMAPageWrite(SenseBufferAddress, temp_sense, SenseLength); - x54x_add_to_period(SenseLength); + x54x_add_to_period(dev, SenseLength); x54x_log("Sense data written to buffer: %02X %02X %02X\n", temp_sense[2], temp_sense[12], temp_sense[13]); } @@ -946,110 +891,143 @@ static void x54x_scsi_cmd(x54x_t *dev) { Req_t *req = &dev->Req; - uint8_t id, lun; - uint8_t temp_cdb[12]; - uint32_t i; - int target_cdb_len = 12; - int target_data_len; uint8_t bit24 = !!req->Is24bit; - int32_t *BufLen; - uint8_t phase; - uint32_t SenseBufferAddress; - int64_t p; + uint32_t i, target_cdb_len = 12; + scsi_device_t *sd; - id = req->TargetID; - lun = req->LUN; + sd = &scsi_devices[req->TargetID]; target_cdb_len = 12; - target_data_len = x54x_get_length(req, bit24); + dev->target_data_len = x54x_get_length(dev, req, bit24); - if (!scsi_device_valid(id)) - fatal("SCSI target on %02i has disappeared\n", id); + if (!scsi_device_valid(sd)) + fatal("SCSI target on %02i has disappeared\n", req->TargetID); - x54x_log("target_data_len = %i\n", target_data_len); + x54x_log("dev->target_data_len = %i\n", dev->target_data_len); - x54x_log("SCSI command being executed on ID %i, LUN %i\n", id, lun); + x54x_log("SCSI command being executed on ID %i, LUN %i\n", req->TargetID, req->LUN); x54x_log("SCSI CDB[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); for (i=1; iCmdBlock.common.CdbLength; i++) x54x_log("SCSI CDB[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); - memset(temp_cdb, 0x00, target_cdb_len); + memset(dev->temp_cdb, 0x00, target_cdb_len); if (req->CmdBlock.common.CdbLength <= target_cdb_len) { - memcpy(temp_cdb, req->CmdBlock.common.Cdb, + memcpy(dev->temp_cdb, req->CmdBlock.common.Cdb, req->CmdBlock.common.CdbLength); - x54x_add_to_period(req->CmdBlock.common.CdbLength); + x54x_add_to_period(dev, req->CmdBlock.common.CdbLength); } else { - memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); - x54x_add_to_period(target_cdb_len); + memcpy(dev->temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); + x54x_add_to_period(dev, target_cdb_len); } dev->Residue = 0; - BufLen = scsi_device_get_buf_len(id); - *BufLen = target_data_len; + sd->buffer_length = dev->target_data_len; - x54x_log("Command buffer: %08X\n", SCSIDevices[id].CmdBuffer); - - scsi_device_command_phase0(id, temp_cdb); - - phase = SCSIDevices[id].Phase; + scsi_device_command_phase0(sd, dev->temp_cdb); + dev->scsi_cmd_phase = sd->phase; x54x_log("Control byte: %02X\n", (req->CmdBlock.common.ControlByte == 0x03)); - if (phase != SCSI_PHASE_STATUS) { - if ((temp_cdb[0] == 0x03) && (req->CmdBlock.common.ControlByte == 0x03)) { - /* Request sense in non-data mode - sense goes to sense buffer. */ - *BufLen = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); - x54x_buf_alloc(id, *BufLen); - scsi_device_command_phase1(id); - if ((SCSIDevices[id].Status != SCSI_STATUS_OK) && (*BufLen > 0)) { - SenseBufferAddress = SenseBufferPointer(req); - DMAPageWrite(SenseBufferAddress, SCSIDevices[id].CmdBuffer, *BufLen); - x54x_add_to_period(*BufLen); - } - } else { - p = scsi_device_get_callback(id); - if (p <= 0LL) - x54x_add_to_period(*BufLen); + if (dev->scsi_cmd_phase == SCSI_PHASE_STATUS) + dev->callback_sub_phase = 3; + else + dev->callback_sub_phase = 2; + + x54x_log("scsi_devices[%02i].Status = %02X\n", id, sd->status); +} + + +static void +x54x_scsi_cmd_phase1(x54x_t *dev) +{ + Req_t *req = &dev->Req; + double p; + uint8_t bit24 = !!req->Is24bit; + scsi_device_t *sd; + + sd = &scsi_devices[req->TargetID]; + + if (dev->scsi_cmd_phase != SCSI_PHASE_STATUS) { + if ((dev->temp_cdb[0] != 0x03) || (req->CmdBlock.common.ControlByte != 0x03)) { + p = scsi_device_get_callback(sd); + if (p <= 0.0) + x54x_add_to_period(dev, sd->buffer_length); else dev->media_period += p; - x54x_buf_alloc(id, MIN(target_data_len, *BufLen)); - if (phase == SCSI_PHASE_DATA_OUT) - x54x_buf_dma_transfer(req, bit24, target_data_len, 1); - scsi_device_command_phase1(id); - if (phase == SCSI_PHASE_DATA_IN) - x54x_buf_dma_transfer(req, bit24, target_data_len, 0); - - SenseBufferFree(req, (SCSIDevices[id].Status != SCSI_STATUS_OK)); + x54x_buf_dma_transfer(dev, req, bit24, dev->target_data_len, (dev->scsi_cmd_phase == SCSI_PHASE_DATA_OUT)); + scsi_device_command_phase1(sd); } + } + + dev->callback_sub_phase = 3; + x54x_log("scsi_devices[%02i].Status = %02X\n", req->TargetID, sd->status); +} + + +static void +x54x_request_sense(x54x_t *dev) +{ + Req_t *req = &dev->Req; + uint32_t SenseBufferAddress; + scsi_device_t *sd; + + sd = &scsi_devices[req->TargetID]; + + if (dev->scsi_cmd_phase != SCSI_PHASE_STATUS) { + if ((dev->temp_cdb[0] == 0x03) && (req->CmdBlock.common.ControlByte == 0x03)) { + /* Request sense in non-data mode - sense goes to sense buffer. */ + sd->buffer_length = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + if ((sd->status != SCSI_STATUS_OK) && (sd->buffer_length > 0)) { + SenseBufferAddress = SenseBufferPointer(req); + DMAPageWrite(SenseBufferAddress, scsi_devices[req->TargetID].sc->temp_buffer, sd->buffer_length); + x54x_add_to_period(dev, sd->buffer_length); + } + scsi_device_command_phase1(sd); + } else + SenseBufferFree(dev, req, (sd->status != SCSI_STATUS_OK)); } else - SenseBufferFree(req, (SCSIDevices[id].Status != SCSI_STATUS_OK)); + SenseBufferFree(dev, req, (sd->status != SCSI_STATUS_OK)); - x54x_set_residue(req, target_data_len); - - x54x_buf_free(id); + x54x_set_residue(dev, req, dev->target_data_len); x54x_log("Request complete\n"); - if (SCSIDevices[id].Status == SCSI_STATUS_OK) { + if (sd->status == SCSI_STATUS_OK) { x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); - } else if (SCSIDevices[id].Status == SCSI_STATUS_CHECK_CONDITION) { + } else if (sd->status == SCSI_STATUS_CHECK_CONDITION) { x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); } - x54x_log("SCSIDevices[%02i].Status = %02X\n", id, SCSIDevices[id].Status); + dev->callback_sub_phase = 4; + x54x_log("scsi_devices[%02i].Status = %02X\n", req->TargetID, sd->status); +} + + +static void +x54x_mbo_free(x54x_t *dev) +{ + uint8_t CmdStatus = MBO_FREE; + uint32_t CodeOffset = 0; + + CodeOffset = (dev->flags & X54X_MBX_24BIT) ? 0 : 7; + + x54x_log("x54x_mbo_free(): Writing %i bytes at %08X\n", sizeof(CmdStatus), dev->Outgoing + CodeOffset); + DMAPageWrite(dev->Outgoing + CodeOffset, &CmdStatus, 1); } static void x54x_notify(x54x_t *dev) { + x54x_mbo_free(dev); + if (dev->MailboxIsBIOS) x54x_ccb(dev); - else + else x54x_mbi(dev); } @@ -1059,38 +1037,38 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) { Req_t *req = &dev->Req; uint8_t id, lun; + scsi_device_t *sd; /* Fetch data from the Command Control Block. */ DMAPageRead(CCBPointer, (uint8_t *)&req->CmdBlock, sizeof(CCB32)); - x54x_add_to_period(sizeof(CCB32)); + x54x_add_to_period(dev, sizeof(CCB32)); - req->Is24bit = dev->Mbx24bit; + req->Is24bit = !!(dev->flags & X54X_MBX_24BIT); req->CCBPointer = CCBPointer; - req->TargetID = dev->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; - req->LUN = dev->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; + req->TargetID = req->Is24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; + req->LUN = req->Is24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; id = req->TargetID; + sd = &scsi_devices[id]; lun = req->LUN; if ((id > dev->max_id) || (lun > 7)) { x54x_log("SCSI Target ID %i or LUN %i is not valid\n",id,lun); x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); - x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); - x54x_notify(dev); + dev->callback_sub_phase = 4; return; } x54x_log("Scanning SCSI Target ID %i\n", id); - SCSIDevices[id].Status = SCSI_STATUS_OK; + sd->status = SCSI_STATUS_OK; /* If there is no device at ID:0, timeout the selection - the LUN is then checked later. */ - if (! scsi_device_present(id)) { + if (! scsi_device_present(sd)) { x54x_log("SCSI Target ID %i and LUN %i have no device attached\n",id,lun); x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); - x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); - x54x_notify(dev); + dev->callback_sub_phase = 4; } else { x54x_log("SCSI Target ID %i detected and working\n", id); @@ -1101,17 +1079,15 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) x54x_log("Invalid opcode: %02X\n", req->CmdBlock.common.ControlByte); x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_INVALID_OP_CODE, SCSI_STATUS_OK, MBI_ERROR); - x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); - x54x_notify(dev); + dev->callback_sub_phase = 4; return; } if (req->CmdBlock.common.Opcode == 0x81) { x54x_log("Bus reset opcode\n"); - scsi_device_reset(id); + scsi_device_reset(sd); x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); - x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); - x54x_notify(dev); + dev->callback_sub_phase = 4; return; } @@ -1119,16 +1095,11 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) x54x_log("Invalid control byte: %02X\n", req->CmdBlock.common.ControlByte); x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_INVALID_DIRECTION, SCSI_STATUS_OK, MBI_ERROR); - x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); - x54x_notify(dev); + dev->callback_sub_phase = 4; return; } - x54x_log("%s: Callback: Process SCSI request\n", dev->name); - x54x_scsi_cmd(dev); - - x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); - x54x_notify(dev); + dev->callback_sub_phase = 1; } } @@ -1140,12 +1111,11 @@ x54x_req_abort(x54x_t *dev, uint32_t CCBPointer) /* Fetch data from the Command Control Block. */ DMAPageRead(CCBPointer, (uint8_t *)&CmdBlock, sizeof(CCB32)); - x54x_add_to_period(sizeof(CCB32)); + x54x_add_to_period(dev, sizeof(CCB32)); x54x_mbi_setup(dev, CCBPointer, &CmdBlock, 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); - x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); - x54x_notify(dev); + dev->callback_sub_phase = 4; } @@ -1166,10 +1136,10 @@ x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) Cur = dev->MailboxOutPosCur; } - if (dev->Mbx24bit) { + if (dev->flags & X54X_MBX_24BIT) { Outgoing = Addr + (Cur * sizeof(Mailbox_t)); DMAPageRead(Outgoing, (uint8_t *)&MailboxOut, sizeof(Mailbox_t)); - x54x_add_to_period(sizeof(Mailbox_t)); + x54x_add_to_period(dev, sizeof(Mailbox_t)); ccbp = *(uint32_t *) &MailboxOut; Mailbox32->CCBPointer = (ccbp >> 24) | ((ccbp >> 8) & 0xff00) | ((ccbp << 8) & 0xff0000); @@ -1178,7 +1148,7 @@ x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) Outgoing = Addr + (Cur * sizeof(Mailbox32_t)); DMAPageRead(Outgoing, (uint8_t *)Mailbox32, sizeof(Mailbox32_t)); - x54x_add_to_period(sizeof(Mailbox32_t)); + x54x_add_to_period(dev, sizeof(Mailbox32_t)); } return(Outgoing); @@ -1189,13 +1159,9 @@ uint8_t x54x_mbo_process(x54x_t *dev) { Mailbox32_t mb32; - uint32_t Outgoing; - uint8_t CmdStatus = MBO_FREE; - uint32_t CodeOffset = 0; - CodeOffset = dev->Mbx24bit ? 0 : 7; - - Outgoing = x54x_mbo(dev, &mb32); + dev->ToRaise = 0; + dev->Outgoing = x54x_mbo(dev, &mb32); if (mb32.u.out.ActionCode == MBO_START) { x54x_log("Start Mailbox Command\n"); @@ -1208,17 +1174,10 @@ x54x_mbo_process(x54x_t *dev) } */ if ((mb32.u.out.ActionCode == MBO_START) || (!dev->MailboxIsBIOS && (mb32.u.out.ActionCode == MBO_ABORT))) { - /* We got the mailbox, mark it as free in the guest. */ - x54x_log("x54x_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); - DMAPageWrite(Outgoing + CodeOffset, &CmdStatus, 1); - x54x_add_to_period(1); - - if (dev->ToRaise) - raise_irq(dev, 0, dev->ToRaise); - + /* We got the mailbox, decrease the number of pending requests. */ if (dev->MailboxIsBIOS) dev->BIOSMailboxReq--; - else + else dev->MailboxReq--; return(1); @@ -1255,11 +1214,9 @@ x54x_do_mail(x54x_t *dev) } } else { /* Strict round robin mode - only process the current mailbox and advance the pointer if successful. */ -x54x_do_mail_again: if (x54x_mbo_process(dev)) { dev->MailboxOutPosCur++; dev->MailboxOutPosCur %= dev->MailboxCount; - goto x54x_do_mail_again; } } } @@ -1273,40 +1230,69 @@ static void x54x_cmd_callback(void *priv) { double period; - x54x_t *dev = (x54x_t *) x54x_dev; + x54x_t *dev = (x54x_t *) priv; int mailboxes_present, bios_mailboxes_present; mailboxes_present = (!(dev->Status & STAT_INIT) && dev->MailboxInit && dev->MailboxReq); bios_mailboxes_present = (dev->ven_callback && dev->BIOSMailboxInit && dev->BIOSMailboxReq); - if (!mailboxes_present && !bios_mailboxes_present) { - /* If we did not get anything, do nothing and wait 10 us. */ - dev->timer_period = 10LL * TIMER_USEC; - return; + dev->temp_period = 0; + dev->media_period = 0.0; + + switch (dev->callback_sub_phase) { + case 0: + /* Sub-phase 0 - Look for mailbox. */ + if ((dev->callback_phase == 0) && mailboxes_present) + x54x_do_mail(dev); + else if ((dev->callback_phase == 1) && bios_mailboxes_present) + dev->ven_callback(dev); + + if (dev->ven_callback && (dev->callback_sub_phase == 0)) + dev->callback_phase ^= 1; + break; + case 1: + /* Sub-phase 1 - Do SCSI command phase 0. */ + x54x_log("%s: Callback: Process SCSI request\n", dev->name); + x54x_scsi_cmd(dev); + break; + case 2: + /* Sub-phase 2 - Do SCSI command phase 1. */ + x54x_log("%s: Callback: Process SCSI request\n", dev->name); + x54x_scsi_cmd_phase1(dev); + break; + case 3: + /* Sub-phase 3 - Request sense. */ + x54x_log("%s: Callback: Process SCSI request\n", dev->name); + x54x_request_sense(dev); + break; + case 4: + /* Sub-phase 4 - Notify. */ + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + + /* Go back to lookup phase. */ + dev->callback_sub_phase = 0; + + /* Toggle normal/BIOS mailbox - only has an effect if both types of mailboxes + have been initialized. */ + if (dev->ven_callback) + dev->callback_phase ^= 1; + + /* Add to period and raise the IRQ if needed. */ + x54x_add_to_period(dev, 1); + + if (dev->ToRaise) + raise_irq(dev, 0, dev->ToRaise); + break; + default: + x54x_log("Invalid sub-phase: %02X\n", dev->callback_sub_phase); + break; } - dev->temp_period = dev->media_period = 0LL; - - if (!mailboxes_present) { - /* Do only BIOS mailboxes. */ - dev->ven_callback(dev); - } else if (!bios_mailboxes_present) { - /* Do only normal mailboxes. */ - x54x_do_mail(dev); - } else { - /* Do both kinds of mailboxes. */ - if (dev->callback_phase) - dev->ven_callback(dev); - else - x54x_do_mail(dev); - - dev->callback_phase = (dev->callback_phase + 1) & 0x01; - } - - period = (1000000.0 / x54x_dev->ha_bps) * ((double) TIMER_USEC) * ((double) dev->temp_period); - dev->timer_period = dev->media_period + ((int64_t) period) + (40LL * TIMER_USEC); - x54x_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods)\n", dev->timer_period, dev->temp_period); + period = (1000000.0 / dev->ha_bps) * ((double) dev->temp_period); + timer_on(&dev->timer, dev->media_period + period + 10.0, 0); + x54x_log("Temporary period: %lf us (%" PRIi64 " periods)\n", dev->timer.period, dev->temp_period); } @@ -1333,7 +1319,7 @@ x54x_in(uint16_t port, void *priv) break; case 2: - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) ret = dev->Interrupt; else ret = dev->Interrupt & ~0x70; @@ -1350,7 +1336,7 @@ x54x_in(uint16_t port, void *priv) 6 Not checked 7 Not checked */ - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) ret = dev->Geometry; else { switch(dev->Geometry) { @@ -1367,9 +1353,6 @@ x54x_in(uint16_t port, void *priv) break; } -#if 0 - x54x_log("%s: Read Port 0x%02X, Value %02X\n", dev->name, port, ret); -#endif return(ret); } @@ -1389,7 +1372,7 @@ x54x_inl(uint16_t port, void *priv) static uint8_t -x54x_read(uint32_t port, void *priv) +x54x_readb(uint32_t port, void *priv) { return(x54x_in(port & 3, priv)); } @@ -1415,8 +1398,6 @@ x54x_reset_poll(void *priv) x54x_t *dev = (x54x_t *)priv; dev->Status = STAT_INIT | STAT_IDLE; - - dev->ResetCB = 0LL; } @@ -1426,15 +1407,18 @@ x54x_reset(x54x_t *dev) int i; clear_irq(dev); - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) dev->Geometry = 0x80; else dev->Geometry = 0x00; dev->callback_phase = 0; + dev->callback_sub_phase = 0; + timer_stop(&dev->timer); + timer_set_delay_u64(&dev->timer, (uint64_t) (dev->timer.period * ((double) TIMER_USEC))); dev->Command = 0xFF; dev->CmdParam = 0; dev->CmdParamLeft = 0; - dev->Mbx24bit = 1; + dev->flags |= X54X_MBX_24BIT; dev->MailboxInPosCur = 0; dev->MailboxOutInterrupts = 0; dev->PendingInterrupt = 0; @@ -1444,7 +1428,7 @@ x54x_reset(x54x_t *dev) /* Reset all devices on controller reset. */ for (i = 0; i < 16; i++) - scsi_device_reset(i); + scsi_device_reset(&scsi_devices[i]); if (dev->ven_reset) dev->ven_reset(dev); @@ -1463,10 +1447,9 @@ x54x_reset_ctrl(x54x_t *dev, uint8_t Reset) if (Reset) { dev->Status = STAT_STST; - dev->ResetCB = X54X_RESET_DURATION_US * TIMER_USEC; - } else { + timer_set_delay_u64(&dev->ResetCB, X54X_RESET_DURATION_US * TIMER_USEC); + } else dev->Status = STAT_INIT | STAT_IDLE; - } } @@ -1494,19 +1477,19 @@ x54x_out(uint16_t port, uint8_t val, void *priv) reset = (val & CTRL_HRST); x54x_log("Reset completed = %x\n", reset); x54x_reset_ctrl(dev, reset); - x54x_log("Controller reset: "); + x54x_log("Controller reset\n"); break; } if (val & CTRL_SCRST) { /* Reset all devices on SCSI bus reset. */ for (i = 0; i < 16; i++) - scsi_device_reset(i); + scsi_device_reset(&scsi_devices[i]); } if (val & CTRL_IRST) { clear_irq(dev); - x54x_log("Interrupt reset: "); + x54x_log("Interrupt reset\n"); } break; @@ -1514,7 +1497,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) /* Fast path for the mailbox execution command. */ if ((val == CMD_START_SCSI) && (dev->Command == 0xff)) { dev->MailboxReq++; - x54x_log("Start SCSI command: "); + x54x_log("Start SCSI command\n"); return; } if (dev->ven_fast_cmds) { @@ -1581,7 +1564,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) break; case CMD_MBINIT: /* mailbox initialization */ - dev->Mbx24bit = 1; + dev->flags |= X54X_MBX_24BIT; mbi = (MailboxInit_t *)dev->CmdBuf; @@ -1603,12 +1586,12 @@ x54x_out(uint16_t port, uint8_t val, void *priv) case CMD_BIOSCMD: /* execute BIOS */ cmd = (BIOSCMD *)dev->CmdBuf; - if (!dev->lba_bios) { + if (!(dev->flags & X54X_LBA_BIOS)) { /* 1640 uses LBA. */ cyl = ((cmd->u.chs.cyl & 0xff) << 8) | ((cmd->u.chs.cyl >> 8) & 0xff); cmd->u.chs.cyl = cyl; } - if (dev->lba_bios) { + if (dev->flags & X54X_LBA_BIOS) { /* 1640 uses LBA. */ x54x_log("BIOS LBA=%06lx (%lu)\n", lba32_blk(cmd), @@ -1621,7 +1604,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) cmd->u.chs.head, cmd->u.chs.sec); } - dev->DataBuf[0] = x54x_bios_command(dev, dev->max_id, cmd, (dev->lba_bios)?1:0); + dev->DataBuf[0] = x54x_bios_command(dev, dev->max_id, cmd, !!(dev->flags & X54X_LBA_BIOS)); x54x_log("BIOS Completion/Status Code %x\n", dev->DataBuf[0]); dev->DataReplyLeft = 1; break; @@ -1678,7 +1661,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) if (i == host_id) continue; /* TODO: Query device for LUN's. */ - if (scsi_device_present(i)) + if (scsi_device_present(&scsi_devices[i])) dev->DataBuf[i] |= 1; } dev->DataReplyLeft = i; @@ -1686,9 +1669,9 @@ x54x_out(uint16_t port, uint8_t val, void *priv) case CMD_RETCONF: /* return Configuration */ if (dev->ven_get_dma) - dev->DataBuf[0] = (1<ven_get_dma(dev)); + dev->DataBuf[0] = (1 << dev->ven_get_dma(dev)); else - dev->DataBuf[0] = (1<DmaChannel); + dev->DataBuf[0] = (1 << dev->DmaChannel); if (dev->ven_get_irq) irq = dev->ven_get_irq(dev); @@ -1708,7 +1691,6 @@ x54x_out(uint16_t port, uint8_t val, void *priv) break; case CMD_RETSETUP: /* return Setup */ - { ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; memset(ReplyISI, 0x00, sizeof(ReplyInquireSetupInformation)); @@ -1718,14 +1700,12 @@ x54x_out(uint16_t port, uint8_t val, void *priv) ReplyISI->cMailbox = dev->MailboxCount; U32_TO_ADDR(ReplyISI->MailboxAddress, dev->MailboxOutAddr); - if (dev->get_ven_data) { + if (dev->get_ven_data) dev->get_ven_data(dev); - } dev->DataReplyLeft = dev->CmdBuf[0]; x54x_log("Return Setup Information: %d (length: %i)\n", dev->CmdBuf[0], sizeof(ReplyInquireSetupInformation)); - } - break; + break; case CMD_ECHO: /* ECHO data */ dev->DataBuf[0] = dev->CmdBuf[0]; @@ -1776,12 +1756,12 @@ x54x_out(uint16_t port, uint8_t val, void *priv) break; case 2: - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) dev->Interrupt = val; break; case 3: - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) dev->Geometry = val; break; } @@ -1803,7 +1783,7 @@ x54x_outl(uint16_t port, uint32_t val, void *priv) static void -x54x_write(uint32_t port, uint8_t val, void *priv) +x54x_writeb(uint32_t port, uint8_t val, void *priv) { x54x_out(port & 3, val, priv); } @@ -1823,17 +1803,24 @@ x54x_writel(uint32_t port, uint32_t val, void *priv) } -void -x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len) +static int +x54x_is_32bit(x54x_t *dev) { int bit32 = 0; if (dev->bus & DEVICE_PCI) bit32 = 1; - else if ((dev->bus & DEVICE_MCA) && dev->bit32) + else if ((dev->bus & DEVICE_MCA) && (dev->flags & X54X_32BIT)) bit32 = 1; - if (bit32) { + return bit32; +} + + +void +x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len) +{ + if (x54x_is_32bit(dev)) { x54x_log("x54x: [PCI] Setting I/O handler at %04X\n", base); io_sethandler(base, len, x54x_in, x54x_inw, x54x_inl, @@ -1850,16 +1837,9 @@ x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len) void x54x_io_remove(x54x_t *dev, uint32_t base, uint8_t len) { - int bit32 = 0; - - if (dev->bus & DEVICE_PCI) - bit32 = 1; - else if ((dev->bus & DEVICE_MCA) && dev->bit32) - bit32 = 1; - x54x_log("x54x: Removing I/O handler at %04X\n", base); - if (bit32) { + if (x54x_is_32bit(dev)) { io_removehandler(base, len, x54x_in, x54x_inw, x54x_inl, x54x_out, x54x_outw, x54x_outl, dev); @@ -1874,22 +1854,15 @@ x54x_io_remove(x54x_t *dev, uint32_t base, uint8_t len) void x54x_mem_init(x54x_t *dev, uint32_t addr) { - int bit32 = 0; - - if (dev->bus & DEVICE_PCI) - bit32 = 1; - else if ((dev->bus & DEVICE_MCA) && dev->bit32) - bit32 = 1; - - if (bit32) { + if (x54x_is_32bit(dev)) { mem_mapping_add(&dev->mmio_mapping, addr, 0x20, - x54x_read, x54x_readw, x54x_readl, - x54x_write, x54x_writew, x54x_writel, + x54x_readb, x54x_readw, x54x_readl, + x54x_writeb, x54x_writew, x54x_writel, NULL, MEM_MAPPING_EXTERNAL, dev); } else { mem_mapping_add(&dev->mmio_mapping, addr, 0x20, - x54x_read, x54x_readw, NULL, - x54x_write, x54x_writew, NULL, + x54x_readb, x54x_readw, NULL, + x54x_writeb, x54x_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, dev); } } @@ -1930,12 +1903,11 @@ x54x_init(const device_t *info) dev->bus = info->flags; dev->callback_phase = 0; - - timer_add(x54x_reset_poll, &dev->ResetCB, &dev->ResetCB, dev); - dev->timer_period = 10LL * TIMER_USEC; - timer_add(x54x_cmd_callback, &dev->timer_period, TIMER_ALWAYS_ENABLED, dev); - - x54x_dev = dev; + + timer_add(&dev->ResetCB, x54x_reset_poll, dev, 0); + timer_add(&dev->timer, x54x_cmd_callback, dev, 1); + dev->timer.period = 10.0; + timer_set_delay_u64(&dev->timer, (uint64_t) (dev->timer.period * ((double) TIMER_USEC))); return(dev); } @@ -1947,10 +1919,11 @@ x54x_close(void *priv) x54x_t *dev = (x54x_t *)priv; if (dev) { - x54x_dev = NULL; - /* Tell the timer to terminate. */ - dev->timer_period = 0LL; + timer_stop(&dev->timer); + + /* Also terminate the reset callback timer. */ + timer_disable(&dev->ResetCB); dev->MailboxInit = dev->BIOSMailboxInit = 0; dev->MailboxCount = dev->BIOSMailboxCount = 0; @@ -1975,6 +1948,6 @@ x54x_device_reset(void *priv) x54x_reset_ctrl(dev, 1); - dev->ResetCB = 0LL; + timer_disable(&dev->ResetCB); dev->Status = STAT_IDLE | STAT_INIT; } diff --git a/src/scsi/scsi_x54x.h b/src/scsi/scsi_x54x.h index 13699a181..cd0948c43 100644 --- a/src/scsi/scsi_x54x.h +++ b/src/scsi/scsi_x54x.h @@ -11,7 +11,7 @@ * of SCSI Host Adapters made by Mylex. * These controllers were designed for various buses. * - * Version: @(#)scsi_x54x.h 1.0.7 2018/04/06 + * Version: @(#)scsi_x54x.h 1.0.10 2018/10/28 * * Authors: TheCollector1995, * Miran Grca, @@ -118,37 +118,8 @@ #define INTR_MBIF 0x01 /* MBI full */ -/* Structure for the INQUIRE_SETUP_INFORMATION reply. */ -#pragma pack(push,1) -typedef struct { - uint8_t uOffset :4, - uTransferPeriod :3, - fSynchronous :1; -} ReplyInquireSetupInformationSynchronousValue; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t fSynchronousInitiationEnabled :1, - fParityCheckingEnabled :1, - uReserved1 :6; - uint8_t uBusTransferRate; - uint8_t uPreemptTimeOnBus; - uint8_t uTimeOffBus; - uint8_t cMailbox; - addr24 MailboxAddress; - ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; - uint8_t uDisconnectPermittedId0To7; - uint8_t VendorSpecificData[28]; -} ReplyInquireSetupInformation; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t Count; - addr24 Address; -} MailboxInit_t; -#pragma pack(pop) +#define ADDR_TO_U32(x) (((x).hi<<16)|((x).mid<<8)|((x).lo&0xFF)) +#define U32_TO_ADDR(a,x) do {(a).hi=(x)>>16;(a).mid=(x)>>8;(a).lo=(x)&0xFF;}while(0) /* * Mailbox Definitions. @@ -166,31 +137,6 @@ typedef struct { #define MBI_NOT_FOUND 0x03 #define MBI_ERROR 0x04 -#pragma pack(push,1) -typedef struct { - uint8_t CmdStatus; - addr24 CCBPointer; -} Mailbox_t; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint32_t CCBPointer; - union { - struct { - uint8_t Reserved[3]; - uint8_t ActionCode; - } out; - struct { - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Reserved; - uint8_t CompletionCode; - } in; - } u; -} Mailbox32_t; -#pragma pack(pop) - /* * * CCB - SCSI Command Control Block @@ -238,13 +184,78 @@ typedef struct { #define CCB_DUPLICATE_CCB 0x19 /* Duplicate CCB */ #define CCB_INVALID_CCB 0x1A /* Invalid CCB - bad parameter */ +#define lba32_blk(p) ((uint32_t)(p->u.lba.lba0<<24) | (p->u.lba.lba1<<16) | \ + (p->u.lba.lba2<<8) | p->u.lba.lba3) + +/* + * + * Scatter/Gather Segment List Definitions + * + * Adapter limits + */ +#define MAX_SG_DESCRIPTORS 32 /* Always make the array 32 elements long, if less are used, that's not an issue. */ + + +#pragma pack(push,1) +typedef struct { + uint8_t hi; + uint8_t mid; + uint8_t lo; +} addr24; + +/* Structure for the INQUIRE_SETUP_INFORMATION reply. */ +typedef struct { + uint8_t uOffset :4, + uTransferPeriod :3, + fSynchronous :1; +} ReplyInquireSetupInformationSynchronousValue; + +typedef struct { + uint8_t fSynchronousInitiationEnabled :1, + fParityCheckingEnabled :1, + uReserved1 :6; + uint8_t uBusTransferRate; + uint8_t uPreemptTimeOnBus; + uint8_t uTimeOffBus; + uint8_t cMailbox; + addr24 MailboxAddress; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; + uint8_t uDisconnectPermittedId0To7; + uint8_t VendorSpecificData[28]; +} ReplyInquireSetupInformation; + +typedef struct { + uint8_t Count; + addr24 Address; +} MailboxInit_t; + +typedef struct { + uint8_t CmdStatus; + addr24 CCBPointer; +} Mailbox_t; + +typedef struct { + uint32_t CCBPointer; + union { + struct { + uint8_t Reserved[3]; + uint8_t ActionCode; + } out; + struct { + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved; + uint8_t CompletionCode; + } in; + } u; +} Mailbox32_t; + /* Byte 15 Target Status See scsi.h files for these statuses. Bytes 16 and 17 Reserved (must be 0) Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block */ -#pragma pack(push,1) typedef struct { uint8_t Opcode; uint8_t Reserved1 :3, @@ -266,9 +277,7 @@ typedef struct { uint8_t Reserved3[6]; uint32_t SensePointer; } CCB32; -#pragma pack(pop) -#pragma pack(push,1) typedef struct { uint8_t Opcode; uint8_t Lun :3, @@ -285,9 +294,7 @@ typedef struct { uint8_t Reserved[2]; uint8_t Cdb[12]; } CCB; -#pragma pack(pop) -#pragma pack(push,1) typedef struct { uint8_t Opcode; uint8_t Pad1 :3, @@ -302,17 +309,13 @@ typedef struct { uint8_t Pad4[2]; uint8_t Cdb[12]; } CCBC; -#pragma pack(pop) -#pragma pack(push,1) typedef union { CCB32 new; CCB old; CCBC common; } CCBU; -#pragma pack(pop) -#pragma pack(push,1) typedef struct { CCBU CmdBlock; uint8_t *RequestSenseBuffer; @@ -324,113 +327,127 @@ typedef struct { TargetStatus, MailboxCompletionCode; } Req_t; -#pragma pack(pop) + +typedef struct +{ + uint8_t command; + uint8_t lun:3, + reserved:2, + id:3; + union { + struct { + uint16_t cyl; + uint8_t head; + uint8_t sec; + } chs; + struct { + uint8_t lba0; /* MSB */ + uint8_t lba1; + uint8_t lba2; + uint8_t lba3; /* LSB */ + } lba; + } u; + uint8_t secount; + addr24 dma_address; +} BIOSCMD; typedef struct { - int8_t type; /* type of device */ + uint32_t Segment; + uint32_t SegmentPointer; +} SGE32; - char vendor[16]; /* name of device vendor */ - char name[16]; /* name of device */ +typedef struct { + addr24 Segment; + addr24 SegmentPointer; +} SGE; +#pragma pack(pop) - int64_t timer_period, temp_period; - uint8_t callback_phase; - int64_t media_period; - double ha_bps; /* bytes per second */ +#define X54X_CDROM_BOOT 1 +#define X54X_32BIT 2 +#define X54X_LBA_BIOS 4 +#define X54X_INT_GEOM_WRITABLE 8 +#define X54X_MBX_24BIT 16 - int8_t Irq; - uint8_t IrqEnabled; +typedef struct { + /* 32 bytes */ + char vendor[16], /* name of device vendor */ + name[16]; /* name of device */ - int8_t DmaChannel; - int8_t HostID; - uint32_t Base; - uint8_t pos_regs[8]; /* MCA */ + /* 24 bytes */ + int8_t type, /* type of device */ + IrqEnabled, Irq, + DmaChannel, + HostID; - wchar_t *bios_path; /* path to BIOS image file */ - uint32_t rom_addr; /* address of BIOS ROM */ - uint16_t rom_ioaddr; /* offset in BIOS of I/O addr */ - uint16_t rom_shram; /* index to shared RAM */ - uint16_t rom_shramsz; /* size of shared RAM */ - uint16_t rom_fwhigh; /* offset in BIOS of ver ID */ - rom_t bios; /* BIOS memory descriptor */ - rom_t uppersck; /* BIOS memory descriptor */ - uint8_t *rom1; /* main BIOS image */ - uint8_t *rom2; /* SCSI-Select image */ - - wchar_t *nvr_path; /* path to NVR image file */ - uint8_t *nvr; /* EEPROM buffer */ - - int64_t ResetCB; + uint8_t callback_phase :4, + callback_sub_phase :4, + scsi_cmd_phase, pad, + sync, + parity, shram_mode, + Geometry, Control, + Command, CmdParam, + BusOnTime, BusOffTime, + ATBusSpeed, setup_info_len, + max_id, pci_slot, + temp_cdb[12]; volatile uint8_t /* for multi-threading, keep */ - Status, /* these volatile */ - Interrupt; + Status, Interrupt, /* these volatile */ + MailboxIsBIOS, ToRaise, + flags; - Req_t Req; - uint8_t Geometry; - uint8_t Control; - uint8_t Command; - uint8_t CmdBuf[128]; - uint8_t CmdParam; - uint32_t CmdParamLeft; - uint8_t DataBuf[65536]; - uint16_t DataReply; - uint16_t DataReplyLeft; + /* 65928 bytes */ + uint8_t pos_regs[8], /* MCA */ + CmdBuf[128], + DataBuf[65536], + shadow_ram[128], + dma_buffer[128]; + + /* 16 bytes */ + char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */ + + uint8_t *rom1, /* main BIOS image */ + *rom2, /* SCSI-Select image */ + *nvr; /* EEPROM buffer */ + + /* 6 words = 12 bytes */ + uint16_t DataReply, DataReplyLeft, + rom_ioaddr, /* offset in BIOS of I/O addr */ + rom_shram, /* index to shared RAM */ + rom_shramsz, /* size of shared RAM */ + rom_fwhigh; /* offset in BIOS of ver ID */ + + /* 16 + 20 + 52 = 88 bytes */ + volatile int + MailboxOutInterrupts, + PendingInterrupt, Lock, + target_data_len, pad0; + + uint32_t Base, rom_addr, /* address of BIOS ROM */ + CmdParamLeft, Outgoing, + pad32; volatile uint32_t - MailboxInit, - MailboxCount, - MailboxOutAddr, - MailboxOutPosCur, - MailboxInAddr, - MailboxInPosCur, - MailboxReq; - - volatile int - Mbx24bit, - MailboxOutInterrupts; - - volatile int - PendingInterrupt, - Lock; - - uint8_t shadow_ram[128]; - - volatile uint8_t - MailboxIsBIOS, - ToRaise; - - uint8_t shram_mode; - - uint8_t sync; - uint8_t parity; - - uint8_t dma_buffer[128]; - - volatile - uint32_t BIOSMailboxInit, - BIOSMailboxCount, - BIOSMailboxOutAddr, - BIOSMailboxOutPosCur, + MailboxInit, MailboxCount, + MailboxOutAddr, MailboxOutPosCur, + MailboxInAddr, MailboxInPosCur, + MailboxReq, + BIOSMailboxInit, BIOSMailboxCount, + BIOSMailboxOutAddr, BIOSMailboxOutPosCur, BIOSMailboxReq, - Residue; + Residue, bus; /* Basically a copy of device flags */ - uint8_t BusOnTime, - BusOffTime, - ATBusSpeed; + /* 8 bytes */ + uint64_t temp_period; - char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */ - uint16_t bus; /* Basically a copy of device flags */ - uint8_t setup_info_len; - uint8_t max_id; - uint8_t pci_slot; - uint8_t bit32; - uint8_t lba_bios; + /* 16 bytes */ + double media_period, ha_bps; /* bytes per second */ - mem_mapping_t mmio_mapping; - - uint8_t int_geom_writable; - uint8_t cdrom_boot; + /* 8 bytes */ + wchar_t *bios_path, /* path to BIOS image file */ + *nvr_path; /* path to NVR image file */ + /* 56 bytes */ /* Pointer to a structure of vendor-specific data that only the vendor-specific code can understand */ void *ven_data; @@ -460,40 +477,19 @@ typedef struct { uint8_t (*interrupt_type)(void *p); /* Pointer to a function that resets vendor-specific data */ void (*ven_reset)(void *p); + + rom_t bios, /* BIOS memory descriptor */ + uppersck; /* BIOS memory descriptor */ + + mem_mapping_t mmio_mapping; + + pc_timer_t timer, ResetCB; + + Req_t Req; } x54x_t; -#pragma pack(push,1) -typedef struct -{ - uint8_t command; - uint8_t lun:3, - reserved:2, - id:3; - union { - struct { - uint16_t cyl; - uint8_t head; - uint8_t sec; - } chs; - struct { - uint8_t lba0; /* MSB */ - uint8_t lba1; - uint8_t lba2; - uint8_t lba3; /* LSB */ - } lba; - } u; - uint8_t secount; - addr24 dma_address; -} BIOSCMD; -#pragma pack(pop) -#define lba32_blk(p) ((uint32_t)(p->u.lba.lba0<<24) | (p->u.lba.lba1<<16) | \ - (p->u.lba.lba2<<8) | p->u.lba.lba3) - - extern void x54x_reset_ctrl(x54x_t *dev, uint8_t Reset); -extern void x54x_buf_alloc(uint8_t id, int length); -extern void x54x_buf_free(uint8_t id); extern uint8_t x54x_mbo_process(x54x_t *dev); extern void x54x_wait_for_poll(void); extern void x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len); diff --git a/src/serial.c b/src/serial.c index 920f381c3..51297a64b 100644 --- a/src/serial.c +++ b/src/serial.c @@ -1,386 +1,741 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * NS8250/16450/16550 UART emulation. + * + * Now passes all the AMIDIAG tests. + * + * Version: @(#)serial.h 1.0.13 2019/10/31 + * + * Author: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + */ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H #include "86box.h" +#include "device.h" +#include "timer.h" #include "machine/machine.h" #include "io.h" #include "pic.h" #include "mem.h" #include "rom.h" #include "serial.h" -#include "timer.h" #include "mouse.h" enum { - SERIAL_INT_LSR = 1, - SERIAL_INT_RECEIVE = 2, - SERIAL_INT_TRANSMIT = 4, - SERIAL_INT_MSR = 8 + SERIAL_INT_LSR = 1, + SERIAL_INT_RECEIVE = 2, + SERIAL_INT_TRANSMIT = 4, + SERIAL_INT_MSR = 8, + SERIAL_INT_TIMEOUT = 16 }; -SERIAL serial1, serial2; -int serial_do_log = 0; + +static int next_inst = 0; +static serial_device_t serial_devices[SERIAL_MAX]; #ifdef ENABLE_SERIAL_LOG int serial_do_log = ENABLE_SERIAL_LOG; -#endif static void -serial_log(const char *format, ...) +serial_log(const char *fmt, ...) { -#ifdef ENABLE_SERIAL_LOG va_list ap; if (serial_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define serial_log(fmt, ...) #endif + + +void +serial_reset_port(serial_t *dev) +{ + dev->lsr = 0x60; /* Mark that both THR/FIFO and TXSR are empty. */ + dev->iir = dev->ier = dev->lcr = dev->fcr = 0; + dev->fifo_enabled = 0; + dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; + dev->baud_cycles = 0; + memset(dev->xmit_fifo, 0, 16); + memset(dev->rcvr_fifo, 0, 14); } -void serial_reset() +void +serial_transmit_period(serial_t *dev) { - serial1.iir = serial1.ier = serial1.lcr = 0; - serial2.iir = serial2.ier = serial2.lcr = 0; - serial1.fifo_read = serial1.fifo_write = 0; - serial2.fifo_read = serial2.fifo_write = 0; + double ddlab; + + ddlab = (double) dev->dlab; + + /* Bit period based on DLAB. */ + dev->transmit_period = (16000000.0 * ddlab) / 1843200.0; } -void serial_update_ints(SERIAL *serial) + +void +serial_update_ints(serial_t *dev) { - int stat = 0; - - serial->iir = 1; + int stat = 0; - if ((serial->ier & 4) && (serial->int_status & SERIAL_INT_LSR)) /*Line status interrupt*/ - { - stat = 1; - serial->iir = 6; - } - else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Recieved data available*/ - { - stat = 1; - serial->iir = 4; - } - else if ((serial->ier & 2) && (serial->int_status & SERIAL_INT_TRANSMIT)) /*Transmit data empty*/ - { - stat = 1; - serial->iir = 2; - } - else if ((serial->ier & 8) && (serial->int_status & SERIAL_INT_MSR)) /*Modem status interrupt*/ - { - stat = 1; - serial->iir = 0; - } + dev->iir = 1; - if (stat && ((serial->mctrl & 8) || PCJR)) { - picintlevel(1 << serial->irq); - } else - picintc(1 << serial->irq); + if ((dev->ier & 4) && (dev->int_status & SERIAL_INT_LSR)) { + /* Line status interrupt */ + stat = 1; + dev->iir = 6; + } else if ((dev->ier & 1) && (dev->int_status & SERIAL_INT_TIMEOUT)) { + /* Received data available */ + stat = 1; + dev->iir = 0x0c; + } else if ((dev->ier & 1) && (dev->int_status & SERIAL_INT_RECEIVE)) { + /* Received data available */ + stat = 1; + dev->iir = 4; + } else if ((dev->ier & 2) && (dev->int_status & SERIAL_INT_TRANSMIT)) { + /* Transmit data empty */ + stat = 1; + dev->iir = 2; + } else if ((dev->ier & 8) && (dev->int_status & SERIAL_INT_MSR)) { + /* Modem status interrupt */ + stat = 1; + dev->iir = 0; + } + + if (stat && ((dev->mctrl & 8) || (dev->type == SERIAL_8250_PCJR))) { + if (dev->type >= SERIAL_NS16450) + picintlevel(1 << dev->irq); + else + picint(1 << dev->irq); + } else + picintc(1 << dev->irq); } -void serial_clear_fifo(SERIAL *serial) + +static void +serial_clear_timeout(serial_t *dev) { - memset(serial->fifo, 0, 256); - serial->fifo_read = serial->fifo_write = 0; + /* Disable timeout timer and clear timeout condition. */ + timer_disable(&dev->timeout_timer); + dev->int_status &= ~SERIAL_INT_TIMEOUT; + serial_update_ints(dev); } -void serial_write_fifo(SERIAL *serial, uint8_t dat) + +static void +write_fifo(serial_t *dev, uint8_t dat) { - serial->fifo[serial->fifo_write] = dat; - serial->fifo_write = (serial->fifo_write + 1) & 0xFF; - if (!(serial->lsr & 1)) - { - serial->lsr |= 1; - serial->int_status |= SERIAL_INT_RECEIVE; - serial_update_ints(serial); - } + serial_log("write_fifo(%08X, %02X, %i, %i)\n", dev, dat, (dev->type >= SERIAL_NS16550) && dev->fifo_enabled, dev->rcvr_fifo_pos & 0x0f); + + if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { + /* FIFO mode. */ + timer_disable(&dev->timeout_timer); + /* Indicate overrun. */ + if (dev->rcvr_fifo_full) + dev->lsr |= 0x02; + else + dev->rcvr_fifo[dev->rcvr_fifo_pos] = dat; + dev->lsr &= 0xfe; + dev->int_status &= ~SERIAL_INT_RECEIVE; + if (dev->rcvr_fifo_pos == (dev->rcvr_fifo_len - 1)) { + dev->lsr |= 0x01; + dev->int_status |= SERIAL_INT_RECEIVE; + } + if (dev->rcvr_fifo_pos < 15) + dev->rcvr_fifo_pos++; + else + dev->rcvr_fifo_full = 1; + serial_update_ints(dev); + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); + } else { + /* Non-FIFO mode. */ + /* Indicate overrun. */ + if (dev->lsr & 0x01) + dev->lsr |= 0x02; + dev->dat = dat; + dev->lsr |= 0x01; + dev->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(dev); + } } -uint8_t serial_read_fifo(SERIAL *serial) + +void +serial_write_fifo(serial_t *dev, uint8_t dat) { - if (serial->fifo_read != serial->fifo_write) - { - serial->dat = serial->fifo[serial->fifo_read]; - serial->fifo_read = (serial->fifo_read + 1) & 0xFF; - } - return serial->dat; + serial_log("serial_write_fifo(%08X, %02X, %i, %i)\n", dev, dat, (dev->type >= SERIAL_NS16550) && dev->fifo_enabled, dev->rcvr_fifo_pos & 0x0f); + + if (!(dev->mctrl & 0x10)) + write_fifo(dev, dat); } -void serial_write(uint16_t addr, uint8_t val, void *p) + +void +serial_transmit(serial_t *dev, uint8_t val) { - SERIAL *serial = (SERIAL *)p; - switch (addr&7) - { - case 0: - if (serial->lcr & 0x80) - { - serial->dlab1 = val; - return; - } - serial->thr = val; - serial->lsr |= 0x20; - serial->int_status |= SERIAL_INT_TRANSMIT; - serial_update_ints(serial); - if (serial->mctrl & 0x10) - { - serial_write_fifo(serial, val); - } - break; - case 1: - if (serial->lcr & 0x80) - { - serial->dlab2 = val; - return; - } - serial->ier = val & 0xf; - serial_update_ints(serial); - break; - case 2: - serial->fcr = val; - break; - case 3: - serial->lcr = val; - break; - case 4: - if ((val & 2) && !(serial->mctrl & 2)) - { - if (serial->rcr_callback) - serial->rcr_callback((struct SERIAL *)serial, serial->rcr_callback_p); - } - serial->mctrl = val; - if (val & 0x10) - { - uint8_t new_msr; - - new_msr = (val & 0x0c) << 4; - new_msr |= (val & 0x02) ? 0x10: 0; - new_msr |= (val & 0x01) ? 0x20: 0; - - if ((serial->msr ^ new_msr) & 0x10) - new_msr |= 0x01; - if ((serial->msr ^ new_msr) & 0x20) - new_msr |= 0x02; - if ((serial->msr ^ new_msr) & 0x80) - new_msr |= 0x08; - if ((serial->msr & 0x40) && !(new_msr & 0x40)) - new_msr |= 0x04; - - serial->msr = new_msr; - } - break; - case 5: - serial->lsr = val; - if (serial->lsr & 0x01) - serial->int_status |= SERIAL_INT_RECEIVE; - if (serial->lsr & 0x1e) - serial->int_status |= SERIAL_INT_LSR; - if (serial->lsr & 0x20) - serial->int_status |= SERIAL_INT_TRANSMIT; - serial_update_ints(serial); - break; - case 6: - serial->msr = val; - if (serial->msr & 0x0f) - serial->int_status |= SERIAL_INT_MSR; - serial_update_ints(serial); - break; - case 7: - serial->scratch = val; - break; - } + if (dev->mctrl & 0x10) + write_fifo(dev, val); + else if (dev->sd->dev_write) + dev->sd->dev_write(dev, dev->sd->priv, val); } -uint8_t serial_read(uint16_t addr, void *p) + +static void +serial_move_to_txsr(serial_t *dev) { - SERIAL *serial = (SERIAL *)p; - uint8_t temp = 0; - switch (addr&7) - { - case 0: - if (serial->lcr & 0x80) - { - temp = serial->dlab1; - break; + int i = 0; + + if (dev->fifo_enabled) { + dev->txsr = dev->xmit_fifo[0]; + if (dev->xmit_fifo_pos > 0) { + /* Move the entire fifo forward by one byte. */ + for (i = 1; i < 16; i++) + dev->xmit_fifo[i - 1] = dev->xmit_fifo[i]; + /* Decrease FIFO position. */ + dev->xmit_fifo_pos--; + } + } else { + dev->txsr = dev->thr; + dev->thr = 0; + } + + dev->lsr &= ~0x40; + serial_log("serial_move_to_txsr(): FIFO %sabled, FIFO pos = %i\n", dev->fifo_enabled ? "en" : "dis", dev->xmit_fifo_pos & 0x0f); + + if (!dev->fifo_enabled || (dev->xmit_fifo_pos == 0x0)) { + /* Update interrupts to signal THRE and that TXSR is no longer empty. */ + dev->lsr |= 0x20; + dev->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(dev); + } + if (dev->transmit_enabled & 2) + dev->baud_cycles++; + else + dev->baud_cycles = 0; /* If not moving while transmitting, reset BAUDOUT cycle count. */ + if (!dev->fifo_enabled || (dev->xmit_fifo_pos == 0x0)) + dev->transmit_enabled &= ~1; /* Stop moving. */ + dev->transmit_enabled |= 2; /* Start transmitting. */ +} + + +static void +serial_process_txsr(serial_t *dev) +{ + serial_log("serial_process_txsr(): FIFO %sabled\n", dev->fifo_enabled ? "en" : "dis"); + serial_transmit(dev, dev->txsr); + dev->txsr = 0; + /* Reset BAUDOUT cycle count. */ + dev->baud_cycles = 0; + /* If FIFO is enabled and there are bytes left to transmit, + continue with the FIFO, otherwise stop. */ + if (dev->fifo_enabled && (dev->xmit_fifo_pos != 0x0)) + dev->transmit_enabled |= 1; + else { + /* Both FIFO/THR and TXSR are empty. */ + /* If bit 5 is set, also set bit 6 to mark both THR and shift register as empty. */ + if (dev->lsr & 0x20) + dev->lsr |= 0x40; + dev->transmit_enabled &= ~2; + } + dev->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(dev); +} + + +/* Transmit_enable flags: + Bit 0 = Do move if set; + Bit 1 = Do transmit if set. */ +static void +serial_transmit_timer(void *priv) +{ + serial_t *dev = (serial_t *) priv; + int delay = 8; /* STOP to THRE delay is 8 BAUDOUT cycles. */ + + if (dev->transmit_enabled & 3) { + if ((dev->transmit_enabled & 1) && (dev->transmit_enabled & 2)) + delay = dev->data_bits; /* Delay by less if already transmitting. */ + + dev->baud_cycles++; + + /* We have processed (total bits) BAUDOUT cycles, transmit the byte. */ + if ((dev->baud_cycles == dev->bits) && (dev->transmit_enabled & 2)) + serial_process_txsr(dev); + + /* We have processed (data bits) BAUDOUT cycles. */ + if ((dev->baud_cycles == delay) && (dev->transmit_enabled & 1)) + serial_move_to_txsr(dev); + + if (dev->transmit_enabled & 3) + timer_on_auto(&dev->transmit_timer, dev->transmit_period); + } else { + dev->baud_cycles = 0; + return; + } +} + + +static void +serial_timeout_timer(void *priv) +{ + serial_t *dev = (serial_t *) priv; + +#ifdef ENABLE_SERIAL_LOG + serial_log("serial_timeout_timer()\n"); +#endif + + dev->lsr |= 0x01; + dev->int_status |= SERIAL_INT_TIMEOUT; + serial_update_ints(dev); +} + + +static void +serial_update_speed(serial_t *dev) +{ + if (dev->transmit_enabled & 3) + timer_on_auto(&dev->transmit_timer, dev->transmit_period); + + if (timer_is_enabled(&dev->timeout_timer)) + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); +} + + +static void +serial_reset_fifo(serial_t *dev) +{ + dev->lsr = (dev->lsr & 0xfe) | 0x60; + dev->int_status = (dev->int_status & ~SERIAL_INT_RECEIVE) | SERIAL_INT_TRANSMIT; + serial_update_ints(dev); + dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; +} + + +void +serial_write(uint16_t addr, uint8_t val, void *p) +{ + serial_t *dev = (serial_t *)p; + uint8_t new_msr, old; + + serial_log("UART: Write %02X to port %02X\n", val, addr); + + sub_cycles(ISA_CYCLES(8)); + + switch (addr & 7) { + case 0: + if (dev->lcr & 0x80) { + dev->dlab = (dev->dlab & 0xff00) | val; + serial_transmit_period(dev); + serial_update_speed(dev); + return; } - serial->lsr &= ~1; - serial->int_status &= ~SERIAL_INT_RECEIVE; - serial_update_ints(serial); - temp = serial_read_fifo(serial); - if (serial->fifo_read != serial->fifo_write) { - serial->recieve_delay = 1000LL * TIMER_USEC; + /* Indicate FIFO/THR is no longer empty. */ + dev->lsr &= 0x9f; + dev->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(dev); + + if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled && (dev->xmit_fifo_pos < 16)) { + /* FIFO mode, begin transmitting. */ + timer_on_auto(&dev->transmit_timer, dev->transmit_period); + dev->transmit_enabled |= 1; /* Start moving. */ + dev->xmit_fifo[dev->xmit_fifo_pos++] = val; + } else { + /* Non-FIFO mode, begin transmitting. */ + timer_on_auto(&dev->transmit_timer, dev->transmit_period); + dev->transmit_enabled |= 1; /* Start moving. */ + dev->thr = val; } - break; - case 1: - if (serial->lcr & 0x80) - temp = serial->dlab2; - else - temp = serial->ier; - break; - case 2: - temp = serial->iir; - if ((temp & 0xe) == 2) - { - serial->int_status &= ~SERIAL_INT_TRANSMIT; - serial_update_ints(serial); - } - if (serial->fcr & 1) - temp |= 0xc0; - break; - case 3: - temp = serial->lcr; - break; - case 4: - temp = serial->mctrl; - break; - case 5: - if (serial->lsr & 0x20) - serial->lsr |= 0x40; - serial->lsr |= 0x20; - temp = serial->lsr; - if (serial->lsr & 0x1f) - serial->lsr &= ~0x1e; - serial->int_status &= ~SERIAL_INT_LSR; - serial_update_ints(serial); - break; - case 6: - temp = serial->msr; - serial->msr &= ~0x0f; - serial->int_status &= ~SERIAL_INT_MSR; - serial_update_ints(serial); - break; - case 7: - temp = serial->scratch; - break; - } - return temp; + break; + case 1: + if (dev->lcr & 0x80) { + dev->dlab = (dev->dlab & 0x00ff) | (val << 8); + serial_transmit_period(dev); + serial_update_speed(dev); + return; + } + if ((val & 2) && (dev->lsr & 0x20)) + dev->int_status |= SERIAL_INT_TRANSMIT; + dev->ier = val & 0xf; + serial_update_ints(dev); + break; + case 2: + if (dev->type >= SERIAL_NS16550) { + if ((val ^ dev->fcr) & 0x01) + serial_reset_fifo(dev); + dev->fcr = val & 0xf9; + dev->fifo_enabled = val & 0x01; + if (!dev->fifo_enabled) { + memset(dev->rcvr_fifo, 0, 14); + memset(dev->xmit_fifo, 0, 16); + dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; + dev->rcvr_fifo_len = 1; + break; + } + if (val & 0x02) { + memset(dev->rcvr_fifo, 0, 14); + dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; + } + if (val & 0x04) { + memset(dev->xmit_fifo, 0, 16); + dev->xmit_fifo_pos = 0; + } + switch ((val >> 6) & 0x03) { + case 0: + dev->rcvr_fifo_len = 1; + break; + case 1: + dev->rcvr_fifo_len = 4; + break; + case 2: + dev->rcvr_fifo_len = 8; + break; + case 3: + dev->rcvr_fifo_len = 14; + break; + } + serial_log("FIFO now %sabled, receive FIFO length = %i\n", dev->fifo_enabled ? "en" : "dis", dev->rcvr_fifo_len); + } + break; + case 3: + old = dev->lcr; + dev->lcr = val; + if ((old ^ val) & 0x0f) { + /* Data bits + start bit. */ + dev->bits = ((dev->lcr & 0x03) + 5) + 1; + /* Stop bits. */ + dev->bits++; /* First stop bit. */ + if (dev->lcr & 0x04) + dev->bits++; /* Second stop bit. */ + /* Parity bit. */ + if (dev->lcr & 0x08) + dev->bits++; + + serial_transmit_period(dev); + serial_update_speed(dev); + } + break; + case 4: + if ((val & 2) && !(dev->mctrl & 2)) { + if (dev->sd->rcr_callback) + dev->sd->rcr_callback(dev, dev->sd->priv); + } + if (!(val & 8) && (dev->mctrl & 8)) + picintc(1 << dev->irq); + if ((val ^ dev->mctrl) & 0x10) + serial_reset_fifo(dev); + dev->mctrl = val; + if (val & 0x10) { + new_msr = (val & 0x0c) << 4; + new_msr |= (val & 0x02) ? 0x10: 0; + new_msr |= (val & 0x01) ? 0x20: 0; + + if ((dev->msr ^ new_msr) & 0x10) + new_msr |= 0x01; + if ((dev->msr ^ new_msr) & 0x20) + new_msr |= 0x02; + if ((dev->msr ^ new_msr) & 0x80) + new_msr |= 0x08; + if ((dev->msr & 0x40) && !(new_msr & 0x40)) + new_msr |= 0x04; + + dev->msr = new_msr; + + dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; + dev->rcvr_fifo_full = 0; + } + break; + case 5: + dev->lsr = val; + if (dev->lsr & 0x01) + dev->int_status |= SERIAL_INT_RECEIVE; + if (dev->lsr & 0x1e) + dev->int_status |= SERIAL_INT_LSR; + if (dev->lsr & 0x20) + dev->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(dev); + break; + case 6: + dev->msr = val; + if (dev->msr & 0x0f) + dev->int_status |= SERIAL_INT_MSR; + serial_update_ints(dev); + break; + case 7: + if (dev->type >= SERIAL_NS16450) + dev->scratch = val; + break; + } } -void serial_recieve_callback(void *p) + +uint8_t +serial_read(uint16_t addr, void *p) { - SERIAL *serial = (SERIAL *)p; - - serial->recieve_delay = 0; - - if (serial->fifo_read != serial->fifo_write) - { - serial->lsr |= 1; - serial->int_status |= SERIAL_INT_RECEIVE; - serial_update_ints(serial); - } + serial_t *dev = (serial_t *)p; + uint8_t i, ret = 0; + + sub_cycles(ISA_CYCLES(8)); + + switch (addr & 7) { + case 0: + if (dev->lcr & 0x80) { + ret = dev->dlab & 0xff; + break; + } + + if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { + /* FIFO mode. */ + + serial_clear_timeout(dev); + + ret = dev->rcvr_fifo[0]; + dev->rcvr_fifo_full = 0; + if (dev->rcvr_fifo_pos > 0) { + for (i = 1; i < 16; i++) + dev->rcvr_fifo[i - 1] = dev->rcvr_fifo[i]; + serial_log("FIFO position %i: read %02X, next %02X\n", dev->rcvr_fifo_pos, ret, dev->rcvr_fifo[0]); + dev->rcvr_fifo_pos--; + /* At least one byte remains to be read, start the timeout + timer so that a timeout is indicated in case of no read. */ + timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); + } else { + dev->lsr &= 0xfe; + dev->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(dev); + } + } else { + ret = dev->dat; + dev->lsr &= 0xfe; + dev->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(dev); + } + serial_log("Read data: %02X\n", ret); + break; + case 1: + if (dev->lcr & 0x80) + ret = (dev->dlab >> 8) & 0xff; + else + ret = dev->ier; + break; + case 2: + ret = dev->iir; + if ((ret & 0xe) == 2) { + dev->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(dev); + } + if (dev->fcr & 1) + ret |= 0xc0; + break; + case 3: + ret = dev->lcr; + break; + case 4: + ret = dev->mctrl; + break; + case 5: + ret = dev->lsr; + if (dev->lsr & 0x1f) + dev->lsr &= ~0x1e; + dev->int_status &= ~SERIAL_INT_LSR; + serial_update_ints(dev); + break; + case 6: + ret = dev->msr; + dev->msr &= ~0x0f; + dev->int_status &= ~SERIAL_INT_MSR; + serial_update_ints(dev); + break; + case 7: + ret = dev->scratch; + break; + } + + serial_log("UART: Read %02X from port %02X\n", ret, addr); + return ret; } -uint16_t base_address[2] = { 0x0000, 0x0000 }; -void serial_remove(int port) +void +serial_remove(serial_t *dev) { - if ((port < 1) || (port > 2)) - { - fatal("serial_remove(): Invalid serial port: %i\n", port); - exit(-1); - } + if (!serial_enabled[dev->inst]) + return; - if (!serial_enabled[port - 1]) - { - return; - } + if (!dev->base_address) + return; - if (!base_address[port - 1]) - { - return; - } + serial_log("Removing serial port %i at %04X...\n", dev->inst, dev->base_address); - serial_log("Removing serial port %i at %04X...\n", port, base_address[port - 1]); - - switch(port) - { - case 1: - io_removehandler(base_address[0], 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - base_address[0] = 0x0000; - break; - case 2: - io_removehandler(base_address[1], 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - base_address[1] = 0x0000; - break; - } + io_removehandler(dev->base_address, 0x0008, + serial_read, NULL, NULL, serial_write, NULL, NULL, dev); + dev->base_address = 0x0000; } -void serial_setup(int port, uint16_t addr, int irq) + +void +serial_setup(serial_t *dev, uint16_t addr, int irq) { - serial_log("Adding serial port %i at %04X...\n", port, addr); + serial_log("Adding serial port %i at %04X...\n", dev->inst, addr); - switch(port) - { - case 1: - if (!serial_enabled[0]) - { - return; - } - if (base_address[0] != 0x0000) - { - serial_remove(port); - } - if (addr != 0x0000) - { - base_address[0] = addr; - io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - } - serial1.irq = irq; - break; - case 2: - if (!serial_enabled[1]) - { - return; - } - if (base_address[1] != 0x0000) - { - serial_remove(port); - } - if (addr != 0x0000) - { - base_address[1] = addr; - io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - } - serial2.irq = irq; - break; - default: - fatal("serial_setup(): Invalid serial port: %i\n", port); - break; - } + if (!serial_enabled[dev->inst]) + return; + if (dev->base_address != 0x0000) + serial_remove(dev); + dev->base_address = addr; + if (addr != 0x0000) + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, dev); + dev->irq = irq; } -void serial_init(void) + +serial_t * +serial_attach(int port, + void (*rcr_callback)(struct serial_s *serial, void *p), + void (*dev_write)(struct serial_s *serial, void *p, uint8_t data), + void *priv) { - base_address[0] = 0x03f8; - base_address[1] = 0x02f8; + serial_device_t *sd = &serial_devices[port]; - if (serial_enabled[0]) - { - serial_log("Adding serial port 1...\n"); - memset(&serial1, 0, sizeof(serial1)); - io_sethandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); - serial1.irq = 4; - serial1.rcr_callback = NULL; - timer_add(serial_recieve_callback, &serial1.recieve_delay, &serial1.recieve_delay, &serial1); - } - if (serial_enabled[1]) - { - serial_log("Adding serial port 2...\n"); - memset(&serial2, 0, sizeof(serial2)); - io_sethandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); - serial2.irq = 3; - serial2.rcr_callback = NULL; - timer_add(serial_recieve_callback, &serial2.recieve_delay, &serial2.recieve_delay, &serial2); - } + sd->rcr_callback = rcr_callback; + sd->dev_write = dev_write; + sd->priv = priv; + + return sd->serial; } + + +static void +serial_speed_changed(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + serial_update_speed(dev); +} + + +static void +serial_close(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + next_inst--; + + free(dev); +} + + +static void * +serial_init(const device_t *info) +{ + serial_t *dev = (serial_t *) malloc(sizeof(serial_t)); + memset(dev, 0, sizeof(serial_t)); + + dev->inst = next_inst; + + if (serial_enabled[next_inst]) { + serial_log("Adding serial port %i...\n", next_inst); + dev->type = info->local; + memset(&(serial_devices[next_inst]), 0, sizeof(serial_device_t)); + dev->sd = &(serial_devices[next_inst]); + dev->sd->serial = dev; + serial_reset_port(dev); + if (next_inst || (info->flags & DEVICE_PCJR)) + serial_setup(dev, SERIAL2_ADDR, SERIAL2_IRQ); + else + serial_setup(dev, SERIAL1_ADDR, SERIAL1_IRQ); + + /* Default to 1200,N,7. */ + dev->dlab = 96; + dev->fcr = 0x06; + serial_transmit_period(dev); + timer_add(&dev->transmit_timer, serial_transmit_timer, dev, 0); + timer_add(&dev->timeout_timer, serial_timeout_timer, dev, 0); + } + + next_inst++; + + return dev; +} + + +void +serial_set_next_inst(int ni) +{ + next_inst = ni; +} + + +void +serial_standalone_init(void) { + if (next_inst == 0) { + device_add_inst(&i8250_device, 1); + device_add_inst(&i8250_device, 2); + } else if (next_inst == 1) + device_add_inst(&i8250_device, 2); +}; + + +const device_t i8250_device = { + "Intel 8250(-compatible) UART", + 0, + SERIAL_8250, + serial_init, serial_close, NULL, + NULL, serial_speed_changed, NULL, + NULL +}; + +const device_t i8250_pcjr_device = { + "Intel 8250(-compatible) UART for PCjr", + DEVICE_PCJR, + SERIAL_8250_PCJR, + serial_init, serial_close, NULL, + NULL, serial_speed_changed, NULL, + NULL +}; + +const device_t ns16450_device = { + "National Semiconductor NS16450(-compatible) UART", + 0, + SERIAL_NS16450, + serial_init, serial_close, NULL, + NULL, serial_speed_changed, NULL, + NULL +}; + +const device_t ns16550_device = { + "National Semiconductor NS16550(-compatible) UART", + 0, + SERIAL_NS16550, + serial_init, serial_close, NULL, + NULL, serial_speed_changed, NULL, + NULL +}; diff --git a/src/serial.h b/src/serial.h index 47eafdbd3..73238c87b 100644 --- a/src/serial.h +++ b/src/serial.h @@ -6,18 +6,27 @@ * * This file is part of the 86Box distribution. * - * Definitions for the SERIAL card. + * Definitions for the NS8250/16450/16550 UART emulation. * - * Version: @(#)serial.h 1.0.7 2018/01/12 + * Version: @(#)serial.h 1.0.12 2019/10/31 * - * Author: Fred N. van Kempen, - * Copyright 2017,2018 Fred N. van Kempen. + * Author: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_SERIAL_H # define EMU_SERIAL_H -#ifdef WALTJE_SERIAL +#define SERIAL_8250 0 +#define SERIAL_8250_PCJR 1 +#define SERIAL_NS16450 2 +#define SERIAL_NS16550 3 + /* Default settings for the standard ports. */ #define SERIAL1_ADDR 0x03f8 #define SERIAL1_IRQ 4 @@ -25,95 +34,55 @@ #define SERIAL2_IRQ 3 -/* Supported UART types. */ -#define UART_TYPE_8250 0 /* standard NS8250 */ -#define UART_TYPE_8250A 1 /* updated NS8250(A) */ -#define UART_TYPE_16450 2 /* 16450 */ -#define UART_TYPE_16550 3 /* 16550 (broken fifo) */ -#define UART_TYPE_16550A 4 /* 16550a (working fifo) */ -#define UART_TYPE_16670 5 /* 16670 (64b fifo) */ +struct serial_device_s; +struct serial_s; - -typedef struct _serial_ { - int8_t port; /* port number (1,2,..) */ - int8_t irq; /* IRQ channel used */ - uint16_t addr; /* I/O address used */ - int8_t type; /* UART type */ - uint8_t int_status; - - uint8_t lsr, thr, mctrl, rcr, /* UART registers */ - iir, ier, lcr, msr; - uint8_t dlab1, dlab2; - uint8_t dat, - hold; - uint8_t scratch; - uint8_t fcr; - - /* Data for the RTS-toggle callback. */ - void (*rts_callback)(void *); - void *rts_callback_p; - - uint8_t fifo[256]; - int fifo_read, fifo_write; - - int64_t receive_delay; - - void *bh; /* BottomHalf handler */ -} SERIAL; - - -/* Functions. */ -extern void serial_init(void); -extern void serial_reset(void); -extern void serial_setup(int port, uint16_t addr, int irq); -extern void serial_remove(int port); -extern SERIAL *serial_attach(int, void *, void *); -extern int serial_link(int, char *); - -extern void serial_clear_fifo(SERIAL *); -extern void serial_write_fifo(SERIAL *, uint8_t, int); - - -#else - - -void serial_remove(int port); -void serial_setup(int port, uint16_t addr, int irq); -void serial_init(void); -void serial_reset(); - -struct SERIAL; - -typedef struct +typedef struct serial_s { - uint8_t lsr,thr,mctrl,rcr,iir,ier,lcr,msr; - uint8_t dlab1,dlab2; - uint8_t dat; - uint8_t int_status; - uint8_t scratch; - uint8_t fcr; - - int irq; + uint8_t lsr, thr, mctrl, rcr, + iir, ier, lcr, msr, + dat, int_status, scratch, fcr, + irq, type, inst, transmit_enabled, + fifo_enabled, rcvr_fifo_len, bits, data_bits, + baud_cycles, rcvr_fifo_full, txsr, pad; - void (*rcr_callback)(struct SERIAL *serial, void *p); - void *rcr_callback_p; - uint8_t fifo[256]; - int fifo_read, fifo_write; - - int64_t recieve_delay; -} SERIAL; + uint16_t dlab, base_address; -void serial_clear_fifo(SERIAL *); -void serial_write_fifo(SERIAL *serial, uint8_t dat); + uint8_t rcvr_fifo_pos, xmit_fifo_pos, + pad0, pad1, + rcvr_fifo[16], xmit_fifo[16]; -extern SERIAL serial1, serial2; + pc_timer_t transmit_timer, timeout_timer; + double transmit_period; -/* Default settings for the standard ports. */ -#define SERIAL1_ADDR 0x03f8 -#define SERIAL1_IRQ 4 -#define SERIAL2_ADDR 0x02f8 -#define SERIAL2_IRQ 3 -#endif + struct serial_device_s *sd; +} serial_t; + +typedef struct serial_device_s +{ + void (*rcr_callback)(struct serial_s *serial, void *p); + void (*dev_write)(struct serial_s *serial, void *p, uint8_t data); + void *priv; + serial_t *serial; +} serial_device_t; + + +extern serial_t * serial_attach(int port, + void (*rcr_callback)(struct serial_s *serial, void *p), + void (*dev_write)(struct serial_s *serial, void *p, uint8_t data), + void *priv); +extern void serial_remove(serial_t *dev); +extern void serial_set_type(serial_t *dev, int type); +extern void serial_setup(serial_t *dev, uint16_t addr, int irq); +extern void serial_clear_fifo(serial_t *dev); +extern void serial_write_fifo(serial_t *dev, uint8_t dat); +extern void serial_set_next_inst(int ni); +extern void serial_standalone_init(void); + +extern const device_t i8250_device; +extern const device_t i8250_pcjr_device; +extern const device_t ns16450_device; +extern const device_t ns16550_device; #endif /*EMU_SERIAL_H*/ diff --git a/src/sio.h b/src/sio.h index 233a9a57e..76f3a08f1 100644 --- a/src/sio.h +++ b/src/sio.h @@ -8,7 +8,7 @@ * * Definitions for the Super I/O chips. * - * Version: @(#)sio.h 1.0.2 2017/10/26 + * Version: @(#)sio.h 1.0.6 2019/05/17 * * Author: Fred N. van Kempen, * Copyright 2017 Fred N. van Kempen. @@ -17,15 +17,20 @@ # define EMU_SIO_H -extern void superio_detect_init(void); -extern void fdc37c663_init(void); -extern void fdc37c665_init(void); -extern void fdc37c669_init(void); -extern void fdc37c932fr_init(void); -extern void fdc37c935_init(void); -extern void pc87306_init(void); -extern void um8669f_init(void); -extern void w83877f_init(void); +extern const device_t acc3221_device; +extern const device_t fdc37c663_device; +extern const device_t fdc37c665_device; +extern const device_t fdc37c666_device; +extern const device_t fdc37c669_device; +extern const device_t fdc37c932fr_device; +extern const device_t fdc37c932qf_device; +extern const device_t fdc37c935_device; +extern const device_t pc87306_device; +extern const device_t sio_detect_device; +extern const device_t um8669f_device; +extern const device_t w83877f_device; +extern const device_t w83877f_president_device; +extern const device_t w83877tf_device; #endif /*EMU_SIO_H*/ diff --git a/src/sio_acc3221.c b/src/sio_acc3221.c new file mode 100644 index 000000000..18f759f17 --- /dev/null +++ b/src/sio_acc3221.c @@ -0,0 +1,485 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ACC 3221-SP Super I/O Chip. + * + * Version: @(#)sio_acc3221.c 1.0.0 2019/04/05 + * + * Authors: Sarah Walker, + * + * Copyright 2019 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "io.h" +#include "timer.h" +#include "device.h" +#include "pci.h" +#include "lpt.h" +#include "serial.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + +typedef struct acc3221_t +{ + int reg_idx; + uint8_t regs[256]; + fdc_t * fdc; + serial_t * uart[2]; +} acc3221_t; + + +/* Configuration Register Index, BE (R/W): + Bit Function + 7 PIRQ 5 polarity. + 1 = active high, default + 0 = active low + 6 PIRQ 7 polarity. + 1 = active high, default + 0 = active low + 5 Primary Parallel Port Extended Mode + 0 = Compatible mode, default + 1 = Extended/Bidirectional mode. + 4 Primary Parallel Port Disable + 1 = Disable, 0 = Enable + Power Up Default is set by pin 120 + (3221-DP)/pin 96 (3221-SP) + 3 Primary Parallel Port Power Down + 1 = Power Down, default = 0 + 2** Secondary Parallel Port Extended + Mode + 0 = Compatible mode, default + 1 = Extended/Bidirectional mode. + 1** Secondary Parallel Port Disable + 1 = Disable, 0 = Enable + Power Up Default is set by pin 77 + (3221-DP) + 0** Secondary Parallel Port Power Down + 1 = Power Down + 0 = Enable, default + Note: Power Up not applicable to 3221-EP. */ +#define REG_BE_LPT1_DISABLE (3 << 3) +#define REG_BE_LPT2_DISABLE (3 << 0) /* 3221-DP/EP only */ + +/* Configuration Register Index, BF (R/W): + Bit Function + 7-0 The 8 most significant address bits of + the primary parallel port (A9-2) + Default 9E (LPT2, at 278-27B) */ + +/* Configuration Register Index, DA (R/W)**: + Bit Function + 7-0 The 8 most significant address bits of + the secondary parallel port (A9-2) + Default DE (LPT1, at 378-37B) */ + +/* Configuration Register Index, DB (R/W): + Bit Function + 7 SIRQ4 polarity. + 1 = active high; default + 0 = active low + 6 SIRQ3 polarity. + 1 = active high; default + 0 = active low + 5 SXTAL clock off. 1 = SCLK off, + 0 = SCKL on, default + 4 Primary serial port disable + 1 = Disable, 0 = Enable + Power Up default is set by pin 116 + (3221-DP)/pin 93 (3221-SP) + 3 Primary serial port power down + 1 = Power down, 0 = Enable + Power Up default is set by pin 116 + (3221-DP)/pin 93 (3221-SP) + 2 Reserved + 1 Secondary serial port disable + 1 = Disable, 0 = Enable + Power Up default is set by pin 121 + (3221-DP)/pin 97 (3221-SP) + 0 Secondary serial port power down + 1 = Power down, 0 = Enable + Power Up default is set by pin 121 + (3221-DP)/pin 97 (3221-SP) + Note: Power Up not applicable to 3221-EP. */ +#define REG_DB_SERIAL1_DISABLE (3 << 3) +#define REG_DB_SERIAL2_DISABLE (3 << 0) + +/* Configuration Register Index, DC (R/W): + Bit Function + 7-1 The MSB of the Primary Serial Port + Address (bits A9-3). + Default = 7F (COM1, at 3F8-3FF). + 0 When this bit is set to 1, bit A2 of + primary parallel port is decoded. + Default is 0. */ + +/* Configuration Register Index, DD (R/W): + Bit Function + 7-1 The MSB of the Secondary Serial Port + Address (bits A9-3). + Default = 5F (COM2, at 2F8-2FF). + 0** When this bit is set to 1, bit A2 of + secondary parallel port is decoded. + Default is 0. */ + +/* Configuration Register Index, DE (R/W): + Bit Function + 7-6 SIRQ3 source + b7 b6 + 0 0 Disabled, tri-stated + 0 1 Disabled, tri-stated** + 1 0 Primary serial port + 1 1 Secondary serial port, + default + 5-4 SIRQ4 source + b5 b4 + 0 0 Disabled, tri-stated + 0 1 Disabled, tri-stated** + 1 0 Primary serial port, + default + 1 1 Secondary serial port + + 3-2** PIRQ7 source + b3 b2 + 0 0 Diabled, tri-stated, + default + 0 1 Primary serial port + 1 0 Primary parallel port + 1 1 Secondary parallel + port + Note: Bits 3-2 are reserved in 3221-SP. + + 1-0 PIRQ5 source + b1 b0 + 0 0 Disabled, tri-stated + 0 1 Secondary serial port + 1 0 Primary parallel port, + default + 1 1 Secondary parallel + port** */ +#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_DE_PIRQ7_SOURCE (3 << 2) +#define REG_DE_PIRQ7_SERIAL1 (1 << 2) +#define REG_DE_PIRQ7_LPT1 (2 << 2) +#define REG_DE_PIRQ7_LPT2 (3 << 2) +#define REG_DE_PIRQ5_SOURCE (3 << 0) +#define REG_DE_PIRQ5_SERIAL2 (1 << 0) +#define REG_DE_PIRQ5_LPT1 (2 << 0) +#define REG_DE_PIRQ5_LPT2 (3 << 0) + +/* Configuration Register Index, DF (R/W)**: + Bit Function + 7-6 Reserved + 5 RTC interface disable + 1 = /RTCCS disabled + 0 = /RTCCS enabled, default + 4 Disable Modem Select + 1 = Moden CS disabled, default + 0 = Modem CS enabled + + 3-2 + b3 b2 + 1 1 Reserved + 1 0 Modem port address + = 3E8-3EF (default) + 0 1 Modem port address: + 2F8-2FF + 0 0 Modem port address: + 3F8-3FF + + 1-0 + b1 b0 + 1 1 Reserved + 1 0 Mode 2, EISA Mode + 0 1 Mode 1, AT BUS, + 0 0 Mode 0, Two parallel + ports, default */ + +/* Configuration Register Index, FA (R/W)**: + Bit Function + 7 General purpose I/O register, Bit 7 + 6 General purpose I/O register, Bit 6 + 5 General purpose I/O register, Bit 5 + 4 General purpose I/O register, Bit 4 + 3 General purpose I/O register, Bit 3 + 2 General purpose I/O register, Bit 2 + 1 General purpose I/O register, Bit 1 + 0 General purpose I/O register, Bit 0 */ + +/* Configuration Register Index, FB (R/W)**: + Bit Function + 7 Reserved + 6** 0/2 EXG (Read Only) + In mode 1 and mode 2 + operation, when the third + floppy drive is installed, pin + EXTFDD should be pulled + high to enable the third floppy + drive or be pulled low to + disable the third floppy drive. + 1 = Third floppy drive enabled + 0 = Third floppy drive disabled + 5** EXTFDD (Read Only) + In mode 1 and mode 2 + operation, when the third + floppy drive is installed and + pin 0/2 EXG is pulled high, + the third floppy drive becomes + the bootable drive (drive 0). + When pi 0/2 EXG is pulled low, + the third floppy drive acts as + drive 2. + 1 = Third floppy drive as drive 0 (bootable) + 0 = Third floppy drive as drive 2 + 4** MS + In mode 1 and mode 2, t his bit is to + control the output pin MS to support a + special 3 1/2", 1.2M drive. When this + bit is set to high (1), the MS pin sends + a low signal. When this bit is set to + low (0), the MS pin sends a high + signal to support a 3 1/2", 1.2M drive. + 3 FDC, Clock disable + 0 = enable, default + 1 = disable + 2 Reserved + 1 FDC disable + 0 = enable, 1= disable + Power Upd efault set by pin 117 (3221- + DP)/pin 94 (3221-SP) + 0 FDC address + 0 = Primary, default + 1 = Secondary + Note: Bits 6-4 are reserved in 3221-SP. */ +#define REG_FB_FDC_DISABLE (1 << 1) + +/* Configuration Register Index, FB (R/W)**: + Bit Function + 7** Disable general chip select 1 + 1 = disable, default + 0 = enable + 6** Disable general chip select 2 + 1 = disable, default + 0 = enable + 5** Enable SA2 decoding for general chip + select 1 + 1 = enable + 0 = disable, default + 4** Enable SA2 decoding for general chip + select 2 + 1 = enable + 0 = disable, default + 3 Reserved + 2 IDE XT selected + 0 = IDE AT interface, default + 1 = IDE XT interface + 1 IDE disable, 1 = IDE disable + 0 = IDE enable + Power Up default set by pin 13 (3221- + DP)/pin 13 (3221-SP) + 0 Secondary IDE + 1 = secondary + 0 = primary, default + Note: Bits 6-4 are reserved in 3221-SP. */ +#define REG_FE_IDE_DISABLE (1 << 1) + + +static void +acc3221_lpt_handle(acc3221_t *dev) +{ + lpt1_remove(); + + if (!(dev->regs[0xbe] & REG_BE_LPT1_DISABLE)) + lpt1_init(dev->regs[0xbf] << 2); +} + + +static void +acc3221_serial1_handler(acc3221_t *dev) +{ + uint16_t com_addr = 0; + + serial_remove(dev->uart[0]); + + if (!(dev->regs[0xdb] & REG_DB_SERIAL1_DISABLE)) { + com_addr = ((dev->regs[0xdc] & 0xfe) << 2); + + if ((dev->regs[0xde] & REG_DE_SIRQ3_SOURCE) == REG_DE_SIRQ3_SERIAL1) + serial_setup(dev->uart[0], com_addr, 3); + else if ((dev->regs[0xde] & REG_DE_SIRQ4_SOURCE) == REG_DE_SIRQ4_SERIAL1) + serial_setup(dev->uart[0], com_addr, 4); + } +} + + +static void +acc3221_serial2_handler(acc3221_t *dev) +{ + uint16_t com_addr = 0; + + serial_remove(dev->uart[1]); + + if (!(dev->regs[0xdb] & REG_DB_SERIAL2_DISABLE)) { + com_addr = ((dev->regs[0xdd] & 0xfe) << 2); + + if ((dev->regs[0xde] & REG_DE_SIRQ3_SOURCE) == REG_DE_SIRQ3_SERIAL2) + serial_setup(dev->uart[1], com_addr, 3); + else if ((dev->regs[0xde] & REG_DE_SIRQ4_SOURCE) == REG_DE_SIRQ4_SERIAL2) + serial_setup(dev->uart[1], com_addr, 4); + else if ((dev->regs[0xde] & REG_DE_PIRQ5_SOURCE) == REG_DE_PIRQ5_SERIAL2) + serial_setup(dev->uart[1], com_addr, 5); + } +} + + +static void +acc3221_write(uint16_t addr, uint8_t val, void *p) +{ + acc3221_t *dev = (acc3221_t *)p; + uint8_t old; + + if (!(addr & 1)) + dev->reg_idx = val; + else { + old = dev->regs[dev->reg_idx]; + dev->regs[dev->reg_idx] = val; + + switch (dev->reg_idx) { + case 0xbe: + if ((old ^ val) & REG_BE_LPT1_DISABLE) + acc3221_lpt_handle(dev); + break; + + case 0xbf: + if (old != val) + acc3221_lpt_handle(dev); + break; + + case 0xdb: + if ((old ^ val) & REG_DB_SERIAL2_DISABLE) + acc3221_serial2_handler(dev); + if ((old ^ val) & REG_DB_SERIAL1_DISABLE) + acc3221_serial1_handler(dev); + break; + + case 0xdc: + if (old != val) + acc3221_serial1_handler(dev); + break; + + case 0xdd: + if (old != val) + acc3221_serial2_handler(dev); + break; + + case 0xde: + if ((old ^ val) & (REG_DE_SIRQ3_SOURCE | REG_DE_SIRQ4_SOURCE)) { + acc3221_serial2_handler(dev); + acc3221_serial1_handler(dev); + } + break; + + case 0xfb: + if ((old ^ val) & REG_FB_FDC_DISABLE) { + fdc_remove(dev->fdc); + if (!(dev->regs[0xfb] & REG_FB_FDC_DISABLE)) + fdc_set_base(dev->fdc, 0x03f0); + } + break; + + case 0xfe: + if ((old ^ val) & REG_FE_IDE_DISABLE) { + ide_pri_disable(); + if (!(dev->regs[0xfe] & REG_FE_IDE_DISABLE)) + ide_pri_enable(); + } + break; + } + } +} + + +static uint8_t +acc3221_read(uint16_t addr, void *p) +{ + acc3221_t *dev = (acc3221_t *)p; + + if (!(addr & 1)) + return dev->reg_idx; + + if (dev->reg_idx < 0xbc) + return 0xff; + + return dev->regs[dev->reg_idx]; +} + + +static void +acc3221_reset(acc3221_t *dev) +{ + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + + lpt1_remove(); + lpt1_init(0x378); + lpt1_irq(7); + + fdc_reset(dev->fdc); +} + +static void +acc3221_close(void *priv) +{ + acc3221_t *dev = (acc3221_t *) priv; + + free(dev); +} + + +static void * +acc3221_init(const device_t *info) +{ + acc3221_t *dev = (acc3221_t *) malloc(sizeof(acc3221_t)); + memset(dev, 0, sizeof(acc3221_t)); + + dev->fdc = device_add(&fdc_at_device); + + dev->uart[0] = device_add_inst(&ns16450_device, 1); + dev->uart[1] = device_add_inst(&ns16450_device, 2); + + io_sethandler(0x00f2, 0x0002, acc3221_read, NULL, NULL, acc3221_write, NULL, NULL, dev); + + acc3221_reset(dev); + + return dev; +} + + +const device_t acc3221_device = { + "ACC 3221-SP Super I/O", + 0, + 0, + acc3221_init, acc3221_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_detect.c b/src/sio_detect.c index 275a9e643..bc0a3e377 100644 --- a/src/sio_detect.c +++ b/src/sio_detect.c @@ -8,7 +8,7 @@ * * Super I/O chip detection code. * - * Version: @(#)sio_detect.c 1.0.0 2018/01/16 + * Version: @(#)sio_detect.c 1.0.1 2018/11/05 * * Authors: Miran Grca, * @@ -16,49 +16,90 @@ */ #include #include +#include #include #include #include "86box.h" #include "device.h" #include "io.h" +#include "timer.h" #include "floppy/fdd.h" #include "floppy/fdc.h" #include "sio.h" -static uint8_t detect_regs[2]; +typedef struct { + uint8_t regs[2]; +} sio_detect_t; -static void superio_detect_write(uint16_t port, uint8_t val, void *priv) +static void +sio_detect_write(uint16_t port, uint8_t val, void *priv) { - pclog("superio_detect_write : port=%04x = %02X\n", port, val); + sio_detect_t *dev = (sio_detect_t *) priv; - detect_regs[port & 1] = val; + pclog("sio_detect_write : port=%04x = %02X\n", port, val); - return; + dev->regs[port & 1] = val; + + return; } -static uint8_t superio_detect_read(uint16_t port, void *priv) +static uint8_t +sio_detect_read(uint16_t port, void *priv) { - pclog("superio_detect_read : port=%04x = %02X\n", port, detect_regs[port & 1]); + sio_detect_t *dev = (sio_detect_t *) priv; - return detect_regs[port & 1]; + pclog("sio_detect_read : port=%04x = %02X\n", port, dev->regs[port & 1]); + + return dev->regs[port & 1]; } -void superio_detect_init(void) +static void +sio_detect_close(void *priv) { - device_add(&fdc_at_smc_device); + sio_detect_t *dev = (sio_detect_t *) priv; - io_sethandler(0x24, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x26, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x2e, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x44, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x46, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x4e, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x108, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x250, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x370, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); - io_sethandler(0x3f0, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + free(dev); } + + +static void * +sio_detect_init(const device_t *info) +{ + sio_detect_t *dev = (sio_detect_t *) malloc(sizeof(sio_detect_t)); + memset(dev, 0, sizeof(sio_detect_t)); + + device_add(&fdc_at_smc_device); + + io_sethandler(0x0024, 0x0004, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x002e, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x0044, 0x0004, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x004e, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x0108, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x0250, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x0370, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + io_sethandler(0x03f0, 0x0002, + sio_detect_read, NULL, NULL, sio_detect_write, NULL, NULL, dev); + + return dev; +} + + +const device_t sio_detect_device = { + "Super I/O Detection Helper", + 0, + 0, + sio_detect_init, sio_detect_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_fdc37c669.c b/src/sio_fdc37c669.c index 58547c55c..1f484af41 100644 --- a/src/sio_fdc37c669.c +++ b/src/sio_fdc37c669.c @@ -8,17 +8,19 @@ * * Implementation of the SMC FDC37C669 Super I/O Chip. * - * Version: @(#)sio_fdc37c669.c 1.0.9 2018/04/29 + * Version: @(#)sio_fdc37c669.c 1.0.10 2018/11/05 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "86box.h" #include "io.h" +#include "timer.h" #include "device.h" #include "pci.h" #include "lpt.h" @@ -30,299 +32,269 @@ #include "sio.h" -static int fdc37c669_locked; -static int fdc37c669_rw_locked = 0; -static int fdc37c669_curreg = 0; -static uint8_t fdc37c669_regs[42]; -static uint8_t tries; -static fdc_t *fdc37c669_fdc; +typedef struct { + uint8_t tries, + regs[42]; + int locked, rw_locked, + cur_reg; + fdc_t *fdc; + serial_t *uart[2]; +} fdc37c669_t; -static uint16_t make_port(uint8_t reg) + +static uint16_t +make_port(fdc37c669_t *dev, uint8_t reg) { - uint16_t p = 0; + uint16_t p = 0; + uint16_t mask = 0; - uint16_t mask = 0; + switch(reg) { + case 0x20: + case 0x21: + case 0x22: + mask = 0xfc; + break; + case 0x23: + mask = 0xff; + break; + case 0x24: + case 0x25: + mask = 0xfe; + break; + } - switch(reg) - { - case 0x20: - case 0x21: - case 0x22: - mask = 0xfc; - break; - case 0x23: - mask = 0xff; - break; - case 0x24: - case 0x25: - mask = 0xfe; - break; - } + p = ((uint16_t) (dev->regs[reg] & mask)) << 2; + if (reg == 0x22) + p |= 6; - p = ((uint16_t) (fdc37c669_regs[reg] & mask)) << 2; - if (reg == 0x22) - { - p |= 6; - } - - return p; + return p; } -void fdc37c669_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t valxor = 0; - uint8_t max = 42; - if (index) - { - if ((val == 0x55) && !fdc37c669_locked) - { - if (tries) - { - fdc37c669_locked = 1; - tries = 0; - } - else - { - tries++; - } - } - else - { - if (fdc37c669_locked) - { - if (val < max) fdc37c669_curreg = val; - if (val == 0xaa) fdc37c669_locked = 0; - } - else - { - if (tries) - tries = 0; - } - } - } - else - { - if (fdc37c669_locked) - { - if ((fdc37c669_curreg < 0x18) && (fdc37c669_rw_locked)) return; - if ((fdc37c669_curreg >= 0x26) && (fdc37c669_curreg <= 0x27)) return; - if (fdc37c669_curreg == 0x29) return; - valxor = val ^ fdc37c669_regs[fdc37c669_curreg]; - fdc37c669_regs[fdc37c669_curreg] = val; - goto process_value; +static void +fdc37c669_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c669_t *dev = (fdc37c669_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint8_t max = 42; + + if (index) { + if ((val == 0x55) && !dev->locked) { + if (dev->tries) { + dev->locked = 1; + dev->tries = 0; + } else + dev->tries++; + } else { + if (dev->locked) { + if (val < max) + dev->cur_reg = val; + if (val == 0xaa) + dev->locked = 0; + } else { + if (dev->tries) + dev->tries = 0; } } return; + } else { + if (dev->locked) { + if ((dev->cur_reg < 0x18) && (dev->rw_locked)) + return; + if ((dev->cur_reg >= 0x26) && (dev->cur_reg <= 0x27)) + return; + if (dev->cur_reg == 0x29) + return; + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + } else + return; + } -process_value: - switch(fdc37c669_curreg) - { - case 0: -#if 0 - if (valxor & 3) - { - ide_pri_disable(); - if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable(); - break; - } -#endif - if (valxor & 8) - { - fdc_remove(fdc37c669_fdc); - if ((fdc37c669_regs[0] & 8) && (fdc37c669_regs[0x20] & 0xc0)) fdc_set_base(fdc37c669_fdc, make_port(0x20)); - } - break; - case 1: - if (valxor & 4) - { - lpt1_remove(); - if ((fdc37c669_regs[1] & 4) && (fdc37c669_regs[0x23] >= 0x40)) - { - lpt1_init(make_port(0x23)); - } - } - if (valxor & 7) - { - fdc37c669_rw_locked = (val & 8) ? 0 : 1; - } - break; - case 2: - if (valxor & 8) - { - serial_remove(1); - if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] >= 0x40)) - { - serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 4); - } - } - if (valxor & 0x80) - { - serial_remove(2); - if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] >= 0x40)) - { - serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0x0F); - } - } - break; - case 3: - if (valxor & 2) fdc_update_enh_mode(fdc37c669_fdc, (val & 2) ? 1 : 0); - break; - case 5: - if (valxor & 0x18) fdc_update_densel_force(fdc37c669_fdc, (val & 0x18) >> 3); - if (valxor & 0x20) fdc_set_swap(fdc37c669_fdc, (val & 0x20) >> 5); - break; - case 0xB: - if (valxor & 3) fdc_update_rwc(fdc37c669_fdc, 0, val & 3); - if (valxor & 0xC) fdc_update_rwc(fdc37c669_fdc, 1, (val & 0xC) >> 2); - break; - case 0x20: - if (valxor & 0xfc) - { - fdc_remove(fdc37c669_fdc); - if ((fdc37c669_regs[0] & 8) && (fdc37c669_regs[0x20] & 0xc0)) fdc_set_base(fdc37c669_fdc, make_port(0x20)); - } - break; - case 0x21: - case 0x22: -#if 0 - if (valxor & 0xfc) - { - ide_pri_disable(); - switch (fdc37c669_curreg) - { - case 0x21: - ide_set_base(0, make_port(0x21)); - break; - case 0x22: - ide_set_side(0, make_port(0x22)); - break; - } - if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable(); - } -#endif - break; - case 0x23: - if (valxor) - { - lpt1_remove(); - if ((fdc37c669_regs[1] & 4) && (fdc37c669_regs[0x23] >= 0x40)) - { - lpt1_init(make_port(0x23)); - } - } - break; - case 0x24: - if (valxor & 0xfe) - { - serial_remove(1); - if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] >= 0x40)) - { - serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 4); - } - } - break; - case 0x25: - if (valxor & 0xfe) - { - serial_remove(2); - if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] >= 0x40)) - { - serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0x0F); - } - } - break; - case 0x28: - if (valxor & 0xf) - { - serial_remove(2); - if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] >= 0x40)) - { - serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0x0F); - } - } - if (valxor & 0xf0) - { - serial_remove(1); - if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] >= 0x40)) - { - serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 4); - } - } - break; - } + switch(dev->cur_reg) { + case 0: + if (valxor & 8) { + fdc_remove(dev->fdc); + if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) + fdc_set_base(dev->fdc, make_port(dev, 0x20)); + } + break; + case 1: + if (valxor & 4) { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } + if (valxor & 7) + dev->rw_locked = (val & 8) ? 0 : 1; + break; + case 2: + if (valxor & 8) { + serial_remove(dev->uart[0]); + if ((dev->regs[2] & 8) && (dev->regs[0x24] >= 0x40)) + serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4); + } + if (valxor & 0x80) { + serial_remove(dev->uart[1]); + if ((dev->regs[2] & 0x80) && (dev->regs[0x25] >= 0x40)) + serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f); + } + break; + case 3: + if (valxor & 2) + fdc_update_enh_mode(dev->fdc, (val & 2) ? 1 : 0); + break; + case 5: + if (valxor & 0x18) + fdc_update_densel_force(dev->fdc, (val & 0x18) >> 3); + if (valxor & 0x20) + fdc_set_swap(dev->fdc, (val & 0x20) >> 5); + break; + case 0xB: + if (valxor & 3) + fdc_update_rwc(dev->fdc, 0, val & 3); + if (valxor & 0xC) + fdc_update_rwc(dev->fdc, 1, (val & 0xC) >> 2); + break; + case 0x20: + if (valxor & 0xfc) { + fdc_remove(dev->fdc); + if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) + fdc_set_base(dev->fdc, make_port(dev, 0x20)); + } + break; + case 0x23: + if (valxor) { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 0x24: + if (valxor & 0xfe) { + serial_remove(dev->uart[0]); + if ((dev->regs[2] & 8) && (dev->regs[0x24] >= 0x40)) + serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4); + } + break; + case 0x25: + if (valxor & 0xfe) { + serial_remove(dev->uart[1]); + if ((dev->regs[2] & 0x80) && (dev->regs[0x25] >= 0x40)) + serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f); + } + break; + case 0x27: + if (valxor & 0xf) + lpt1_irq(val & 0xf); + break; + case 0x28: + if (valxor & 0xf) { + serial_remove(dev->uart[1]); + if ((dev->regs[2] & 0x80) && (dev->regs[0x25] >= 0x40)) + serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f); + } + if (valxor & 0xf0) { + serial_remove(dev->uart[0]); + if ((dev->regs[2] & 8) && (dev->regs[0x24] >= 0x40)) + serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4); + } + break; + } } -uint8_t fdc37c669_read(uint16_t port, void *priv) + +static uint8_t +fdc37c669_read(uint16_t port, void *priv) { - uint8_t index = (port & 1) ? 0 : 1; + fdc37c669_t *dev = (fdc37c669_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; - if (!fdc37c669_locked) - { - return 0xFF; - } + if (dev->locked) { + if (index) + ret = dev->cur_reg; + else if ((dev->cur_reg >= 0x18) || !dev->rw_locked) + ret = dev->regs[dev->cur_reg]; + } - if (index) - return fdc37c669_curreg; - else - { - if ((fdc37c669_curreg < 0x18) && (fdc37c669_rw_locked)) return 0xff; - return fdc37c669_regs[fdc37c669_curreg]; - } + return ret; } -void fdc37c669_reset(void) + +static void +fdc37c669_reset(fdc37c669_t *dev) { - fdc_reset(fdc37c669_fdc); + fdc_reset(dev->fdc); - serial_remove(1); - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - serial_remove(2); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - lpt2_remove(); + lpt1_remove(); + lpt1_init(0x378); - lpt1_remove(); - lpt1_init(0x378); + memset(dev->regs, 0, 42); + dev->regs[0x00] = 0x28; + dev->regs[0x01] = 0x9c; + dev->regs[0x02] = 0x88; + dev->regs[0x03] = 0x78; + dev->regs[0x06] = 0xff; + dev->regs[0x0d] = 0x03; + dev->regs[0x0e] = 0x02; + dev->regs[0x1e] = 0x80; /* Gameport controller. */ + dev->regs[0x20] = (0x3f0 >> 2) & 0xfc; + dev->regs[0x21] = (0x1f0 >> 2) & 0xfc; + dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; + dev->regs[0x23] = (0x378 >> 2); + dev->regs[0x24] = (0x3f8 >> 2) & 0xfe; + dev->regs[0x25] = (0x2f8 >> 2) & 0xfe; + dev->regs[0x26] = (2 << 4) | 3; + dev->regs[0x27] = (6 << 4) | 7; + dev->regs[0x28] = (4 << 4) | 3; - memset(fdc37c669_regs, 0, 42); - fdc37c669_regs[0] = 0x28; - fdc37c669_regs[1] = 0x9C; - fdc37c669_regs[2] = 0x88; - fdc37c669_regs[3] = 0x78; - fdc37c669_regs[4] = 0; - fdc37c669_regs[5] = 0; - fdc37c669_regs[6] = 0xFF; - fdc37c669_regs[7] = 0; - fdc37c669_regs[8] = 0; - fdc37c669_regs[9] = 0; - fdc37c669_regs[0xA] = 0; - fdc37c669_regs[0xB] = 0; - fdc37c669_regs[0xC] = 0; - fdc37c669_regs[0xD] = 3; - fdc37c669_regs[0xE] = 2; - fdc37c669_regs[0x1E] = 0x80; /* Gameport controller. */ - fdc37c669_regs[0x20] = (0x3f0 >> 2) & 0xfc; - fdc37c669_regs[0x21] = (0x1f0 >> 2) & 0xfc; - fdc37c669_regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; - fdc37c669_regs[0x23] = (0x378 >> 2); - fdc37c669_regs[0x24] = (0x3f8 >> 2) & 0xfe; - fdc37c669_regs[0x25] = (0x2f8 >> 2) & 0xfe; - fdc37c669_regs[0x26] = (2 << 4) | 3; - fdc37c669_regs[0x27] = (6 << 4) | 7; - fdc37c669_regs[0x28] = (4 << 4) | 3; - - fdc37c669_locked = 0; - fdc37c669_rw_locked = 0; + dev->locked = 0; + dev->rw_locked = 0; } -void fdc37c669_init() + +static void +fdc37c669_close(void *priv) { - fdc37c669_fdc = device_add(&fdc_at_smc_device); + fdc37c669_t *dev = (fdc37c669_t *) priv; - io_sethandler(0x3f0, 0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, NULL); - - fdc37c669_reset(); + free(dev); } + + +static void * +fdc37c669_init(const device_t *info) +{ + fdc37c669_t *dev = (fdc37c669_t *) malloc(sizeof(fdc37c669_t)); + memset(dev, 0, sizeof(fdc37c669_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + io_sethandler(0x3f0, 0x0002, + fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, dev); + + fdc37c669_reset(dev); + + return dev; +} + + +const device_t fdc37c669_device = { + "SMC FDC37C669 Super I/O", + 0, + 0, + fdc37c669_init, fdc37c669_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_fdc37c66x.c b/src/sio_fdc37c66x.c index a97ee26e9..c1560f920 100644 --- a/src/sio_fdc37c66x.c +++ b/src/sio_fdc37c66x.c @@ -9,20 +9,22 @@ * Implementation of the SMC FDC37C663 and FDC37C665 Super * I/O Chips. * - * Version: @(#)sio_fdc37c66x.c 1.0.11 2018/04/04 + * Version: @(#)sio_fdc37c66x.c 1.0.15 2020/01/11 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. */ #include #include +#include #include #include #include "86box.h" #include "io.h" +#include "timer.h" #include "device.h" #include "pci.h" #include "lpt.h" @@ -34,298 +36,275 @@ #include "sio.h" -static uint8_t fdc37c66x_lock[2]; -static int fdc37c66x_curreg; -static uint8_t fdc37c66x_regs[16]; -static int com3_addr, com4_addr; -static fdc_t *fdc37c66x_fdc; +typedef struct { + uint8_t chip_id, + lock[2], + regs[16]; + int cur_reg, + com3_addr, com4_addr; + fdc_t *fdc; + serial_t *uart[2]; +} fdc37c66x_t; -static void write_lock(uint8_t val) +static void +write_lock(fdc37c66x_t *dev, uint8_t val) { - if (val == 0x55 && fdc37c66x_lock[1] == 0x55) - fdc_3f1_enable(fdc37c66x_fdc, 0); - if (fdc37c66x_lock[0] == 0x55 && fdc37c66x_lock[1] == 0x55 && val != 0x55) - fdc_3f1_enable(fdc37c66x_fdc, 1); + if (val == 0x55 && dev->lock[1] == 0x55) + fdc_3f1_enable(dev->fdc, 0); + if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55) && (val != 0x55)) + fdc_3f1_enable(dev->fdc, 1); - fdc37c66x_lock[0] = fdc37c66x_lock[1]; - fdc37c66x_lock[1] = val; + dev->lock[0] = dev->lock[1]; + dev->lock[1] = val; } -static void ide_handler() + +static void +set_com34_addr(fdc37c66x_t *dev) { -#if 0 - uint16_t or_value = 0; - if ((romset == ROM_440FX) || (romset == ROM_R418) || (romset == ROM_MB500N)) - { - return; - } - ide_pri_disable(); - if (fdc37c66x_regs[0] & 1) - { - if (fdc37c66x_regs[5] & 2) - { - or_value = 0; - } - else - { - or_value = 0x800; - } - ide_set_base(0, 0x170 | or_value); - ide_set_side(0, 0x376 | or_value); - ide_pri_enable(); - } -#endif + switch (dev->regs[1] & 0x60) { + case 0x00: + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; + break; + case 0x20: + dev->com3_addr = 0x3e8; + dev->com4_addr = 0x2e8; + break; + case 0x40: + dev->com3_addr = 0x3e8; + dev->com4_addr = 0x2e0; + break; + case 0x60: + dev->com3_addr = 0x220; + dev->com4_addr = 0x228; + break; + } } -static void set_com34_addr() + +static void +set_serial_addr(fdc37c66x_t *dev, int port) { - switch (fdc37c66x_regs[1] & 0x60) - { - case 0x00: - com3_addr = 0x338; - com4_addr = 0x238; + uint8_t shift = (port << 4); + + if (dev->regs[2] & (4 << shift)) { + switch (dev->regs[2] & (3 << shift)) { + case 0: + serial_setup(dev->uart[port], SERIAL1_ADDR, SERIAL1_IRQ); break; - case 0x20: - com3_addr = 0x3e8; - com4_addr = 0x2e8; - break; - case 0x40: - com3_addr = 0x3e8; - com4_addr = 0x2e0; - break; - case 0x60: - com3_addr = 0x220; - com4_addr = 0x228; - break; - } -} - -static void set_serial1_addr() -{ - if (fdc37c66x_regs[2] & 4) - { - switch (fdc37c66x_regs[2] & 3) - { - case 0: - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - break; - - case 1: - serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); - break; - - case 2: - serial_setup(1, com3_addr, 4); - break; - - case 3: - serial_setup(1, com4_addr, 3); - break; - } - } -} - -static void set_serial2_addr() -{ - if (fdc37c66x_regs[2] & 0x40) - { - switch (fdc37c66x_regs[2] & 0x30) - { - case 0: - serial_setup(2, SERIAL1_ADDR, SERIAL1_IRQ); - break; - - case 1: - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); - break; - - case 2: - serial_setup(2, com3_addr, 4); - break; - - case 3: - serial_setup(2, com4_addr, 3); - break; - } - } -} - -static void lpt1_handler() -{ - lpt1_remove(); - switch (fdc37c66x_regs[1] & 3) - { case 1: - lpt1_init(0x3bc); + serial_setup(dev->uart[port], SERIAL2_ADDR, SERIAL2_IRQ); break; case 2: - lpt1_init(0x378); + serial_setup(dev->uart[port], dev->com3_addr, 4); break; case 3: - lpt1_init(0x278); + serial_setup(dev->uart[port], dev->com4_addr, 3); break; } + } } -static void fdc37c66x_write(uint16_t port, uint8_t val, void *priv) + +static void +lpt1_handler(fdc37c66x_t *dev) { - uint8_t valxor = 0; - if (fdc37c66x_lock[0] == 0x55 && fdc37c66x_lock[1] == 0x55) - { - if (port == 0x3f0) - { - if (val == 0xaa) - write_lock(val); - else - fdc37c66x_curreg = val; -#if 0 - if (fdc37c66x_curreg != 0) - { - fdc37c66x_curreg = val & 0xf; + lpt1_remove(); + switch (dev->regs[1] & 3) { + case 1: + lpt1_init(0x3bc); + lpt1_irq(7); + break; + case 2: + lpt1_init(0x378); + lpt1_irq(5); + break; + case 3: + lpt1_init(0x278); + lpt1_irq(5); + break; + } +} + + +static void +fdc_handler(fdc37c66x_t *dev) +{ + fdc_remove(dev->fdc); + if (dev->regs[0] & 0x10) + fdc_set_base(dev->fdc, (dev->regs[5] & 0x01) ? 0x0370 : 0x03f0); +} + + +static void +fdc37c66x_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c66x_t *dev = (fdc37c66x_t *) priv; + uint8_t valxor = 0; + + if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { + if (port == 0x3f0) { + if (val == 0xaa) + write_lock(dev, val); + else + dev->cur_reg = val; + } else { + if (dev->cur_reg > 15) + return; + + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + + switch(dev->cur_reg) { + case 0: + if (valxor & 0x10) + fdc_handler(dev); + break; + case 1: + if (valxor & 3) + lpt1_handler(dev); + if (valxor & 0x60) { + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + set_com34_addr(dev); + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); } - else - { - /* Hardcode the IDE to AT type. */ - fdc37c66x_curreg = (val & 0xf) | 2; + break; + case 2: + if (valxor & 7) { + serial_remove(dev->uart[0]); + set_serial_addr(dev, 0); } -#endif - } - else - { - if (fdc37c66x_curreg > 15) - return; - - valxor = val ^ fdc37c66x_regs[fdc37c66x_curreg]; - fdc37c66x_regs[fdc37c66x_curreg] = val; - - switch(fdc37c66x_curreg) - { - case 0: - if (valxor & 1) - { - ide_handler(); - } - break; - case 1: - if (valxor & 3) - { - lpt1_handler(); - } - if (valxor & 0x60) - { - serial_remove(1); - set_com34_addr(); - set_serial1_addr(); - set_serial2_addr(); - } - break; - case 2: - if (valxor & 7) - { - serial_remove(1); - set_serial1_addr(); - } - if (valxor & 0x70) - { - serial_remove(2); - set_serial2_addr(); - } - break; - case 3: - if (valxor & 2) - { - fdc_update_enh_mode(fdc37c66x_fdc, (fdc37c66x_regs[3] & 2) ? 1 : 0); - } - break; - case 5: - if (valxor & 2) - { - ide_handler(); - } - if (valxor & 0x18) - { - fdc_update_densel_force(fdc37c66x_fdc, (fdc37c66x_regs[5] & 0x18) >> 3); - } - if (valxor & 0x20) - { - fdc_set_swap(fdc37c66x_fdc, (fdc37c66x_regs[5] & 0x20) >> 5); - } - break; - } - } - } - else - { - if (port == 0x3f0) - write_lock(val); - } + if (valxor & 0x70) { + serial_remove(dev->uart[1]); + set_serial_addr(dev, 1); + } + break; + case 3: + if (valxor & 2) + fdc_update_enh_mode(dev->fdc, (dev->regs[3] & 2) ? 1 : 0); + break; + case 5: + if (valxor & 0x01) + fdc_handler(dev); + if (valxor & 0x18) + fdc_update_densel_force(dev->fdc, (dev->regs[5] & 0x18) >> 3); + if (valxor & 0x20) + fdc_set_swap(dev->fdc, (dev->regs[5] & 0x20) >> 5); + break; + } + } + } else { + if (port == 0x3f0) + write_lock(dev, val); + } } -static uint8_t fdc37c66x_read(uint16_t port, void *priv) + +static uint8_t +fdc37c66x_read(uint16_t port, void *priv) { - if (fdc37c66x_lock[0] == 0x55 && fdc37c66x_lock[1] == 0x55) - { - if (port == 0x3f1) - return fdc37c66x_regs[fdc37c66x_curreg]; - } - return 0xff; + fdc37c66x_t *dev = (fdc37c66x_t *) priv; + uint8_t ret = 0xff; + + if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { + if (port == 0x3f1) + ret = dev->regs[dev->cur_reg]; + } + + return ret; } -static void fdc37c66x_reset(void) + +static void +fdc37c66x_reset(fdc37c66x_t *dev) { - com3_addr = 0x338; - com4_addr = 0x238; + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; - serial_remove(1); - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - serial_remove(2); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - lpt2_remove(); + lpt1_remove(); + lpt1_init(0x378); - lpt1_remove(); - lpt1_init(0x378); + fdc_reset(dev->fdc); - fdc_reset(fdc37c66x_fdc); - - memset(fdc37c66x_lock, 0, 2); - memset(fdc37c66x_regs, 0, 16); - fdc37c66x_regs[0x0] = 0x3a; - fdc37c66x_regs[0x1] = 0x9f; - fdc37c66x_regs[0x2] = 0xdc; - fdc37c66x_regs[0x3] = 0x78; - fdc37c66x_regs[0x6] = 0xff; - fdc37c66x_regs[0xe] = 0x01; + memset(dev->lock, 0, 2); + memset(dev->regs, 0, 16); + + dev->regs[0x0] = 0x3a; + dev->regs[0x1] = 0x9f; + dev->regs[0x2] = 0xdc; + dev->regs[0x3] = 0x78; + dev->regs[0x6] = 0xff; + dev->regs[0xd] = dev->chip_id; + dev->regs[0xe] = 0x01; } -static void fdc37c663_reset(void) + +static void +fdc37c66x_close(void *priv) { - fdc37c66x_reset(); - fdc37c66x_regs[0xd] = 0x63; + fdc37c66x_t *dev = (fdc37c66x_t *) priv; + + free(dev); } -static void fdc37c665_reset(void) + +static void * +fdc37c66x_init(const device_t *info) { - fdc37c66x_reset(); - fdc37c66x_regs[0xd] = 0x65; + fdc37c66x_t *dev = (fdc37c66x_t *) malloc(sizeof(fdc37c66x_t)); + memset(dev, 0, sizeof(fdc37c66x_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->chip_id = info->local; + + io_sethandler(0x03f0, 0x0002, + fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, dev); + + fdc37c66x_reset(dev); + + return dev; } -void fdc37c663_init() -{ - fdc37c66x_fdc = device_add(&fdc_at_smc_device); - io_sethandler(0x03f0, 0x0002, fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, NULL); +/* The three appear to differ only in the chip ID, if I + understood their datasheets correctly. */ +const device_t fdc37c663_device = { + "SMC FDC37C663 Super I/O", + 0, + 0x63, + fdc37c66x_init, fdc37c66x_close, NULL, + NULL, NULL, NULL, + NULL +}; - fdc37c663_reset(); -} +const device_t fdc37c665_device = { + "SMC FDC37C665 Super I/O", + 0, + 0x65, + fdc37c66x_init, fdc37c66x_close, NULL, + NULL, NULL, NULL, + NULL +}; -void fdc37c665_init() -{ - fdc37c66x_fdc = device_add(&fdc_at_smc_device); - - io_sethandler(0x03f0, 0x0002, fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, NULL); - - fdc37c665_reset(); -} +const device_t fdc37c666_device = { + "SMC FDC37C666 Super I/O", + 0, + 0x66, + fdc37c66x_init, fdc37c66x_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_fdc37c93x.c b/src/sio_fdc37c93x.c index 5d2f7816d..e93ffea54 100644 --- a/src/sio_fdc37c93x.c +++ b/src/sio_fdc37c93x.c @@ -9,17 +9,19 @@ * Implementation of the SMC FDC37C932FR and FDC37C935 Super * I/O Chips. * - * Version: @(#)sio_fdc37c93x.c 1.0.13 2018/04/29 + * Version: @(#)sio_fdc37c93x.c 1.0.15 2018/11/12 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "86box.h" #include "io.h" +#include "timer.h" #include "device.h" #include "pci.h" #include "lpt.h" @@ -31,104 +33,9 @@ #include "sio.h" -static int fdc37c93x_locked; -static int fdc37c93x_curreg = 0; -static int fdc37c93x_gpio_reg = 0; -static uint8_t fdc37c93x_regs[48]; -static uint8_t fdc37c93x_ld_regs[10][256]; -static uint16_t fdc37c93x_gpio_base = 0x00EA; -static fdc_t *fdc37c93x_fdc; - -static uint8_t tries; - -static uint16_t make_port(uint8_t ld) -{ - uint16_t r0 = fdc37c93x_ld_regs[ld][0x60]; - uint16_t r1 = fdc37c93x_ld_regs[ld][0x61]; - - uint16_t p = (r0 << 8) + r1; - - return p; -} - -static uint8_t fdc37c93x_gpio_read(uint16_t port, void *priv) -{ - return fdc37c93x_gpio_reg; -} - -static void fdc37c93x_gpio_write(uint16_t port, uint8_t val, void *priv) -{ - fdc37c93x_gpio_reg = val; -} - -static void fdc37c93x_fdc_handler(void) -{ - uint16_t ld_port = 0; - - uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << 0)); - uint8_t local_enable = !!fdc37c93x_ld_regs[0][0x30]; - - fdc_remove(fdc37c93x_fdc); - if (global_enable && local_enable) - { - ld_port = make_port(0); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) { - fdc_set_base(fdc37c93x_fdc, ld_port); - } - } -} - -static void fdc37c93x_lpt_handler(void) -{ - uint16_t ld_port = 0; - - uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << 3)); - uint8_t local_enable = !!fdc37c93x_ld_regs[3][0x30]; - - lpt1_remove(); - if (global_enable && local_enable) - { - ld_port = make_port(3); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) - lpt1_init(ld_port); - } -} - -static void fdc37c93x_serial_handler(int uart) -{ - uint16_t ld_port = 0; - - uint8_t uart_no = 3 + uart; - - uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << uart_no)); - uint8_t local_enable = !!fdc37c93x_ld_regs[uart_no][0x30]; - - serial_remove(uart); - if (global_enable && local_enable) - { - ld_port = make_port(uart_no); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) - serial_setup(uart, ld_port, fdc37c93x_ld_regs[uart_no][0x70]); - } -} - -static void fdc37c93x_auxio_handler(void) -{ - uint16_t ld_port = 0; - - uint8_t local_enable = !!fdc37c93x_ld_regs[8][0x30]; - - io_removehandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); - if (local_enable) - { - fdc37c93x_gpio_base = ld_port = make_port(8); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) - io_sethandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); - } -} - #define AB_RST 0x80 + typedef struct { uint8_t control; uint8_t status; @@ -138,430 +45,648 @@ typedef struct { uint16_t base; } access_bus_t; -static access_bus_t access_bus; +typedef struct { + uint8_t chip_id, tries, + gpio_regs[2], auxio_reg, + regs[48], + ld_regs[10][256]; + uint16_t gpio_base, /* Set to EA */ + auxio_base; + int locked, + cur_reg; + fdc_t *fdc; + serial_t *uart[2]; + access_bus_t *access_bus; +} fdc37c93x_t; -static uint8_t fdc37c932fr_access_bus_read(uint16_t port, void *priv) + +static uint16_t +make_port(fdc37c93x_t *dev, uint8_t ld) { - switch(port & 3) { + uint16_t r0 = dev->ld_regs[ld][0x60]; + uint16_t r1 = dev->ld_regs[ld][0x61]; + + uint16_t p = (r0 << 8) + r1; + + return p; +} + + +static uint8_t +fdc37c93x_auxio_read(uint16_t port, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + return dev->auxio_reg; +} + + +static void +fdc37c93x_auxio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + dev->auxio_reg = val; +} + + +static uint8_t +fdc37c93x_gpio_read(uint16_t port, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + return dev->gpio_regs[port & 1]; +} + + +static void +fdc37c93x_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + dev->gpio_regs[port & 1] = val; +} + + +static void +fdc37c93x_fdc_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 0)); + uint8_t local_enable = !!dev->ld_regs[0][0x30]; + + fdc_remove(dev->fdc); + if (global_enable && local_enable) { + ld_port = make_port(dev, 0); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + fdc_set_base(dev->fdc, ld_port); + } +} + + +static void +fdc37c93x_lpt_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 3)); + uint8_t local_enable = !!dev->ld_regs[3][0x30]; + uint8_t lpt_irq = dev->ld_regs[3][0x70]; + + if (lpt_irq > 15) + lpt_irq = 0xff; + + lpt1_remove(); + if (global_enable && local_enable) { + ld_port = make_port(dev, 3); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + lpt1_init(ld_port); + } + lpt1_irq(lpt_irq); +} + + +static void +fdc37c93x_serial_handler(fdc37c93x_t *dev, int uart) +{ + uint16_t ld_port = 0; + uint8_t uart_no = 4 + uart; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << uart_no)); + uint8_t local_enable = !!dev->ld_regs[uart_no][0x30]; + + serial_remove(dev->uart[uart]); + if (global_enable && local_enable) { + ld_port = make_port(dev, uart_no); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + serial_setup(dev->uart[uart], ld_port, dev->ld_regs[uart_no][0x70]); + } +} + + +static void fdc37c93x_auxio_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable = !!dev->ld_regs[8][0x30]; + + io_removehandler(dev->auxio_base, 0x0001, + fdc37c93x_auxio_read, NULL, NULL, fdc37c93x_auxio_write, NULL, NULL, dev); + if (local_enable) { + dev->auxio_base = ld_port = make_port(dev, 8); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) + io_sethandler(dev->auxio_base, 0x0001, + fdc37c93x_auxio_read, NULL, NULL, fdc37c93x_auxio_write, NULL, NULL, dev); + } +} + + +static void fdc37c93x_gpio_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable; + + local_enable = !!(dev->regs[0x03] & 0x80); + + io_removehandler(dev->gpio_base, 0x0002, + fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); + if (local_enable) { + switch (dev->regs[0x03] & 0x03) { case 0: - return (access_bus.status & 0xBF); + ld_port = 0xe0; break; case 1: - return (access_bus.own_addr & 0x7F); + ld_port = 0xe2; break; case 2: - return access_bus.data; + ld_port = 0xe4; break; case 3: - return (access_bus.clock & 0x87); - break; - default: - return 0xFF; - } -} - -static void fdc37c932fr_access_bus_write(uint16_t port, uint8_t val, void *priv) -{ - switch(port & 3) { - case 0: - access_bus.control = (val & 0xCF); - break; - case 1: - access_bus.own_addr = (val & 0x7F); - break; - case 2: - access_bus.data = val; - break; - case 3: - access_bus.clock &= 0x80; - access_bus.clock |= (val & 0x07); + ld_port = 0xea; /* Default */ break; } + dev->gpio_base = ld_port; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFE)) + io_sethandler(dev->gpio_base, 0x0002, + fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); + } } -static void fdc37c932fr_access_bus_handler(void) +static uint8_t +fdc37c932fr_access_bus_read(uint16_t port, void *priv) { - uint16_t ld_port = 0; + access_bus_t *dev = (access_bus_t *) priv; + uint8_t ret = 0xff; - uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << 6)); - uint8_t local_enable = !!fdc37c93x_ld_regs[9][0x30]; + switch(port & 3) { + case 0: + ret = (dev->status & 0xBF); + break; + case 1: + ret = (dev->own_addr & 0x7F); + break; + case 2: + ret = dev->data; + break; + case 3: + ret = (dev->clock & 0x87); + break; + } - io_removehandler(access_bus.base, 0x0004, fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, NULL); - if (global_enable && local_enable) - { - access_bus.base = ld_port = make_port(9); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) - io_sethandler(access_bus.base, 0x0004, fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, NULL); - } + return ret; } -static void fdc37c93x_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t valxor = 0; - if (index) - { - if ((val == 0x55) && !fdc37c93x_locked) - { - if (tries) - { - fdc37c93x_locked = 1; - fdc_3f1_enable(fdc37c93x_fdc, 0); - tries = 0; - } - else - { - tries++; - } - } - else - { - if (fdc37c93x_locked) - { - if (val == 0xaa) - { - fdc37c93x_locked = 0; - fdc_3f1_enable(fdc37c93x_fdc, 1); - return; - } - fdc37c93x_curreg = val; - } - else - { - if (tries) - tries = 0; - } - } - } - else - { - if (fdc37c93x_locked) - { - if (fdc37c93x_curreg < 48) - { - valxor = val ^ fdc37c93x_regs[fdc37c93x_curreg]; - if ((val == 0x20) || (val == 0x21)) - return; - fdc37c93x_regs[fdc37c93x_curreg] = val; - goto process_value; - } - else - { - valxor = val ^ fdc37c93x_ld_regs[fdc37c93x_regs[7]][fdc37c93x_curreg]; - if (((fdc37c93x_curreg & 0xF0) == 0x70) && (fdc37c93x_regs[7] < 4)) return; - /* Block writes to IDE configuration. */ - if (fdc37c93x_regs[7] == 1) return; - if (fdc37c93x_regs[7] == 2) return; - if ((fdc37c93x_regs[7] > 5) && (fdc37c93x_regs[7] != 8) && (fdc37c93x_regs[7] != 9)) return; - if ((fdc37c93x_regs[7] == 9) && (fdc37c93x_regs[0x20] != 3)) return; - fdc37c93x_ld_regs[fdc37c93x_regs[7]][fdc37c93x_curreg] = val; - goto process_value; +static void +fdc37c932fr_access_bus_write(uint16_t port, uint8_t val, void *priv) +{ + access_bus_t *dev = (access_bus_t *) priv; + + switch(port & 3) { + case 0: + dev->control = (val & 0xCF); + break; + case 1: + dev->own_addr = (val & 0x7F); + break; + case 2: + dev->data = val; + break; + case 3: + dev->clock &= 0x80; + dev->clock |= (val & 0x07); + break; + } +} + + +static void fdc37c932fr_access_bus_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 6)); + uint8_t local_enable = !!dev->ld_regs[9][0x30]; + + io_removehandler(dev->access_bus->base, 0x0004, + fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); + if (global_enable && local_enable) { + dev->access_bus->base = ld_port = make_port(dev, 9); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + io_sethandler(dev->access_bus->base, 0x0004, + fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); + } +} + + +static void +fdc37c93x_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + + if (index) { + if ((val == 0x55) && !dev->locked) { + if (dev->tries) { + dev->locked = 1; + fdc_3f1_enable(dev->fdc, 0); + dev->tries = 0; + } else + dev->tries++; + } else { + if (dev->locked) { + if (val == 0xaa) { + dev->locked = 0; + fdc_3f1_enable(dev->fdc, 1); + return; } + dev->cur_reg = val; + } else { + if (dev->tries) + dev->tries = 0; } } return; + } else { + if (dev->locked) { + if (dev->cur_reg < 48) { + valxor = val ^ dev->regs[dev->cur_reg]; + if ((val == 0x20) || (val == 0x21)) + return; + dev->regs[dev->cur_reg] = val; + } else { + valxor = val ^ dev->ld_regs[dev->regs[7]][dev->cur_reg]; + if (((dev->cur_reg & 0xF0) == 0x70) && (dev->regs[7] < 4)) + return; + /* Block writes to some logical devices. */ + if (dev->regs[7] > 9) + return; + else switch (dev->regs[7]) { + case 1: + case 2: + case 6: + case 7: + return; + case 9: + /* If we're on the FDC37C935, return as this is not a valid + logical device there. */ + if (dev->chip_id == 0x02) + return; + break; + } + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + } + } else + return; + } -process_value: - if (fdc37c93x_curreg < 48) - { - switch(fdc37c93x_curreg) - { - case 0x22: + if (dev->cur_reg < 48) { + switch(dev->cur_reg) { + case 0x03: + if (valxor & 0x83) + fdc37c93x_gpio_handler(dev); + dev->regs[0x03] &= 0x83; + break; + case 0x22: + if (valxor & 0x01) + fdc37c93x_fdc_handler(dev); + if (valxor & 0x08) + fdc37c93x_lpt_handler(dev); + if (valxor & 0x10) + fdc37c93x_serial_handler(dev, 0); + if (valxor & 0x20) + fdc37c93x_serial_handler(dev, 1); + break; + } + + return; + } + + switch(dev->regs[7]) { + case 0: + /* FDD */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + if (valxor) + fdc37c93x_fdc_handler(dev); + break; + case 0xF0: if (valxor & 0x01) - fdc37c93x_fdc_handler(); - if (valxor & 0x08) - fdc37c93x_lpt_handler(); + fdc_update_enh_mode(dev->fdc, val & 0x01); if (valxor & 0x10) - fdc37c93x_serial_handler(1); - if (valxor & 0x20) - fdc37c93x_serial_handler(2); + fdc_set_swap(dev->fdc, (val & 0x10) >> 4); + break; + case 0xF1: + if (valxor & 0xC) + fdc_update_densel_force(dev->fdc, (val & 0xC) >> 2); + break; + case 0xF2: + if (valxor & 0xC0) + fdc_update_rwc(dev->fdc, 3, (valxor & 0xC0) >> 6); + if (valxor & 0x30) + fdc_update_rwc(dev->fdc, 2, (valxor & 0x30) >> 4); + if (valxor & 0x0C) + fdc_update_rwc(dev->fdc, 1, (valxor & 0x0C) >> 2); + if (valxor & 0x03) + fdc_update_rwc(dev->fdc, 0, (valxor & 0x03)); + break; + case 0xF4: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 0, (val & 0x18) >> 3); + break; + case 0xF5: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 1, (val & 0x18) >> 3); + break; + case 0xF6: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 2, (val & 0x18) >> 3); + break; + case 0xF7: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 3, (val & 0x18) >> 3); break; } - - return; - } - - switch(fdc37c93x_regs[7]) - { - case 0: - /* FDD */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - if (valxor) - { - fdc37c93x_fdc_handler(); - } - break; - case 0xF0: - if (valxor & 0x01) fdc_update_enh_mode(fdc37c93x_fdc, val & 0x01); - if (valxor & 0x10) fdc_set_swap(fdc37c93x_fdc, (val & 0x10) >> 4); - break; - case 0xF1: - if (valxor & 0xC) fdc_update_densel_force(fdc37c93x_fdc, (val & 0xC) >> 2); - break; - case 0xF2: - if (valxor & 0xC0) fdc_update_rwc(fdc37c93x_fdc, 3, (valxor & 0xC0) >> 6); - if (valxor & 0x30) fdc_update_rwc(fdc37c93x_fdc, 2, (valxor & 0x30) >> 4); - if (valxor & 0x0C) fdc_update_rwc(fdc37c93x_fdc, 1, (valxor & 0x0C) >> 2); - if (valxor & 0x03) fdc_update_rwc(fdc37c93x_fdc, 0, (valxor & 0x03)); - break; - case 0xF4: - if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 0, (val & 0x18) >> 3); - break; - case 0xF5: - if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 1, (val & 0x18) >> 3); - break; - case 0xF6: - if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 2, (val & 0x18) >> 3); - break; - case 0xF7: - if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 3, (val & 0x18) >> 3); - break; - } - break; - case 3: - /* Parallel port */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - if (valxor) - { - fdc37c93x_lpt_handler(); - } - break; - } - break; - case 4: - /* Serial port 1 */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if (valxor) - { - fdc37c93x_serial_handler(1); - } - break; - } - break; - case 5: - /* Serial port 2 */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if (valxor) - { - fdc37c93x_serial_handler(2); - } - break; - } - break; - case 8: - /* Auxiliary I/O */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if (valxor) - { - fdc37c93x_auxio_handler(); - } - break; - } - break; - case 9: - /* Access bus (FDC37C932FR only) */ - switch(fdc37c93x_curreg) - { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if (valxor) - { - fdc37c932fr_access_bus_handler(); - } - break; - } - break; - } + break; + case 3: + /* Parallel port */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_lpt_handler(dev); + break; + } + break; + case 4: + /* Serial port 1 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_serial_handler(dev, 0); + break; + } + break; + case 5: + /* Serial port 2 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_serial_handler(dev, 1); + break; + } + break; + case 8: + /* Auxiliary I/O */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_auxio_handler(dev); + break; + } + break; + case 9: + /* Access bus (FDC37C932FR only) */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c932fr_access_bus_handler(dev); + break; + } + break; + } } + static uint8_t fdc37c93x_read(uint16_t port, void *priv) { - uint8_t index = (port & 1) ? 0 : 1; - - if (!fdc37c93x_locked) - { - return 0xff; - } + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; + if (dev->locked) { if (index) - return fdc37c93x_curreg; - else - { - if (fdc37c93x_curreg < 0x30) - { - return fdc37c93x_regs[fdc37c93x_curreg]; - } - else - { - if ((fdc37c93x_regs[7] == 0) && (fdc37c93x_curreg == 0xF2)) return (fdc_get_rwc(fdc37c93x_fdc, 0) | (fdc_get_rwc(fdc37c93x_fdc, 1) << 2)); - return fdc37c93x_ld_regs[fdc37c93x_regs[7]][fdc37c93x_curreg]; + ret = dev->cur_reg; + else { + if (dev->cur_reg < 0x30) { + if (dev->cur_reg == 0x20) + ret = dev->chip_id; + else + ret = dev->regs[dev->cur_reg]; + } else { + if ((dev->regs[7] == 0) && (dev->cur_reg == 0xF2)) { + ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | + (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); + } else + ret = dev->ld_regs[dev->regs[7]][dev->cur_reg]; } } + } + + return ret; } -static void fdc37c93x_reset(void) + +static void +fdc37c93x_reset(fdc37c93x_t *dev) { - int i = 0; + int i = 0; - memset(fdc37c93x_regs, 0, 48); + memset(dev->regs, 0, 48); - fdc37c93x_regs[0x03] = 3; - fdc37c93x_regs[0x21] = 1; - fdc37c93x_regs[0x22] = 0x39; - fdc37c93x_regs[0x24] = 4; - fdc37c93x_regs[0x26] = 0xF0; - fdc37c93x_regs[0x27] = 3; + dev->regs[0x03] = 0x03; + dev->regs[0x21] = 0x01; + dev->regs[0x20] = dev->chip_id; + dev->regs[0x22] = 0x39; + dev->regs[0x24] = 0x04; + dev->regs[0x26] = 0xF0; + dev->regs[0x27] = 0x03; - for (i = 0; i < 10; i++) - { - memset(fdc37c93x_ld_regs[i], 0, 256); - } + for (i = 0; i < 10; i++) + memset(dev->ld_regs[i], 0, 256); - /* Logical device 0: FDD */ - fdc37c93x_ld_regs[0][0x30] = 1; - fdc37c93x_ld_regs[0][0x60] = 3; - fdc37c93x_ld_regs[0][0x61] = 0xF0; - fdc37c93x_ld_regs[0][0x70] = 6; - fdc37c93x_ld_regs[0][0x74] = 2; - fdc37c93x_ld_regs[0][0xF0] = 0xE; - fdc37c93x_ld_regs[0][0xF2] = 0xFF; + /* Logical device 0: FDD */ + dev->ld_regs[0][0x30] = 1; + dev->ld_regs[0][0x60] = 3; + dev->ld_regs[0][0x61] = 0xF0; + dev->ld_regs[0][0x70] = 6; + dev->ld_regs[0][0x74] = 2; + dev->ld_regs[0][0xF0] = 0xE; + dev->ld_regs[0][0xF2] = 0xFF; - /* Logical device 1: IDE1 */ - fdc37c93x_ld_regs[1][0x30] = 0; - fdc37c93x_ld_regs[1][0x60] = 1; - fdc37c93x_ld_regs[1][0x61] = 0xF0; - fdc37c93x_ld_regs[1][0x62] = 3; - fdc37c93x_ld_regs[1][0x63] = 0xF6; - fdc37c93x_ld_regs[1][0x70] = 0xE; - fdc37c93x_ld_regs[1][0xF0] = 0xC; + /* Logical device 1: IDE1 */ + dev->ld_regs[1][0x30] = 0; + dev->ld_regs[1][0x60] = 1; + dev->ld_regs[1][0x61] = 0xF0; + dev->ld_regs[1][0x62] = 3; + dev->ld_regs[1][0x63] = 0xF6; + dev->ld_regs[1][0x70] = 0xE; + dev->ld_regs[1][0xF0] = 0xC; - /* Logical device 2: IDE2 */ - fdc37c93x_ld_regs[2][0x30] = 0; - fdc37c93x_ld_regs[2][0x60] = 1; - fdc37c93x_ld_regs[2][0x61] = 0x70; - fdc37c93x_ld_regs[2][0x62] = 3; - fdc37c93x_ld_regs[2][0x63] = 0x76; - fdc37c93x_ld_regs[2][0x70] = 0xF; + /* Logical device 2: IDE2 */ + dev->ld_regs[2][0x30] = 0; + dev->ld_regs[2][0x60] = 1; + dev->ld_regs[2][0x61] = 0x70; + dev->ld_regs[2][0x62] = 3; + dev->ld_regs[2][0x63] = 0x76; + dev->ld_regs[2][0x70] = 0xF; - /* Logical device 3: Parallel Port */ - fdc37c93x_ld_regs[3][0x30] = 1; - fdc37c93x_ld_regs[3][0x60] = 3; - fdc37c93x_ld_regs[3][0x61] = 0x78; - fdc37c93x_ld_regs[3][0x70] = 7; - fdc37c93x_ld_regs[3][0x74] = 4; - fdc37c93x_ld_regs[3][0xF0] = 0x3C; + /* Logical device 3: Parallel Port */ + dev->ld_regs[3][0x30] = 1; + dev->ld_regs[3][0x60] = 3; + dev->ld_regs[3][0x61] = 0x78; + dev->ld_regs[3][0x70] = 7; + dev->ld_regs[3][0x74] = 4; + dev->ld_regs[3][0xF0] = 0x3C; - /* Logical device 4: Serial Port 1 */ - fdc37c93x_ld_regs[4][0x30] = 1; - fdc37c93x_ld_regs[4][0x60] = 3; - fdc37c93x_ld_regs[4][0x61] = 0xf8; - fdc37c93x_ld_regs[4][0x70] = 4; - fdc37c93x_ld_regs[4][0xF0] = 3; - serial_setup(1, 0x3f8, fdc37c93x_ld_regs[4][0x70]); + /* Logical device 4: Serial Port 1 */ + dev->ld_regs[4][0x30] = 1; + dev->ld_regs[4][0x60] = 3; + dev->ld_regs[4][0x61] = 0xf8; + dev->ld_regs[4][0x70] = 4; + dev->ld_regs[4][0xF0] = 3; + serial_setup(dev->uart[0], 0x3f8, dev->ld_regs[4][0x70]); - /* Logical device 5: Serial Port 2 */ - fdc37c93x_ld_regs[5][0x30] = 1; - fdc37c93x_ld_regs[5][0x60] = 2; - fdc37c93x_ld_regs[5][0x61] = 0xf8; - fdc37c93x_ld_regs[5][0x70] = 3; - fdc37c93x_ld_regs[5][0x74] = 4; - fdc37c93x_ld_regs[5][0xF1] = 2; - fdc37c93x_ld_regs[5][0xF2] = 3; - serial_setup(2, 0x2f8, fdc37c93x_ld_regs[5][0x70]); + /* Logical device 5: Serial Port 2 */ + dev->ld_regs[5][0x30] = 1; + dev->ld_regs[5][0x60] = 2; + dev->ld_regs[5][0x61] = 0xf8; + dev->ld_regs[5][0x70] = 3; + dev->ld_regs[5][0x74] = 4; + dev->ld_regs[5][0xF1] = 2; + dev->ld_regs[5][0xF2] = 3; + serial_setup(dev->uart[1], 0x2f8, dev->ld_regs[5][0x70]); - /* Logical device 6: RTC */ - fdc37c93x_ld_regs[6][0x63] = 0x70; - fdc37c93x_ld_regs[6][0xF4] = 3; + /* Logical device 6: RTC */ + dev->ld_regs[6][0x63] = 0x70; + dev->ld_regs[6][0xF4] = 3; - /* Logical device 7: Keyboard */ - fdc37c93x_ld_regs[7][0x30] = 1; - fdc37c93x_ld_regs[7][0x61] = 0x60; - fdc37c93x_ld_regs[7][0x70] = 1; + /* Logical device 7: Keyboard */ + dev->ld_regs[7][0x30] = 1; + dev->ld_regs[7][0x61] = 0x60; + dev->ld_regs[7][0x70] = 1; - /* Logical device 8: Auxiliary I/O */ - fdc37c93x_ld_regs[8][0x30] = 1; - fdc37c93x_ld_regs[8][0x61] = 0xEA; + /* Logical device 8: Auxiliary I/O */ - /* Logical device 8: AUX I/O */ + /* Logical device 9: ACCESS.bus */ - /* Logical device 9: ACCESS.bus */ + fdc37c93x_gpio_handler(dev); + fdc37c93x_lpt_handler(dev); + fdc37c93x_serial_handler(dev, 0); + fdc37c93x_serial_handler(dev, 1); + fdc37c93x_auxio_handler(dev); + if (dev->chip_id == 0x03) + fdc37c932fr_access_bus_handler(dev); - io_removehandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); - fdc37c93x_gpio_base = 0x00EA; - io_sethandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); + fdc_reset(dev->fdc); + fdc37c93x_fdc_handler(dev); - fdc37c93x_lpt_handler(); - fdc37c93x_serial_handler(1); - fdc37c93x_serial_handler(2); - fdc37c93x_auxio_handler(); - - fdc_reset(fdc37c93x_fdc); - - fdc37c93x_locked = 0; + dev->locked = 0; } -static void fdc37c932fr_reset(void) + +static void +access_bus_close(void *priv) { - fdc37c93x_reset(); + access_bus_t *dev = (access_bus_t *) priv; - fdc37c93x_regs[0x20] = 3; - - fdc37c932fr_access_bus_handler(); + free(dev); } -static void fdc37c935_reset(void) + +static void * +access_bus_init(const device_t *info) { - fdc37c93x_reset(); + access_bus_t *dev = (access_bus_t *) malloc(sizeof(access_bus_t)); + memset(dev, 0, sizeof(access_bus_t)); - fdc37c93x_regs[0x20] = 2; + return dev; } -static void fdc37c93x_init(void) + +static const device_t access_bus_device = { + "SMC FDC37C932FR ACCESS.bus", + 0, + 0x03, + access_bus_init, access_bus_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +static void +fdc37c93x_close(void *priv) { - lpt2_remove(); + fdc37c93x_t *dev = (fdc37c93x_t *) priv; - fdc37c93x_fdc = device_add(&fdc_at_smc_device); - - fdc37c93x_gpio_reg = 0xFD; - - io_sethandler(0x3f0, 0x0002, fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, NULL); + free(dev); } -void fdc37c932fr_init(void) + +static void * +fdc37c93x_init(const device_t *info) { - fdc37c93x_init(); - fdc37c932fr_reset(); + fdc37c93x_t *dev = (fdc37c93x_t *) malloc(sizeof(fdc37c93x_t)); + memset(dev, 0, sizeof(fdc37c93x_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->chip_id = info->local; + + dev->gpio_regs[0] = 0xFD; + dev->gpio_regs[1] = 0xFF; + + if (dev->chip_id == 0x03) + dev->access_bus = device_add(&access_bus_device); + + io_sethandler(0x3f0, 0x0002, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + + fdc37c93x_reset(dev); + + return dev; } -void fdc37c935_init(void) -{ - fdc37c93x_init(); - fdc37c935_reset(); -} + +const device_t fdc37c932fr_device = { + "SMC FDC37C932FR Super I/O", + 0, + 0x03, + fdc37c93x_init, fdc37c93x_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t fdc37c932qf_device = { + "SMC FDC37C932QF Super I/O", + 0, + 0x02, /* Share the same ID with the 935. */ + fdc37c93x_init, fdc37c93x_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t fdc37c935_device = { + "SMC FDC37C935 Super I/O", + 0, + 0x02, + fdc37c93x_init, fdc37c93x_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_pc87306.c b/src/sio_pc87306.c index 3761d53d5..c2d3ceaf8 100644 --- a/src/sio_pc87306.c +++ b/src/sio_pc87306.c @@ -8,17 +8,19 @@ * * Emulation of the NatSemi PC87306 Super I/O chip. * - * Version: @(#)sio_pc87306.c 1.0.12 2018/05/11 + * Version: @(#)sio_pc87306.c 1.0.15 2018/11/12 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "86box.h" #include "io.h" +#include "timer.h" #include "device.h" #include "lpt.h" #include "mem.h" @@ -29,427 +31,395 @@ #include "disk/hdc_ide.h" #include "floppy/fdd.h" #include "floppy/fdc.h" -#include "machine/machine.h" #include "sio.h" -static int pc87306_curreg; -static uint8_t pc87306_regs[29]; -static uint8_t pc87306_gpio[2] = {0xFF, 0xFB}; -static fdc_t *pc87306_fdc; -static uint8_t tries; -static uint16_t lpt_port; +typedef struct { + uint8_t tries, + regs[29], gpio[2]; + int cur_reg; + fdc_t *fdc; + serial_t *uart[2]; +} pc87306_t; -void pc87306_gpio_remove(); -void pc87306_gpio_init(); -void pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) +static void +pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) { - pc87306_gpio[port & 1] = val; + pc87306_t *dev = (pc87306_t *) priv; + + dev->gpio[port & 1] = val; } -uint8_t uart1_int() + +uint8_t +pc87306_gpio_read(uint16_t port, void *priv) { - uint8_t fer_irq, pnp1_irq; - fer_irq = ((pc87306_regs[1] >> 2) & 1) ? 3 : 4; /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ - pnp1_irq = ((pc87306_regs[0x1C] >> 2) & 1) ? 4 : 3; - return (pc87306_regs[0x1C] & 1) ? pnp1_irq : fer_irq; + pc87306_t *dev = (pc87306_t *) priv; + + return dev->gpio[port & 1]; } -uint8_t uart2_int() + +static void +pc87306_gpio_remove(pc87306_t *dev) { - uint8_t fer_irq, pnp1_irq; - fer_irq = ((pc87306_regs[1] >> 4) & 1) ? 3 : 4; /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ - pnp1_irq = ((pc87306_regs[0x1C] >> 6) & 1) ? 4 : 3; - return (pc87306_regs[0x1C] & 1) ? pnp1_irq : fer_irq; + io_removehandler(dev->regs[0x0f] << 2, 0x0001, + pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev); + io_removehandler((dev->regs[0x0f] << 2) + 1, 0x0001, + pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev); } -void lpt1_handler() + +static void +pc87306_gpio_init(pc87306_t *dev) { - int temp; - uint16_t lptba; - temp = pc87306_regs[0x01] & 3; - lptba = ((uint16_t) pc87306_regs[0x19]) << 2; - if (pc87306_regs[0x1B] & 0x10) { - if (pc87306_regs[0x1B] & 0x20) - lpt_port = 0x278; - else - lpt_port = 0x378; + if ((dev->regs[0x12]) & 0x10) + io_sethandler(dev->regs[0x0f] << 2, 0x0001, + pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev); + + if ((dev->regs[0x12]) & 0x20) + io_sethandler((dev->regs[0x0f] << 2) + 1, 0x0001, + pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev); +} + + +static void +lpt1_handler(pc87306_t *dev) +{ + int temp; + uint16_t lptba, lpt_port = 0x378; + uint8_t lpt_irq = 5; + + temp = dev->regs[0x01] & 3; + lptba = ((uint16_t) dev->regs[0x19]) << 2; + + if (dev->regs[0x1b] & 0x10) { + if (dev->regs[0x1b] & 0x20) { + lpt_port = 0x278; + lpt_irq = 7; } else { - switch (temp) { - case 0: - lpt_port = 0x378; - break; - case 1: - lpt_port = lptba; - break; - case 2: - lpt_port = 0x278; - break; - case 3: - lpt_port = 0x000; - break; - } + lpt_port = 0x378; + lpt_irq = 5; } - if (lpt_port) - lpt1_init(lpt_port); -} - -void serial1_handler() -{ - int temp; - temp = (pc87306_regs[1] >> 2) & 3; - switch (temp) - { - case 0: serial_setup(1, SERIAL1_ADDR, uart1_int()); break; - case 1: serial_setup(1, SERIAL2_ADDR, uart1_int()); break; - case 2: - switch ((pc87306_regs[1] >> 6) & 3) - { - case 0: serial_setup(1, 0x3e8, uart1_int()); break; - case 1: serial_setup(1, 0x338, uart1_int()); break; - case 2: serial_setup(1, 0x2e8, uart1_int()); break; - case 3: serial_setup(1, 0x220, uart1_int()); break; - } - break; - case 3: - switch ((pc87306_regs[1] >> 6) & 3) - { - case 0: serial_setup(1, 0x2e8, uart1_int()); break; - case 1: serial_setup(1, 0x238, uart1_int()); break; - case 2: serial_setup(1, 0x2e0, uart1_int()); break; - case 3: serial_setup(1, 0x228, uart1_int()); break; - } - break; - } -} - -void serial2_handler() -{ - int temp; - temp = (pc87306_regs[1] >> 4) & 3; - switch (temp) - { - case 0: serial_setup(2, SERIAL1_ADDR, uart2_int()); break; - case 1: serial_setup(2, SERIAL2_ADDR, uart2_int()); break; - case 2: - switch ((pc87306_regs[1] >> 6) & 3) - { - case 0: serial_setup(2, 0x3e8, uart2_int()); break; - case 1: serial_setup(2, 0x338, uart2_int()); break; - case 2: serial_setup(2, 0x2e8, uart2_int()); break; - case 3: serial_setup(2, 0x220, uart2_int()); break; - } - break; - case 3: - switch ((pc87306_regs[1] >> 6) & 3) - { - case 0: serial_setup(2, 0x2e8, uart2_int()); break; - case 1: serial_setup(2, 0x238, uart2_int()); break; - case 2: serial_setup(2, 0x2e0, uart2_int()); break; - case 3: serial_setup(2, 0x228, uart2_int()); break; - } - break; - } -} - -void pc87306_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t index, valxor; - - index = (port & 1) ? 0 : 1; - - if (index) - { - pc87306_curreg = val & 0x1f; - tries = 0; - return; - } - else - { - if (tries) - { - if ((pc87306_curreg == 0) && (val == 8)) - { - val = 0x4b; - } - valxor = val ^ pc87306_regs[pc87306_curreg]; - tries = 0; - if ((pc87306_curreg == 0x19) && !(pc87306_regs[0x1B] & 0x40)) - { - return; - } - if ((pc87306_curreg <= 28) && (pc87306_curreg != 8)/* && (pc87306_curreg != 0x18)*/) - { - if (pc87306_curreg == 0) - { - val &= 0x5f; - } - if (((pc87306_curreg == 0x0F) || (pc87306_curreg == 0x12)) && valxor) - { - pc87306_gpio_remove(); - } - pc87306_regs[pc87306_curreg] = val; - goto process_value; - } - } - else - { - tries++; - return; - } - } - return; - -process_value: - switch(pc87306_curreg) - { + } else { + switch (temp) { case 0: - if (valxor & 1) - { - lpt1_remove(); - if (val & 1) - { - lpt1_handler(); - } - } - - if (valxor & 2) - { - serial_remove(1); - if (val & 2) - { - serial1_handler(); - } - } - if (valxor & 4) - { - serial_remove(2); - if (val & 4) - { - serial2_handler(); - } - } - if (valxor & 0x28) - { - fdc_remove(pc87306_fdc); - if (val & 8) - { - fdc_set_base(pc87306_fdc, (val & 0x20) ? 0x370 : 0x3f0); - } - } + lpt_port = 0x378; + lpt_irq = (dev->regs[0x02] & 0x08) ? 7 : 5; break; case 1: - if (valxor & 3) - { - lpt1_remove(); - if (pc87306_regs[0] & 1) - { - lpt1_handler(); - } - } - - if (valxor & 0xcc) - { - if (pc87306_regs[0] & 2) - { - serial1_handler(); - } - else - { - serial_remove(1); - } - } - - if (valxor & 0xf0) - { - if (pc87306_regs[0] & 4) - { - serial2_handler(); - } - else - { - serial_remove(2); - } - } + lpt_port = lptba; + lpt_irq = 7; break; case 2: - if (valxor & 1) - { - if (val & 1) - { - lpt1_remove(); - serial_remove(1); - serial_remove(2); - fdc_remove(pc87306_fdc); - } - else - { - if (pc87306_regs[0] & 1) - { - lpt1_handler(); - } - if (pc87306_regs[0] & 2) - { - serial1_handler(); - } - if (pc87306_regs[0] & 4) - { - serial2_handler(); - } - if (pc87306_regs[0] & 8) - { - fdc_set_base(pc87306_fdc, (pc87306_regs[0] & 0x20) ? 0x370 : 0x3f0); - } - } - } + lpt_port = 0x278; + lpt_irq = 5; break; - case 9: - if (valxor & 0x44) - { - fdc_update_enh_mode(pc87306_fdc, (val & 4) ? 1 : 0); - fdc_update_densel_polarity(pc87306_fdc, (val & 0x40) ? 1 : 0); - } - break; - case 0xF: - if (valxor) - { - pc87306_gpio_init(); - } - break; - case 0x12: - if (valxor & 0x30) - { - pc87306_gpio_init(); - } - break; - case 0x19: - if (valxor) - { - lpt1_remove(); - if (pc87306_regs[0] & 1) - { - lpt1_handler(); - } - } - break; - case 0x1B: - if (valxor & 0x70) - { - lpt1_remove(); - if (!(val & 0x40)) - { - pc87306_regs[0x19] = 0xEF; - } - if (pc87306_regs[0] & 1) - { - lpt1_handler(); - } - } - break; - case 0x1C: - if (valxor) - { - if (pc87306_regs[0] & 2) - { - serial1_handler(); - } - if (pc87306_regs[0] & 4) - { - serial2_handler(); - } - } + case 3: + lpt_port = 0x000; + lpt_irq = 0xff; break; } + } + + if (lpt_port) + lpt1_init(lpt_port); + + lpt1_irq(lpt_irq); } -uint8_t pc87306_gpio_read(uint16_t port, void *priv) + +static void +serial_handler(pc87306_t *dev, int uart) { - return pc87306_gpio[port & 1]; -} + int temp; + uint8_t fer_irq, pnp1_irq; + uint8_t fer_shift, pnp_shift; + uint8_t irq; -uint8_t pc87306_read(uint16_t port, void *priv) -{ - uint8_t index; - index = (port & 1) ? 0 : 1; + temp = (dev->regs[1] >> (2 << uart)) & 3; - tries = 0; + fer_shift = 2 << uart; /* 2 for UART 1, 4 for UART 2 */ + pnp_shift = 2 + (uart << 2); /* 2 for UART 1, 6 for UART 2 */ - if (index) - { - return pc87306_curreg & 0x1f; - } - else - { - if (pc87306_curreg >= 28) - { - return 0xff; + /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ + fer_irq = ((dev->regs[1] >> fer_shift) & 1) ? 3 : 4; + pnp1_irq = ((dev->regs[0x1c] >> pnp_shift) & 1) ? 4 : 3; + + irq = (dev->regs[0x1c] & 1) ? pnp1_irq : fer_irq; + + switch (temp) { + case 0: + serial_setup(dev->uart[uart], SERIAL1_ADDR, irq); + break; + case 1: + serial_setup(dev->uart[uart], SERIAL2_ADDR, irq); + break; + case 2: + switch ((dev->regs[1] >> 6) & 3) { + case 0: + serial_setup(dev->uart[uart], 0x3e8, irq); + break; + case 1: + serial_setup(dev->uart[uart], 0x338, irq); + break; + case 2: + serial_setup(dev->uart[uart], 0x2e8, irq); + break; + case 3: + serial_setup(dev->uart[uart], 0x220, irq); + break; } - else if (pc87306_curreg == 8) - { - return 0x70; + break; + case 3: + switch ((dev->regs[1] >> 6) & 3) { + case 0: + serial_setup(dev->uart[uart], 0x2e8, irq); + break; + case 1: + serial_setup(dev->uart[uart], 0x238, irq); + break; + case 2: + serial_setup(dev->uart[uart], 0x2e0, irq); + break; + case 3: + serial_setup(dev->uart[uart], 0x228, irq); + break; } - else - { - return pc87306_regs[pc87306_curreg]; + break; + } +} + + +static void +pc87306_write(uint16_t port, uint8_t val, void *priv) +{ + pc87306_t *dev = (pc87306_t *) priv; + uint8_t index, valxor; + + index = (port & 1) ? 0 : 1; + + if (index) { + dev->cur_reg = val & 0x1f; + dev->tries = 0; + return; + } else { + if (dev->tries) { + if ((dev->cur_reg == 0) && (val == 8)) + val = 0x4b; + valxor = val ^ dev->regs[dev->cur_reg]; + dev->tries = 0; + if ((dev->cur_reg == 0x19) && !(dev->regs[0x1B] & 0x40)) + return; + if ((dev->cur_reg <= 28) && (dev->cur_reg != 8)) { + if (dev->cur_reg == 0) + val &= 0x5f; + if (((dev->cur_reg == 0x0F) || (dev->cur_reg == 0x12)) && valxor) + pc87306_gpio_remove(dev); + dev->regs[dev->cur_reg] = val; + } else + return; + } else { + dev->tries++; + return; + } + } + + switch(dev->cur_reg) { + case 0: + if (valxor & 1) { + lpt1_remove(); + if (val & 1) + lpt1_handler(dev); } - } + if (valxor & 2) { + serial_remove(dev->uart[0]); + if (val & 2) + serial_handler(dev, 0); + } + if (valxor & 4) { + serial_remove(dev->uart[1]); + if (val & 4) + serial_handler(dev, 1); + } + if (valxor & 0x28) { + fdc_remove(dev->fdc); + if (val & 8) + fdc_set_base(dev->fdc, (val & 0x20) ? 0x370 : 0x3f0); + } + break; + case 1: + if (valxor & 3) { + lpt1_remove(); + if (dev->regs[0] & 1) + lpt1_handler(dev); + } + if (valxor & 0xcc) { + if (dev->regs[0] & 2) + serial_handler(dev, 0); + else + serial_remove(dev->uart[0]); + } + if (valxor & 0xf0) { + if (dev->regs[0] & 4) + serial_handler(dev, 1); + else + serial_remove(dev->uart[1]); + } + break; + case 2: + if (valxor & 1) { + lpt1_remove(); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + fdc_remove(dev->fdc); + + if (!(val & 1)) { + if (dev->regs[0] & 1) + lpt1_handler(dev); + if (dev->regs[0] & 2) + serial_handler(dev, 0); + if (dev->regs[0] & 4) + serial_handler(dev, 1); + if (dev->regs[0] & 8) + fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? 0x370 : 0x3f0); + } + } + break; + case 9: + if (valxor & 0x44) { + fdc_update_enh_mode(dev->fdc, (val & 4) ? 1 : 0); + fdc_update_densel_polarity(dev->fdc, (val & 0x40) ? 1 : 0); + } + break; + case 0xF: + if (valxor) + pc87306_gpio_init(dev); + break; + case 0x12: + if (valxor & 0x30) + pc87306_gpio_init(dev); + break; + case 0x19: + if (valxor) { + lpt1_remove(); + if (dev->regs[0] & 1) + lpt1_handler(dev); + } + break; + case 0x1B: + if (valxor & 0x70) { + lpt1_remove(); + if (!(val & 0x40)) + dev->regs[0x19] = 0xEF; + if (dev->regs[0] & 1) + lpt1_handler(dev); + } + break; + case 0x1C: + if (valxor) { + if (dev->regs[0] & 2) + serial_handler(dev, 0); + if (dev->regs[0] & 4) + serial_handler(dev, 1); + } + break; + } } -void pc87306_gpio_remove() + +uint8_t +pc87306_read(uint16_t port, void *priv) { - io_removehandler(pc87306_regs[0xF] << 2, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); + pc87306_t *dev = (pc87306_t *) priv; + uint8_t ret = 0xff, index; + + index = (port & 1) ? 0 : 1; + + dev->tries = 0; + + if (index) + ret = dev->cur_reg & 0x1f; + else { + if (dev->cur_reg == 8) + ret = 0x70; + else if (dev->cur_reg < 28) + ret = dev->regs[dev->cur_reg]; + } + + return ret; } -void pc87306_gpio_init() + +void +pc87306_reset(pc87306_t *dev) { - if ((pc87306_regs[0x12]) & 0x10) - { - io_sethandler(pc87306_regs[0xF] << 2, 0x0001, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); - } + memset(dev->regs, 0, 29); - if ((pc87306_regs[0x12]) & 0x20) - { - io_sethandler((pc87306_regs[0xF] << 2) + 1, 0x0001, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); - } + dev->regs[0x00] = 0x0B; + dev->regs[0x01] = 0x01; + dev->regs[0x03] = 0x01; + dev->regs[0x05] = 0x0D; + dev->regs[0x08] = 0x70; + dev->regs[0x09] = 0xC0; + dev->regs[0x0b] = 0x80; + dev->regs[0x0f] = 0x1E; + dev->regs[0x12] = 0x30; + dev->regs[0x19] = 0xEF; + + dev->gpio[0] = 0xff; + dev->gpio[1] = 0xfb; + + /* + 0 = 360 rpm @ 500 kbps for 3.5" + 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" + */ + lpt1_remove(); + lpt1_handler(dev); + serial_remove(dev->uart[0]); + serial_remove(dev->uart[1]); + serial_handler(dev, 0); + serial_handler(dev, 1); + fdc_reset(dev->fdc); + pc87306_gpio_init(dev); } -void pc87306_reset(void) + +static void +pc87306_close(void *priv) { - memset(pc87306_regs, 0, 29); + pc87306_t *dev = (pc87306_t *) priv; - pc87306_regs[0] = 0x0B; - pc87306_regs[1] = 0x01; - pc87306_regs[3] = 0x01; - pc87306_regs[5] = 0x0D; - pc87306_regs[8] = 0x70; - pc87306_regs[9] = 0xC0; - pc87306_regs[0xB] = 0x80; - pc87306_regs[0xF] = 0x1E; - pc87306_regs[0x12] = 0x30; - pc87306_regs[0x19] = 0xEF; - /* - 0 = 360 rpm @ 500 kbps for 3.5" - 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" - */ - lpt1_remove(); - lpt2_remove(); - lpt1_handler(); - serial_remove(1); - serial_remove(2); - serial1_handler(); - serial2_handler(); - fdc_reset(pc87306_fdc); - pc87306_gpio_init(); + free(dev); } -void pc87306_init() + +static void * +pc87306_init(const device_t *info) { - pc87306_fdc = device_add(&fdc_at_nsc_device); + pc87306_t *dev = (pc87306_t *) malloc(sizeof(pc87306_t)); + memset(dev, 0, sizeof(pc87306_t)); - lpt2_remove(); + dev->fdc = device_add(&fdc_at_nsc_device); - pc87306_reset(); + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); - io_sethandler(0x02e, 0x0002, pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, NULL); + pc87306_reset(dev); + + io_sethandler(0x02e, 0x0002, + pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, dev); + + return dev; } + + +const device_t pc87306_device = { + "National Semiconductor PC87306 Super I/O", + 0, + 0, + pc87306_init, pc87306_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_um8669f.c b/src/sio_um8669f.c index fb991fede..d946c251c 100644 --- a/src/sio_um8669f.c +++ b/src/sio_um8669f.c @@ -23,11 +23,13 @@ PnP registers : #include #include +#include #include #include #include "86box.h" #include "device.h" #include "io.h" +#include "timer.h" #include "pci.h" #include "lpt.h" #include "serial.h" @@ -36,30 +38,6 @@ PnP registers : #include "sio.h" -typedef struct um8669f_t -{ - 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]; - - fdc_t *fdc; - int pnp_active; -} um8669f_t; - - -static um8669f_t um8669f_global; - - #define DEV_FDC 0 #define DEV_COM1 1 #define DEV_COM2 2 @@ -74,222 +52,270 @@ static um8669f_t um8669f_global; #define REG_DMA 0x74 -void um8669f_pnp_write(uint16_t port, uint8_t val, void *p) +typedef struct um8669f_t { - um8669f_t *um8669f = (um8669f_t *)p; + int locked, cur_reg_108, + cur_reg, cur_device, + pnp_active; - uint8_t valxor = 0; + uint8_t regs_108[256]; - if (port == 0x279) - um8669f->cur_reg = val; - else - { - if (um8669f->cur_reg == REG_DEVICE) - um8669f->cur_device = val & 7; - else - { - switch (um8669f->cur_reg) - { - case REG_ENABLE: - valxor = um8669f->dev[um8669f->cur_device].enable ^ val; - um8669f->dev[um8669f->cur_device].enable = val; - break; - case REG_ADDRLO: - valxor = (um8669f->dev[um8669f->cur_device].addr & 0xff) ^ val; - um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0xff00) | val; - break; - case REG_ADDRHI: - valxor = ((um8669f->dev[um8669f->cur_device].addr >> 8) & 0xff) ^ val; - um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0x00ff) | (val << 8); - break; - case REG_IRQ: - valxor = um8669f->dev[um8669f->cur_device].irq ^ val; - um8669f->dev[um8669f->cur_device].irq = val; - break; - case REG_DMA: - valxor = um8669f->dev[um8669f->cur_device].dma ^ val; - um8669f->dev[um8669f->cur_device].dma = val; - break; - default: + struct { + int enable; + uint16_t addr; + int irq; + int dma; + } dev[8]; + + fdc_t *fdc; + serial_t *uart[2]; +} um8669f_t; + + +static void +um8669f_pnp_write(uint16_t port, uint8_t val, void *priv) +{ + um8669f_t *dev = (um8669f_t *) priv; + + uint8_t valxor = 0; + uint8_t lpt_irq = 0xff; + + if (port == 0x279) + dev->cur_reg = val; + else { + if (dev->cur_reg == REG_DEVICE) + dev->cur_device = val & 7; + else { + switch (dev->cur_reg) { + case REG_ENABLE: + valxor = dev->dev[dev->cur_device].enable ^ val; + dev->dev[dev->cur_device].enable = val; + break; + case REG_ADDRLO: + valxor = (dev->dev[dev->cur_device].addr & 0xff) ^ val; + dev->dev[dev->cur_device].addr = (dev->dev[dev->cur_device].addr & 0xff00) | val; + break; + case REG_ADDRHI: + valxor = ((dev->dev[dev->cur_device].addr >> 8) & 0xff) ^ val; + dev->dev[dev->cur_device].addr = (dev->dev[dev->cur_device].addr & 0x00ff) | (val << 8); + break; + case REG_IRQ: + valxor = dev->dev[dev->cur_device].irq ^ val; + dev->dev[dev->cur_device].irq = val; + break; + case REG_DMA: + valxor = dev->dev[dev->cur_device].dma ^ val; + dev->dev[dev->cur_device].dma = val; + break; + default: valxor = 0; break; - } + } - switch (um8669f->cur_device) - { - case DEV_FDC: - if ((um8669f->cur_reg == REG_ENABLE) && valxor) - { - fdc_remove(um8669f_global.fdc); - if (um8669f->dev[DEV_FDC].enable & 1) - fdc_set_base(um8669f_global.fdc, 0x03f0); + switch (dev->cur_device) { + case DEV_FDC: + if ((dev->cur_reg == REG_ENABLE) && valxor) { + fdc_remove(dev->fdc); + if (dev->dev[DEV_FDC].enable & 1) + fdc_set_base(dev->fdc, 0x03f0); } - break; - case DEV_COM1: - if ((um8669f->cur_reg == REG_ENABLE) && valxor) - { - serial_remove(1); - if (um8669f->dev[DEV_COM1].enable & 1) - serial_setup(1, um8669f->dev[DEV_COM1].addr, um8669f->dev[DEV_COM1].irq); + break; + case DEV_COM1: + if ((dev->cur_reg == REG_ENABLE) && valxor) { + serial_remove(dev->uart[0]); + if (dev->dev[DEV_COM1].enable & 1) + serial_setup(dev->uart[0], dev->dev[DEV_COM1].addr, dev->dev[DEV_COM1].irq); } - break; - case DEV_COM2: - if ((um8669f->cur_reg == REG_ENABLE) && valxor) - { - serial_remove(2); - if (um8669f->dev[DEV_COM2].enable & 1) - serial_setup(2, um8669f->dev[DEV_COM2].addr, um8669f->dev[DEV_COM2].irq); + break; + case DEV_COM2: + if ((dev->cur_reg == REG_ENABLE) && valxor) { + serial_remove(dev->uart[1]); + if (dev->dev[DEV_COM2].enable & 1) + serial_setup(dev->uart[1], dev->dev[DEV_COM2].addr, dev->dev[DEV_COM2].irq); } - break; - case DEV_LPT1: - if ((um8669f->cur_reg == REG_ENABLE) && valxor) - { - lpt1_remove(); - if (um8669f->dev[DEV_LPT1].enable & 1) - lpt1_init(um8669f->dev[DEV_LPT1].addr); + break; + case DEV_LPT1: + if ((dev->cur_reg == REG_ENABLE) && valxor) { + lpt1_remove(); + if (dev->dev[DEV_LPT1].enable & 1) + lpt1_init(dev->dev[DEV_LPT1].addr); } - break; - } - } - } -} - - -uint8_t um8669f_pnp_read(uint16_t port, void *p) -{ - um8669f_t *um8669f = (um8669f_t *)p; - - 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; - int new_pnp_active; - - if (um8669f->locked) - { - if (port == 0x108 && val == 0xaa) - um8669f->locked = 0; - } - else - { - if (port == 0x108) - { - if (val == 0x55) - um8669f->locked = 1; - else - um8669f->cur_reg_108 = val; - } - else - { - um8669f->regs_108[um8669f->cur_reg_108] = val; - - if (um8669f->cur_reg_108 == 0xc1) { - new_pnp_active = !!(um8669f->regs_108[0xc1] & 0x80); - if (new_pnp_active != um8669f->pnp_active) { - if (new_pnp_active) { - 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); - } else { - 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); - } - um8669f->pnp_active = new_pnp_active; - } - } - } - } -} - - -uint8_t um8669f_read(uint16_t port, void *p) -{ - um8669f_t *um8669f = (um8669f_t *)p; - - if (um8669f->locked) - return 0xff; - - if (port == 0x108) - return um8669f->cur_reg_108; /*???*/ - else - return um8669f->regs_108[um8669f->cur_reg_108]; -} - - -void um8669f_reset(void) -{ - fdc_t *temp_fdc = um8669f_global.fdc; - - fdc_reset(um8669f_global.fdc); - - serial_remove(1); - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - - serial_remove(2); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); - - lpt2_remove(); - - lpt1_remove(); - lpt1_init(0x378); - - if (um8669f_global.pnp_active) { - io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, &um8669f_global); - io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, &um8669f_global); - io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, &um8669f_global); - um8669f_global.pnp_active = 0; + if (dev->dev[DEV_LPT1].irq <= 15) + lpt_irq = dev->dev[DEV_LPT1].irq; + lpt1_irq(lpt_irq); + break; + } } - - memset(&um8669f_global, 0, sizeof(um8669f_t)); - - um8669f_global.fdc = temp_fdc; - - um8669f_global.locked = 1; - - um8669f_global.dev[DEV_FDC].enable = 1; - um8669f_global.dev[DEV_FDC].addr = 0x03f0; - um8669f_global.dev[DEV_FDC].irq = 6; - um8669f_global.dev[DEV_FDC].dma = 2; - - um8669f_global.dev[DEV_COM1].enable = 1; - um8669f_global.dev[DEV_COM1].addr = 0x03f8; - um8669f_global.dev[DEV_COM1].irq = 4; - - um8669f_global.dev[DEV_COM2].enable = 1; - um8669f_global.dev[DEV_COM2].addr = 0x02f8; - um8669f_global.dev[DEV_COM2].irq = 3; - - um8669f_global.dev[DEV_LPT1].enable = 1; - um8669f_global.dev[DEV_LPT1].addr = 0x0378; - um8669f_global.dev[DEV_LPT1].irq = 7; + } } -void um8669f_init(void) +static uint8_t +um8669f_pnp_read(uint16_t port, void *priv) { - um8669f_global.fdc = device_add(&fdc_at_device); + um8669f_t *dev = (um8669f_t *) priv; + uint8_t ret = 0xff; - io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, &um8669f_global); + switch (dev->cur_reg) { + case REG_DEVICE: + ret = dev->cur_device; + break; + case REG_ENABLE: + ret = dev->dev[dev->cur_device].enable; + break; + case REG_ADDRLO: + ret = dev->dev[dev->cur_device].addr & 0xff; + break; + case REG_ADDRHI: + ret = dev->dev[dev->cur_device].addr >> 8; + break; + case REG_IRQ: + ret = dev->dev[dev->cur_device].irq; + break; + case REG_DMA: + ret = dev->dev[dev->cur_device].dma; + break; + } - um8669f_reset(); + return ret; } + + +void um8669f_write(uint16_t port, uint8_t val, void *priv) +{ + um8669f_t *dev = (um8669f_t *) priv; + int new_pnp_active; + + if (dev->locked) { + if ((port == 0x108) && (val == 0xaa)) + dev->locked = 0; + } else { + if (port == 0x108) { + if (val == 0x55) + dev->locked = 1; + else + dev->cur_reg_108 = val; + } else { + dev->regs_108[dev->cur_reg_108] = val; + + if (dev->cur_reg_108 == 0xc1) { + new_pnp_active = !!(dev->regs_108[0xc1] & 0x80); + if (new_pnp_active != dev->pnp_active) { + if (new_pnp_active) { + io_sethandler(0x0279, 0x0001, + NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_sethandler(0x0a79, 0x0001, + NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_sethandler(0x03e3, 0x0001, + um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, dev); + } else { + io_removehandler(0x0279, 0x0001, + NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_removehandler(0x0a79, 0x0001, + NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_removehandler(0x03e3, 0x0001, + um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, dev); + } + dev->pnp_active = new_pnp_active; + } + } + } + } +} + + +uint8_t um8669f_read(uint16_t port, void *priv) +{ + um8669f_t *dev = (um8669f_t *) priv; + uint8_t ret = 0xff; + + if (!dev->locked) { + if (port == 0x108) + ret = dev->cur_reg_108; /* ??? */ + else + ret = dev->regs_108[dev->cur_reg_108]; + } + + return ret; +} + + +void +um8669f_reset(um8669f_t *dev) +{ + fdc_reset(dev->fdc); + + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + + lpt1_remove(); + lpt1_init(0x378); + + if (dev->pnp_active) { + io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, dev); + io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, dev); + dev->pnp_active = 0; + } + + dev->locked = 1; + + dev->dev[DEV_FDC].enable = 1; + dev->dev[DEV_FDC].addr = 0x03f0; + dev->dev[DEV_FDC].irq = 6; + dev->dev[DEV_FDC].dma = 2; + + dev->dev[DEV_COM1].enable = 1; + dev->dev[DEV_COM1].addr = 0x03f8; + dev->dev[DEV_COM1].irq = 4; + + dev->dev[DEV_COM2].enable = 1; + dev->dev[DEV_COM2].addr = 0x02f8; + dev->dev[DEV_COM2].irq = 3; + + dev->dev[DEV_LPT1].enable = 1; + dev->dev[DEV_LPT1].addr = 0x0378; + dev->dev[DEV_LPT1].irq = 7; +} + + +static void +um8669f_close(void *priv) +{ + um8669f_t *dev = (um8669f_t *) priv; + + free(dev); +} + + +static void * +um8669f_init(const device_t *info) +{ + um8669f_t *dev = (um8669f_t *) malloc(sizeof(um8669f_t)); + memset(dev, 0, sizeof(um8669f_t)); + + dev->fdc = device_add(&fdc_at_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + io_sethandler(0x0108, 0x0002, + um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, dev); + + um8669f_reset(dev); + + return dev; +} + + +const device_t um8669f_device = { + "UMC UM8669F Super I/O", + 0, + 0, + um8669f_init, um8669f_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_w83877f.c b/src/sio_w83877f.c index 775beccfe..69ad67286 100644 --- a/src/sio_w83877f.c +++ b/src/sio_w83877f.c @@ -11,19 +11,20 @@ * Winbond W83877F Super I/O Chip * Used by the Award 430HX * - * Version: @(#)sio_w83877f.c 1.0.11 2018/04/29 + * Version: @(#)sio_w83877f.c 1.0.16 2020/01/11 * * Author: Miran Grca, - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2020 Miran Grca. */ #include #include +#include #include #include #include "86box.h" -#include "machine/machine.h" #include "device.h" #include "io.h" +#include "timer.h" #include "pci.h" #include "mem.h" #include "rom.h" @@ -34,505 +35,431 @@ #include "sio.h" -static int w83877f_locked; -static int w83877f_rw_locked = 0; -static int w83877f_curreg = 0; -static uint8_t w83877f_regs[0x2A]; -static uint8_t tries; -static fdc_t *w83877f_fdc; +#define FDDA_TYPE (dev->regs[7] & 3) +#define FDDB_TYPE ((dev->regs[7] >> 2) & 3) +#define FDDC_TYPE ((dev->regs[7] >> 4) & 3) +#define FDDD_TYPE ((dev->regs[7] >> 6) & 3) -static int winbond_port = 0x3f0; -static int winbond_key = 0x89; -static int winbond_key_times = 1; +#define FD_BOOT (dev->regs[8] & 3) +#define SWWP ((dev->regs[8] >> 4) & 1) +#define DISFDDWR ((dev->regs[8] >> 5) & 1) + +#define EN3MODE ((dev->regs[9] >> 5) & 1) + +#define DRV2EN_NEG (dev->regs[0xB] & 1) /* 0 = drive 2 installed */ +#define INVERTZ ((dev->regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */ +#define IDENT ((dev->regs[0xB] >> 3) & 1) + +#define HEFERE ((dev->regs[0xC] >> 5) & 1) + +#define HEFRAS (dev->regs[0x16] & 1) + +#define PRTIQS (dev->regs[0x27] & 0x0f) +#define ECPIRQ ((dev->regs[0x27] >> 5) & 0x07) -void w83877f_write(uint16_t port, uint8_t val, void *priv); -uint8_t w83877f_read(uint16_t port, void *priv); - -#define OCSS0 (w83877f_regs[0] & 1) -#define OCSS1 ((w83877f_regs[0] >> 1) & 1) -#define PRTMODS0 ((w83877f_regs[0] >> 2) & 1) -#define PRTMODS1 ((w83877f_regs[0] >> 3) & 1) - -#define ABCHG (w83877f_regs[1] >> 7) - -#define CEA (w83877f_regs[2] & 1) -#define EA3 ((w83877f_regs[2] >> 1) & 1) -#define EA4 ((w83877f_regs[2] >> 2) & 1) -#define EA5 ((w83877f_regs[2] >> 3) & 1) -#define EA6 ((w83877f_regs[2] >> 4) & 1) -#define EA7 ((w83877f_regs[2] >> 5) & 1) -#define EA8 ((w83877f_regs[2] >> 6) & 1) -#define EA9 (w83877f_regs[2] >> 7) - -#define SUBMIDI (w83877f_regs[3] & 1) -#define SUAMIDI ((w83877f_regs[3] >> 1) & 1) -#define GMODS ((w83877f_regs[3] >> 4) & 1) -#define EPPVER ((w83877f_regs[3] >> 5) & 1) -#define GMENL ((w83877f_regs[3] >> 6) & 1) - -#define URBTRI (w83877f_regs[4] & 1) -#define URATRI ((w83877f_regs[4] >> 1) & 1) -#define GMTRI ((w83877f_regs[4] >> 2) & 1) -#define PRTTRI ((w83877f_regs[4] >> 3) & 1) -#define URBPWD ((w83877f_regs[4] >> 4) & 1) -#define URAPWD ((w83877f_regs[4] >> 5) & 1) -#define GMPWD ((w83877f_regs[4] >> 6) & 1) -#define PRTPWD (w83877f_regs[4] >> 7) - -#define ECPFTHR0 (w83877f_regs[5] & 1) -#define ECPFTHR1 ((w83877f_regs[5] >> 1) & 1) -#define ECPFTHR2 ((w83877f_regs[5] >> 2) & 1) -#define ECPFTHR3 ((w83877f_regs[5] >> 3) & 1) - -#define IDETRI (w83877f_regs[6] & 1) -#define FDCTRI ((w83877f_regs[6] >> 1) & 1) -#define IDEPWD ((w83877f_regs[6] >> 2) & 1) -#define FDCPWD ((w83877f_regs[6] >> 3) & 1) -#define FIPURDWM ((w83877f_regs[6] >> 4) & 1) -#define SEL4FDD ((w83877f_regs[6] >> 5) & 1) -#define OSCS2 ((w83877f_regs[6] >> 6) & 1) - -#define FDDA_TYPE (w83877f_regs[7] & 3) -#define FDDB_TYPE ((w83877f_regs[7] >> 2) & 3) -#define FDDC_TYPE ((w83877f_regs[7] >> 4) & 3) -#define FDDD_TYPE ((w83877f_regs[7] >> 6) & 3) - -#define FD_BOOT (w83877f_regs[8] & 3) -#define MEDIA_ID ((w83877f_regs[8] >> 2) & 3) -#define SWWP ((w83877f_regs[8] >> 4) & 1) -#define DISFDDWR ((w83877f_regs[8] >> 5) & 1) -#define APDTMS2 ((w83877f_regs[8] >> 6) & 1) -#define APDTMS1 (w83877f_regs[8] >> 7) - -#define CHIP_ID (w83877f_regs[9] & 0xF) -#define EN3MODE ((w83877f_regs[9] >> 5) & 1) -#define LOCKREG ((w83877f_regs[9] >> 6) & 1) -#define PRTMODS2 ((w83877f_regs[9] >> 7) & 1) - -#define PEXTECPP (w83877f_regs[0xA] & 1) -#define PEXT_ECP ((w83877f_regs[0xA] >> 1) & 1) -#define PEXT_EPP ((w83877f_regs[0xA] >> 2) & 1) -#define PEXT_ADP ((w83877f_regs[0xA] >> 3) & 1) -#define PDCACT ((w83877f_regs[0xA] >> 4) & 1) -#define PDIRHOP ((w83877f_regs[0xA] >> 5) & 1) -#define PEXT_ACT ((w83877f_regs[0xA] >> 6) & 1) -#define PFDCACT (w83877f_regs[0xA] >> 7) - -#define DRV2EN_NEG (w83877f_regs[0xB] & 1) /* 0 = drive 2 installed */ -#define INVERTZ ((w83877f_regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */ -#define MFM ((w83877f_regs[0xB] >> 2) & 1) -#define IDENT ((w83877f_regs[0xB] >> 3) & 1) -#define ENIFCHG ((w83877f_regs[0xB] >> 4) & 1) - -#define TX2INV (w83877f_regs[0xC] & 1) -#define RX2INV ((w83877f_regs[0xC] >> 1) & 1) -#define URIRSEL ((w83877f_regs[0xC] >> 3) & 1) -#define HEFERE ((w83877f_regs[0xC] >> 5) & 1) -#define TURB ((w83877f_regs[0xC] >> 6) & 1) -#define TURA (w83877f_regs[0xC] >> 7) - -#define IRMODE0 (w83877f_regs[0xD] & 1) -#define IRMODE1 ((w83877f_regs[0xD] >> 1) & 1) -#define IRMODE2 ((w83877f_regs[0xD] >> 2) & 1) -#define HDUPLX ((w83877f_regs[0xD] >> 3) & 1) -#define SIRRX0 ((w83877f_regs[0xD] >> 4) & 1) -#define SIRRX1 ((w83877f_regs[0xD] >> 5) & 1) -#define SIRTX0 ((w83877f_regs[0xD] >> 6) & 1) -#define SIRTX1 (w83877f_regs[0xD] >> 7) - -#define GIO0AD (w83877f_regs[0x10] | (((uint16_t) w83877f_regs[0x11] & 7) << 8)) -#define GIO0CADM (w83877f_regs[0x11] >> 6) -#define GIO1AD (w83877f_regs[0x12] | (((uint16_t) w83877f_regs[0x13] & 7) << 8)) -#define GIO1CADM (w83877f_regs[0x13] >> 6) - -#define GDA0IPI (w83877f_regs[0x14] & 1) -#define GDA0OPI ((w83877f_regs[0x14] >> 1) & 1) -#define GCS0IOW ((w83877f_regs[0x14] >> 2) & 1) -#define GCS0IOR ((w83877f_regs[0x14] >> 3) & 1) -#define GIO0CSH ((w83877f_regs[0x14] >> 4) & 1) -#define GIOP0MD ((w83877f_regs[0x14] >> 5) & 7) - -#define GDA1IPI (w83877f_regs[0x15] & 1) -#define GDA1OPI ((w83877f_regs[0x15] >> 1) & 1) -#define GCS1IOW ((w83877f_regs[0x15] >> 2) & 1) -#define GCS1IOR ((w83877f_regs[0x15] >> 3) & 1) -#define GIO1CSH ((w83877f_regs[0x15] >> 4) & 1) -#define GIOP1MD ((w83877f_regs[0x15] >> 5) & 7) - -#define HEFRAS (w83877f_regs[0x16] & 1) -#define IRIDE ((w83877f_regs[0x16] >> 1) & 1) -#define PNPCVS ((w83877f_regs[0x16] >> 2) & 1) -#define GMDRQ ((w83877f_regs[0x16] >> 3) & 1) -#define GOIQSEL ((w83877f_regs[0x16] >> 4) & 1) - -#define DSUBLGRQ (w83877f_regs[0x17] & 1) -#define DSUALGRQ ((w83877f_regs[0x17] >> 1) & 1) -#define DSPRLGRQ ((w83877f_regs[0x17] >> 2) & 1) -#define DSFDLGRQ ((w83877f_regs[0x17] >> 3) & 1) -#define PRIRQOD ((w83877f_regs[0x17] >> 4) & 1) - -#define GMAS (w83877f_regs[0x1E] & 3) -#define GMAD (w83877f_regs[0x1E] & 0xFC) - -#define FDCAD ((w83877f_regs[0x20] & 0xFC) << 2) - -/* Main IDE base address. */ -#define IDE0AD ((w83877f_regs[0x21] & 0xFC) << 2) -/* IDE Alternate status base address. */ -#define IDE1AD ((w83877f_regs[0x22] & 0xFC) << 2) - -#define PRTAD (((uint16_t) w83877f_regs[0x23]) << 2) - -#define URAAD (((uint16_t) w83877f_regs[0x24] & 0xFE) << 2) -#define URBAD (((uint16_t) w83877f_regs[0x25] & 0xFE) << 2) - -#define PRTDQS (w83877f[regs[0x26] & 0xF) -#define FDCDQS (w83877f[regs[0x26] >> 4) - -#define PRTIQS (w83877f[regs[0x27] & 0xF) -#define ECPIRQx (w83877f[regs[0x27] >> 5) - -#define URBIQS (w83877f[regs[0x28] & 0xF) -#define URAIQS (w83877f[regs[0x28] >> 4) - -#define IQNIQS (w83877f[regs[0x29] & 0xF) -#define FDCIQS (w83877f[regs[0x29] >> 4) - -#define W83757 (!PRTMODS2 && !PRTMODS1 && !PRTMODS0) -#define EXTFDC (!PRTMODS2 && !PRTMODS1 && PRTMODS0) -#define EXTADP (!PRTMODS2 && PRTMODS1 && !PRTMODS0) -#define EXT2FDD (!PRTMODS2 && PRTMODS1 && PRTMODS0) -#define JOYSTICK (PRTMODS2 && !PRTMODS1 && !PRTMODS0) -#define EPP_SPP (PRTMODS2 && !PRTMODS1 && PRTMODS0) -#define ECP (PRTMODS2 && PRTMODS1 && !PRTMODS0) -#define ECP_EPP (PRTMODS2 && PRTMODS1 && PRTMODS0) - -static uint16_t fdc_valid_ports[2] = {0x3F0, 0x370}; -static uint16_t ide_valid_ports[2] = {0x1F0, 0x170}; -static uint16_t ide_as_valid_ports[2] = {0x3F6, 0x376}; -static uint16_t lpt1_valid_ports[3] = {0x3BC, 0x378, 0x278}; -static uint16_t com1_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; -static uint16_t com2_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; +typedef struct { + uint8_t tries, regs[42]; + uint16_t reg_init; + int locked, rw_locked, + cur_reg, + base_address, key, + key_times; + fdc_t *fdc; + serial_t *uart[2]; +} w83877f_t; -static void w83877f_remap(void) +static void w83877f_write(uint16_t port, uint8_t val, void *priv); +static uint8_t w83877f_read(uint16_t port, void *priv); + + +static void +w83877f_remap(w83877f_t *dev) { - io_removehandler(0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); - io_removehandler(0x3f0, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); - io_sethandler(HEFRAS ? 0x3f0 : 0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); - winbond_port = (HEFRAS ? 0x3f0 : 0x250); - winbond_key_times = HEFRAS + 1; - winbond_key = (HEFRAS ? 0x86 : 0x88) | HEFERE; + uint8_t hefras = HEFRAS; + + io_removehandler(0x250, 0x0002, + w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev); + io_removehandler(0x3f0, 0x0002, + w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev); + dev->base_address = (hefras ? 0x3f0 : 0x250); + io_sethandler(dev->base_address, 0x0002, + w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, dev); + dev->key_times = hefras + 1; + dev->key = (hefras ? 0x86 : 0x88) | HEFERE; } -static uint8_t is_in_array(uint16_t *port_array, uint8_t max, uint16_t port) +static uint8_t +get_lpt_length(w83877f_t *dev) { - uint8_t i = 0; + uint8_t length = 4; - for (i = 0; i < max; i++) - { - if (port_array[i] == port) return 1; - } - return 0; + if (dev->regs[9] & 0x80) { + if (dev->regs[0] & 0x04) + length = 8; /* EPP mode. */ + if (dev->regs[0] & 0x08) + length |= 0x80; /* ECP mode. */ + } + + return length; } -static uint16_t make_port(uint8_t reg) +static uint16_t +make_port(w83877f_t *dev, uint8_t reg) { - uint16_t p = 0; + uint16_t p = 0; + uint8_t l; - switch(reg) - { - case 0x20: - p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; - p &= 0xFF0; - if ((p < 0x100) || (p > 0x3F0)) p = 0x3F0; - if (!(is_in_array(fdc_valid_ports, 2, p))) p = 0x3F0; - w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); - break; - case 0x21: - p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; - p &= 0xFF0; - if ((p < 0x100) || (p > 0x3F0)) p = 0x1F0; - if (!(is_in_array(ide_valid_ports, 2, p))) p = 0x1F0; - w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); - break; - case 0x22: - p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; - p &= 0xFF0; - if ((p < 0x106) || (p > 0x3F6)) p = 0x3F6; - if (!(is_in_array(ide_as_valid_ports, 2, p))) p = 0x3F6; - w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); - break; - case 0x23: - p = ((uint16_t) (w83877f_regs[reg] & 0xff)) << 2; - p &= 0xFFC; - if ((p < 0x100) || (p > 0x3F8)) p = 0x378; - if (!(is_in_array(lpt1_valid_ports, 3, p))) p = 0x378; - w83877f_regs[reg] = (p >> 2); - break; - case 0x24: - p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; - p &= 0xFF8; - if ((p < 0x100) || (p > 0x3F8)) p = 0x3F8; - if (!(is_in_array(com1_valid_ports, 9, p))) p = 0x3F8; - w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); - break; - case 0x25: - p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; - p &= 0xFF8; - if ((p < 0x100) || (p > 0x3F8)) p = 0x2F8; - if (!(is_in_array(com2_valid_ports, 9, p))) p = 0x2F8; - w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); - break; - } - - return p; -} - - -void w83877f_serial_handler(int id) -{ - int reg_mask = (id - 1) ? 0x10 : 0x20; - int reg_id = (id - 1) ? 0x24 : 0x25; - int irq_mask = (id - 1) ? 0xF : 0xF0; - - if ((w83877f_regs[4] & reg_mask) || !(w83877f_regs[reg_id] & 0xc0)) - { - serial_remove(id); - } - else - { - serial_setup(id, make_port(reg_id), w83877f_regs[0x28] & irq_mask); - } -} - - -void w83877f_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t valxor = 0; - uint8_t max = 0x2A; - - if (index) - { - if ((val == winbond_key) && !w83877f_locked) - { - if (winbond_key_times == 2) - { - if (tries) - { - w83877f_locked = 1; - tries = 0; - } - else - { - tries++; - } - } - else - { - w83877f_locked = 1; - tries = 0; - } - } + switch (reg) { + case 0x20: + p = ((uint16_t) (dev->regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x3F0; + break; + case 0x23: + l = get_lpt_length(dev); + p = ((uint16_t) (dev->regs[reg] & 0xff)) << 2; + /* 8 ports in EPP mode, 4 in non-EPP mode. */ + if ((l & 0x0f) == 8) + p &= 0x3F8; else - { - if (w83877f_locked) - { - if (val < max) w83877f_curreg = val; - if (val == 0xaa) - { - w83877f_locked = 0; - } - } - else - { - if (tries) - tries = 0; - } - } - } + p &= 0x3FC; + if ((p < 0x100) || (p > 0x3FF)) p = 0x378; + /* In ECP mode, A10 is active. */ + if (l & 0x80) + p |= 0x400; + break; + case 0x24: + p = ((uint16_t) (dev->regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x3F8; + break; + case 0x25: + p = ((uint16_t) (dev->regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x2F8; + break; + } + + return p; +} + + +static void +w83877f_serial_handler(w83877f_t *dev, int uart) +{ + int reg_mask = uart ? 0x10 : 0x20; + int reg_id = uart ? 0x24 : 0x25; + int irq_mask = uart ? 0x0f : 0xf0; + int irq_shift = uart ? 4 : 0; + + if ((dev->regs[4] & reg_mask) || !(dev->regs[reg_id] & 0xc0)) + serial_remove(dev->uart[uart]); + else + serial_setup(dev->uart[uart], make_port(dev, reg_id), (dev->regs[0x28] & irq_mask) >> irq_shift); +} + + +static void +w83877f_write(uint16_t port, uint8_t val, void *priv) +{ + w83877f_t *dev = (w83877f_t *) priv; + uint8_t valxor = 0; + uint8_t max = 0x2A; + uint8_t lpt_irq; + + if (port == 0x250) { + if (val == dev->key) + dev->locked = 1; else - { - if (w83877f_locked) - { - if (w83877f_rw_locked) return; - if ((w83877f_curreg >= 0x26) && (w83877f_curreg <= 0x27)) return; - if (w83877f_curreg == 0x29) return; - if (w83877f_curreg == 6) val &= 0xF3; - valxor = val ^ w83877f_regs[w83877f_curreg]; - w83877f_regs[w83877f_curreg] = val; - goto process_value; + dev->locked = 0; + return; + } else if (port == 0x251) { + if (val <= max) + dev->cur_reg = val; + return; + } else if (port == 0x03f0) { + if ((val == dev->key) && !dev->locked) { + if (dev->key_times == 2) { + if (dev->tries) { + dev->locked = 1; + dev->tries = 0; + } else + dev->tries++; + } else { + dev->locked = 1; + dev->tries = 0; + } + } else { + if (dev->locked) { + if (val < max) + dev->cur_reg = val; + if (val == 0xaa) + dev->locked = 0; + } else { + if (dev->tries) + dev->tries = 0; } } return; + } else if ((port == 0x252) || (port == 0x3f1)) { + if (dev->locked) { + if (dev->rw_locked) + return; + if ((dev->cur_reg >= 0x26) && (dev->cur_reg <= 0x27)) + return; + if (dev->cur_reg == 0x29) + return; + if (dev->cur_reg == 6) + val &= 0xF3; + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + } else + return; + } -process_value: - switch(w83877f_curreg) - { - case 1: - if (valxor & 0x80) - { - fdc_set_swap(w83877f_fdc, (w83877f_regs[1] & 0x80) ? 1 : 0); - } - break; - case 4: - if (valxor & 0x10) - { - w83877f_serial_handler(2); - } - if (valxor & 0x20) - { - w83877f_serial_handler(1); - } - if (valxor & 0x80) - { - lpt1_remove(); - if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); - } - break; - case 6: - if (valxor & 0x08) - { - fdc_remove(w83877f_fdc); - if (!(w83877f_regs[6] & 0x08)) fdc_set_base(w83877f_fdc, 0x03f0); - } - break; - case 7: - if (valxor & 3) fdc_update_rwc(w83877f_fdc, 0, FDDA_TYPE); - if (valxor & 0xC) fdc_update_rwc(w83877f_fdc, 1, FDDB_TYPE); - if (valxor & 0x30) fdc_update_rwc(w83877f_fdc, 2, FDDC_TYPE); - if (valxor & 0xC0) fdc_update_rwc(w83877f_fdc, 3, FDDD_TYPE); - break; - case 8: - if (valxor & 3) fdc_update_boot_drive(w83877f_fdc, FD_BOOT); - if (valxor & 0x10) fdc_set_swwp(w83877f_fdc, SWWP ? 1 : 0); - if (valxor & 0x20) fdc_set_diswr(w83877f_fdc, DISFDDWR ? 1 : 0); - break; - case 9: - if (valxor & 0x20) - { - fdc_update_enh_mode(w83877f_fdc, EN3MODE ? 1 : 0); - } - if (valxor & 0x40) - { - w83877f_rw_locked = (val & 0x40) ? 1 : 0; - } - break; - case 0xB: - if (valxor & 1) fdc_update_drv2en(w83877f_fdc, DRV2EN_NEG ? 0 : 1); - if (valxor & 2) fdc_update_densel_polarity(w83877f_fdc, INVERTZ ? 1 : 0); - break; - case 0xC: - if (valxor & 0x20) w83877f_remap(); - break; - case 0x16: - if (valxor & 1) w83877f_remap(); - break; - case 0x23: - if (valxor) - { - lpt1_remove(); - if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); - } - break; - case 0x24: - if (valxor & 0xfe) - { - w83877f_serial_handler(1); - } - break; - case 0x25: - if (valxor & 0xfe) - { - w83877f_serial_handler(2); - } - break; - case 0x28: - if (valxor & 0xf) - { - if ((w83877f_regs[0x28] & 0xf) == 0) w83877f_regs[0x28] |= 0x3; - if (!(w83877f_regs[2] & 0x10)) serial_setup(2, make_port(0x25), w83877f_regs[0x28] & 0xF); - } - if (valxor & 0xf0) - { - if ((w83877f_regs[0x28] & 0xf0) == 0) w83877f_regs[0x28] |= 0x40; - if (!(w83877f_regs[4] & 0x20)) - { - serial_setup(1, make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); - } - } - break; - } + switch (dev->cur_reg) { + case 0: + if (valxor & 0x0c) { + lpt1_remove(); + if (!(dev->regs[4] & 0x80)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 1: + if (valxor & 0x80) + fdc_set_swap(dev->fdc, (dev->regs[1] & 0x80) ? 1 : 0); + break; + case 4: + if (valxor & 0x10) + w83877f_serial_handler(dev, 1); + if (valxor & 0x20) + w83877f_serial_handler(dev, 0); + if (valxor & 0x80) { + lpt1_remove(); + if (!(dev->regs[4] & 0x80)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 6: + if (valxor & 0x08) { + fdc_remove(dev->fdc); + if (!(dev->regs[6] & 0x08)) + fdc_set_base(dev->fdc, 0x03f0); + } + break; + case 7: + if (valxor & 0x03) + fdc_update_rwc(dev->fdc, 0, FDDA_TYPE); + if (valxor & 0x0c) + fdc_update_rwc(dev->fdc, 1, FDDB_TYPE); + if (valxor & 0x30) + fdc_update_rwc(dev->fdc, 2, FDDC_TYPE); + if (valxor & 0xc0) + fdc_update_rwc(dev->fdc, 3, FDDD_TYPE); + break; + case 8: + if (valxor & 0x03) + fdc_update_boot_drive(dev->fdc, FD_BOOT); + if (valxor & 0x10) + fdc_set_swwp(dev->fdc, SWWP ? 1 : 0); + if (valxor & 0x20) + fdc_set_diswr(dev->fdc, DISFDDWR ? 1 : 0); + break; + case 9: + if (valxor & 0x20) + fdc_update_enh_mode(dev->fdc, EN3MODE ? 1 : 0); + if (valxor & 0x40) + dev->rw_locked = (val & 0x40) ? 1 : 0; + if (valxor & 0x80) { + lpt1_remove(); + if (!(dev->regs[4] & 0x80)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 0xB: + if (valxor & 1) + fdc_update_drv2en(dev->fdc, DRV2EN_NEG ? 0 : 1); + if (valxor & 2) + fdc_update_densel_polarity(dev->fdc, INVERTZ ? 1 : 0); + break; + case 0xC: + if (valxor & 0x20) + w83877f_remap(dev); + break; + case 0x16: + if (valxor & 1) + w83877f_remap(dev); + break; + case 0x20: + if (valxor) { + fdc_remove(dev->fdc); + if (!(dev->regs[4] & 0x80)) + fdc_set_base(dev->fdc, make_port(dev, 0x20)); + } + break; + case 0x23: + if (valxor) { + lpt1_remove(); + if (!(dev->regs[4] & 0x80)) + lpt1_init(make_port(dev, 0x23)); + } + break; + case 0x24: + if (valxor & 0xfe) + w83877f_serial_handler(dev, 0); + break; + case 0x25: + if (valxor & 0xfe) + w83877f_serial_handler(dev, 1); + break; + case 0x27: + if (valxor & 0xef) { + lpt_irq = 0xff; + + if (PRTIQS != 0x00) + lpt_irq = ECPIRQ; + + lpt1_irq(lpt_irq); + } + break; + case 0x28: + if (valxor & 0xf) { + if ((dev->regs[0x28] & 0x0f) == 0) + dev->regs[0x28] |= 0x03; + if (!(dev->regs[2] & 0x10)) + serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f); + } + if (valxor & 0xf0) { + if ((dev->regs[0x28] & 0xf0) == 0) + dev->regs[0x28] |= 0x40; + if (!(dev->regs[4] & 0x20)) + serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4); + } + break; + } } -uint8_t w83877f_read(uint16_t port, void *priv) +static uint8_t +w83877f_read(uint16_t port, void *priv) { - uint8_t index = (port & 1) ? 0 : 1; + w83877f_t *dev = (w83877f_t *) priv; + uint8_t ret = 0xff; - if (!w83877f_locked) - { - return 0xff; + if (dev->locked) { + if ((port == 0x3f0) || (port == 0x251)) + ret = dev->cur_reg; + else if ((port == 0x3f1) || (port == 0x252)) { + if (dev->cur_reg == 7) + ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2)); + else if ((dev->cur_reg >= 0x18) || !dev->rw_locked) + ret = dev->regs[dev->cur_reg]; } + } - if (index) - { - return w83877f_curreg; - } - else - { - if ((w83877f_curreg < 0x18) && w83877f_rw_locked) return 0xff; - if (w83877f_curreg == 7) - return (fdc_get_rwc(w83877f_fdc, 0) | (fdc_get_rwc(w83877f_fdc, 1) << 2)); - return w83877f_regs[w83877f_curreg]; - } + return ret; } -void w83877f_reset(void) +static void +w83877f_reset(w83877f_t *dev) { - lpt1_remove(); - lpt1_init(0x378); + lpt1_remove(); + lpt1_init(0x378); - fdc_reset(w83877f_fdc); + fdc_reset(dev->fdc); - memset(w83877f_regs, 0, 0x2A); - w83877f_regs[3] = 0x30; - w83877f_regs[7] = 0xF5; - w83877f_regs[9] = 0x0A; - w83877f_regs[0xA] = 0x1F; - w83877f_regs[0xC] = 0x28; - w83877f_regs[0xD] = 0xA3; - w83877f_regs[0x16] = (romset == ROM_PRESIDENT) ? 4 : 5; - w83877f_regs[0x1E] = 0x81; - w83877f_regs[0x20] = (0x3f0 >> 2) & 0xfc; - w83877f_regs[0x21] = (0x1f0 >> 2) & 0xfc; - w83877f_regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; - w83877f_regs[0x23] = (0x378 >> 2); - w83877f_regs[0x24] = (0x3f8 >> 2) & 0xfe; - w83877f_regs[0x25] = (0x2f8 >> 2) & 0xfe; - w83877f_regs[0x26] = (2 << 4) | 4; - w83877f_regs[0x27] = (6 << 4) | 7; - w83877f_regs[0x28] = (4 << 4) | 3; - w83877f_regs[0x29] = 0x62; + memset(dev->regs, 0, 0x2A); + dev->regs[0x03] = 0x30; + dev->regs[0x07] = 0xF5; + dev->regs[0x09] = (dev->reg_init >> 8) & 0xff; + dev->regs[0x0a] = 0x1F; + dev->regs[0x0c] = 0x28; + dev->regs[0x0d] = 0xA3; + dev->regs[0x16] = dev->reg_init & 0xff; + dev->regs[0x1e] = 0x81; + dev->regs[0x20] = (0x3f0 >> 2) & 0xfc; + dev->regs[0x21] = (0x1f0 >> 2) & 0xfc; + dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; + dev->regs[0x23] = (0x378 >> 2); + dev->regs[0x24] = (0x3f8 >> 2) & 0xfe; + dev->regs[0x25] = (0x2f8 >> 2) & 0xfe; + dev->regs[0x26] = (2 << 4) | 4; + dev->regs[0x27] = (6 << 4) | 7; + dev->regs[0x28] = (4 << 4) | 3; + dev->regs[0x29] = 0x62; - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); - w83877f_remap(); - w83877f_locked = 0; - w83877f_rw_locked = 0; + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + + dev->base_address = 0x3f0; + dev->key = 0x89; + dev->key_times = 1; + + w83877f_remap(dev); + + dev->locked = 0; + dev->rw_locked = 0; } -void w83877f_init(void) +static void +w83877f_close(void *priv) { - w83877f_fdc = device_add(&fdc_at_winbond_device); + w83877f_t *dev = (w83877f_t *) priv; - lpt2_remove(); - - w83877f_reset(); + free(dev); } + + +static void * +w83877f_init(const device_t *info) +{ + w83877f_t *dev = (w83877f_t *) malloc(sizeof(w83877f_t)); + memset(dev, 0, sizeof(w83877f_t)); + + dev->fdc = device_add(&fdc_at_winbond_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->reg_init = info->local; + + w83877f_reset(dev); + + return dev; +} + + +const device_t w83877f_device = { + "Winbond W83877F Super I/O", + 0, + 0x0a05, + w83877f_init, w83877f_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t w83877f_president_device = { + "Winbond W83877F Super I/O (President)", + 0, + 0x0a04, + w83877f_init, w83877f_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t w83877tf_device = { + "Winbond W83877TF Super I/O", + 0, + 0x0c04, + w83877f_init, w83877f_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sound/dbopl.cpp b/src/sound/dbopl.cpp deleted file mode 100644 index 85228ae10..000000000 --- a/src/sound/dbopl.cpp +++ /dev/null @@ -1,1512 +0,0 @@ -/* Copyright holders: The DOSBox Team - see COPYING for more details -*/ - -/* - DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator. - Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2 - Except for the table generation it's all integer math - Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms - The generation was based on the MAME implementation but tried to have it use less memory and be faster in general - MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times - - //TODO Don't delay first operator 1 sample in opl3 mode - //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter - //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? - //TODO Check if having the same accuracy in all frequency multipliers sounds better or not - - //DUNNO Keyon in 4op, switch to 2op without keyoff. -*/ - -/* $Id: dbopl.cpp,v 1.10 2009-06-10 19:54:51 harekiet Exp $ */ - -#include -#include -#include -#include "dbopl.h" - - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -namespace DBOPL { - -#define OPLRATE ((double)(14318180.0 / 288.0)) -#define TREMOLO_TABLE 52 - -//Try to use most precision for frequencies -//Else try to keep different waves in synch -//#define WAVE_PRECISION 1 -#ifndef WAVE_PRECISION -//Wave bits available in the top of the 32bit range -//Original adlib uses 10.10, we use 10.22 -#define WAVE_BITS 10 -#else -//Need some extra bits at the top to have room for octaves and frequency multiplier -//We support to 8 times lower rate -//128 * 15 * 8 = 15350, 2^13.9, so need 14 bits -#define WAVE_BITS 14 -#endif -#define WAVE_SH ( 32 - WAVE_BITS ) -#define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 ) - -//Use the same accuracy as the waves -#define LFO_SH ( WAVE_SH - 10 ) -//LFO is controlled by our tremolo 256 sample limit -#define LFO_MAX ( 256 << ( LFO_SH ) ) - - -//Maximum amount of attenuation bits -//Envelope goes to 511, 9 bits -#if (DBOPL_WAVE == WAVE_TABLEMUL ) -//Uses the value directly -#define ENV_BITS ( 9 ) -#else -//Add 3 bits here for more accuracy and would have to be shifted up either way -#define ENV_BITS ( 9 ) -#endif -//Limits of the envelope with those bits and when the envelope goes silent -#define ENV_MIN 0 -#define ENV_EXTRA ( ENV_BITS - 9 ) -#define ENV_MAX ( 511 << ENV_EXTRA ) -#define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) ) -#define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT ) - -//Attack/decay/release rate counter shift -#define RATE_SH 24 -#define RATE_MASK ( ( 1 << RATE_SH ) - 1 ) -//Has to fit within 16bit lookuptable -#define MUL_SH 16 - -//Check some ranges -#if ENV_EXTRA > 3 -#error Too many envelope bits -#endif - - -//How much to substract from the base value for the final attenuation -static const Bit8u KslCreateTable[16] = { - //0 will always be be lower than 7 * 8 - 64, 32, 24, 19, - 16, 12, 11, 10, - 8, 6, 5, 4, - 3, 2, 1, 0, -}; - -#define M(_X_) ((Bit8u)( (_X_) * 2)) -static const Bit8u FreqCreateTable[16] = { - M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ), - M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15) -}; -#undef M - -//We're not including the highest attack rate, that gets a special value -static const Bit8u AttackSamplesTable[13] = { - 69, 55, 46, 40, - 35, 29, 23, 20, - 19, 15, 11, 10, - 9 -}; -//On a real opl these values take 8 samples to reach and are based upon larger tables -static const Bit8u EnvelopeIncreaseTable[13] = { - 4, 5, 6, 7, - 8, 10, 12, 14, - 16, 20, 24, 28, - 32, -}; - -#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) -static Bit16u ExpTable[ 256 ]; -#endif - -#if ( DBOPL_WAVE == WAVE_HANDLER ) -//PI table used by WAVEHANDLER -static Bit16u SinTable[ 512 ]; -#endif - -#if ( DBOPL_WAVE > WAVE_HANDLER ) -//Layout of the waveform table in 512 entry intervals -//With overlapping waves we reduce the table to half it's size - -// | |//\\|____|WAV7|//__|/\ |____|/\/\| -// |\\//| | |WAV7| | \/| | | -// |06 |0126|17 |7 |3 |4 |4 5 |5 | - -//6 is just 0 shifted and masked - -static Bit16s WaveTable[ 8 * 512 ]; -//Distance into WaveTable the wave starts -static const Bit16u WaveBaseTable[8] = { - 0x000, 0x200, 0x200, 0x800, - 0xa00, 0xc00, 0x100, 0x400, - -}; -//Mask the counter with this -static const Bit16u WaveMaskTable[8] = { - 1023, 1023, 511, 511, - 1023, 1023, 512, 1023, -}; - -//Where to start the counter on at keyon -static const Bit16u WaveStartTable[8] = { - 512, 0, 0, 0, - 0, 512, 512, 256, -}; -#endif - -#if ( DBOPL_WAVE == WAVE_TABLEMUL ) -static Bit16u MulTable[ 384 ]; -#endif - -static Bit8u KslTable[ 8 * 16 ]; -static Bit8u TremoloTable[ TREMOLO_TABLE ]; -//Start of a channel behind the chip struct start -static Bit16u ChanOffsetTable[32]; -//Start of an operator behind the chip struct start -static Bit16u OpOffsetTable[64]; - -//The lower bits are the shift of the operator vibrato value -//The highest bit is right shifted to generate -1 or 0 for negation -//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0 -static const Bit8s VibratoTable[ 8 ] = { - 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, - 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 -}; - -//Shift strength for the ksl value determined by ksl strength -static const Bit8u KslShiftTable[4] = { - 31,1,2,0 -}; - -//Generate a table index and table shift value using input value from a selected rate -static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) { - if ( val < 13 * 4 ) { //Rate 0 - 12 - shift = 12 - ( val >> 2 ); - index = val & 3; - } else if ( val < 15 * 4 ) { //rate 13 - 14 - shift = 0; - index = val - 12 * 4; - } else { //rate 15 and up - shift = 0; - index = 12; - } -} - -#if ( DBOPL_WAVE == WAVE_HANDLER ) -/* - Generate the different waveforms out of the sine/exponetial table using handlers -*/ -static inline Bits MakeVolume( Bitu wave, Bitu volume ) { - Bitu total = wave + volume; - Bitu index = total & 0xff; - Bitu sig = ExpTable[ index ]; - Bitu exp = total >> 8; -#if 0 - //Check if we overflow the 31 shift limit - if ( exp >= 32 ) { - LOG_MSG( "WTF %d %d", total, exp ); - } -#endif - return (sig >> exp); -}; - -static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) { - Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 - Bitu wave = SinTable[i & 511]; - return (MakeVolume( wave, volume ) ^ neg) - neg; -} -static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) { - Bit32u wave = SinTable[i & 511]; - wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) { - Bitu wave = SinTable[i & 511]; - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) { - Bitu wave = SinTable[i & 255]; - wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 ); - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) { - //Twice as fast - i <<= 1; - Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 - Bitu wave = SinTable[i & 511]; - wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); - return (MakeVolume( wave, volume ) ^ neg) - neg; -} -static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) { - //Twice as fast - i <<= 1; - Bitu wave = SinTable[i & 511]; - wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) { - Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 - return (MakeVolume( 0, volume ) ^ neg) - neg; -} -static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) { - //Negative is reversed here - Bits neg = (( i >> 9) & 1) - 1; - Bitu wave = (i << 3); - //When negative the volume also runs backwards - wave = ((wave ^ neg) - neg) & 4095; - return (MakeVolume( wave, volume ) ^ neg) - neg; -} - -static const WaveHandler WaveHandlerTable[8] = { - WaveForm0, WaveForm1, WaveForm2, WaveForm3, - WaveForm4, WaveForm5, WaveForm6, WaveForm7 -}; - -#endif - -/* - Operator -*/ - -//We zero out when rate == 0 -inline void Operator::UpdateAttack( const Chip* chip ) { - Bit8u rate = reg60 >> 4; - if ( rate ) { - Bit8u val = (rate << 2) + ksr; - attackAdd = chip->attackRates[ val ]; - rateZero &= ~(1 << ATTACK); - } else { - attackAdd = 0; - rateZero |= (1 << ATTACK); - } -} -inline void Operator::UpdateDecay( const Chip* chip ) { - Bit8u rate = reg60 & 0xf; - if ( rate ) { - Bit8u val = (rate << 2) + ksr; - decayAdd = chip->linearRates[ val ]; - rateZero &= ~(1 << DECAY); - } else { - decayAdd = 0; - rateZero |= (1 << DECAY); - } -} -inline void Operator::UpdateRelease( const Chip* chip ) { - Bit8u rate = reg80 & 0xf; - if ( rate ) { - Bit8u val = (rate << 2) + ksr; - releaseAdd = chip->linearRates[ val ]; - rateZero &= ~(1 << RELEASE); - if ( !(reg20 & MASK_SUSTAIN ) ) { - rateZero &= ~( 1 << SUSTAIN ); - } - } else { - rateZero |= (1 << RELEASE); - releaseAdd = 0; - if ( !(reg20 & MASK_SUSTAIN ) ) { - rateZero |= ( 1 << SUSTAIN ); - } - } -} - -inline void Operator::UpdateAttenuation( ) { - Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff); - Bit32u tl = reg40 & 0x3f; - Bit8u kslShift = KslShiftTable[ reg40 >> 6 ]; - //Make sure the attenuation goes to the right bits - totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max - totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift; -} - -void Operator::UpdateFrequency( ) { - Bit32u freq = chanData & (( 1 << 10 ) - 1); - Bit32u block = (chanData >> 10) & 0xff; -#ifdef WAVE_PRECISION - block = 7 - block; - waveAdd = ( freq * freqMul ) >> block; -#else - waveAdd = ( freq << block ) * freqMul; -#endif - if ( reg20 & MASK_VIBRATO ) { - vibStrength = (Bit8u)(freq >> 7); - -#ifdef WAVE_PRECISION - vibrato = ( vibStrength * freqMul ) >> block; -#else - vibrato = ( vibStrength << block ) * freqMul; -#endif - } else { - vibStrength = 0; - vibrato = 0; - } -} - -void Operator::UpdateRates( const Chip* chip ) { - //Mame seems to reverse this where enabling ksr actually lowers - //the rate, but pdf manuals says otherwise? - Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff); - if ( !( reg20 & MASK_KSR ) ) { - newKsr >>= 2; - } - if ( ksr == newKsr ) - return; - ksr = newKsr; - UpdateAttack( chip ); - UpdateDecay( chip ); - UpdateRelease( chip ); -} - -INLINE Bit32s Operator::RateForward( Bit32u add ) { - rateIndex += add; - Bit32s ret = rateIndex >> RATE_SH; - rateIndex = rateIndex & RATE_MASK; - return ret; -} - -template< Operator::State yes> -Bits Operator::TemplateVolume( ) { - Bit32s vol = volume; - Bit32s change; - switch ( yes ) { - case OFF: - return ENV_MAX; - case ATTACK: - change = RateForward( attackAdd ); - if ( !change ) - return vol; - vol += ( (~vol) * change ) >> 3; - if ( vol < ENV_MIN ) { - volume = ENV_MIN; - rateIndex = 0; - SetState( DECAY ); - return ENV_MIN; - } - break; - case DECAY: - vol += RateForward( decayAdd ); - if ( GCC_UNLIKELY(vol >= sustainLevel) ) { - //Check if we didn't overshoot max attenuation, then just go off - if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { - volume = ENV_MAX; - SetState( OFF ); - return ENV_MAX; - } - //Continue as sustain - rateIndex = 0; - SetState( SUSTAIN ); - } - break; - case SUSTAIN: - if ( reg20 & MASK_SUSTAIN ) { - return vol; - } - //In sustain phase, but not sustaining, do regular release - case RELEASE: - vol += RateForward( releaseAdd );; - if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { - volume = ENV_MAX; - SetState( OFF ); - return ENV_MAX; - } - break; - } - volume = vol; - return vol; -} - -static const VolumeHandler VolumeHandlerTable[5] = { - &Operator::TemplateVolume< Operator::OFF >, - &Operator::TemplateVolume< Operator::RELEASE >, - &Operator::TemplateVolume< Operator::SUSTAIN >, - &Operator::TemplateVolume< Operator::DECAY >, - &Operator::TemplateVolume< Operator::ATTACK > -}; - -INLINE Bitu Operator::ForwardVolume() { - return currentLevel + (this->*volHandler)(); -} - - -INLINE Bitu Operator::ForwardWave() { - waveIndex += waveCurrent; - return waveIndex >> WAVE_SH; -} - -void Operator::Write20( const Chip* chip, Bit8u val ) { - Bit8u change = (reg20 ^ val ); - if ( !change ) - return; - reg20 = val; - //Shift the tremolo bit over the entire register, saved a branch, YES! - tremoloMask = (Bit8s)(val) >> 7; - tremoloMask &= ~(( 1 << ENV_EXTRA ) -1); - //Update specific features based on changes - if ( change & MASK_KSR ) { - UpdateRates( chip ); - } - //With sustain enable the volume doesn't change - if ( reg20 & MASK_SUSTAIN || ( !releaseAdd ) ) { - rateZero |= ( 1 << SUSTAIN ); - } else { - rateZero &= ~( 1 << SUSTAIN ); - } - //Frequency multiplier or vibrato changed - if ( change & (0xf | MASK_VIBRATO) ) { - freqMul = chip->freqMul[ val & 0xf ]; - UpdateFrequency(); - } -} - -void Operator::Write40( const Chip* /*chip*/, Bit8u val ) { - if (!(reg40 ^ val )) - return; - reg40 = val; - UpdateAttenuation( ); -} - -void Operator::Write60( const Chip* chip, Bit8u val ) { - Bit8u change = reg60 ^ val; - reg60 = val; - if ( change & 0x0f ) { - UpdateDecay( chip ); - } - if ( change & 0xf0 ) { - UpdateAttack( chip ); - } -} - -void Operator::Write80( const Chip* chip, Bit8u val ) { - Bit8u change = (reg80 ^ val ); - if ( !change ) - return; - reg80 = val; - Bit8u sustain = val >> 4; - //Turn 0xf into 0x1f - sustain |= ( sustain + 1) & 0x10; - sustainLevel = sustain << ( ENV_BITS - 5 ); - if ( change & 0x0f ) { - UpdateRelease( chip ); - } -} - -void Operator::WriteE0( const Chip* chip, Bit8u val ) { - if ( !(regE0 ^ val) ) - return; - //in opl3 mode you can always selet 7 waveforms regardless of waveformselect - Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); - regE0 = val; -#if ( DBOPL_WAVE == WAVE_HANDLER ) - waveHandler = WaveHandlerTable[ waveForm ]; -#else - waveBase = WaveTable + WaveBaseTable[ waveForm ]; - waveStart = WaveStartTable[ waveForm ] << WAVE_SH; - waveMask = WaveMaskTable[ waveForm ]; -#endif -} - -INLINE void Operator::SetState( Bit8u s ) { - state = s; - volHandler = VolumeHandlerTable[ s ]; -} - -INLINE bool Operator::Silent() const { - if ( !ENV_SILENT( totalLevel + volume ) ) - return false; - if ( !(rateZero & ( 1 << state ) ) ) - return false; - return true; -} - -INLINE void Operator::Prepare( const Chip* chip ) { - currentLevel = totalLevel + (chip->tremoloValue & tremoloMask); - waveCurrent = waveAdd; - if ( vibStrength >> chip->vibratoShift ) { - Bit32s add = vibrato >> chip->vibratoShift; - //Sign extend over the shift value - Bit32s neg = chip->vibratoSign; - //Negate the add with -1 or 0 - add = ( add ^ neg ) - neg; - waveCurrent += add; - } -} - -void Operator::KeyOn( Bit8u mask ) { - if ( !keyOn ) { - //Restart the frequency generator -#if ( DBOPL_WAVE > WAVE_HANDLER ) - waveIndex = waveStart; -#else - waveIndex = 0; -#endif - rateIndex = 0; - SetState( ATTACK ); - } - keyOn |= mask; -} - -void Operator::KeyOff( Bit8u mask ) { - keyOn &= ~mask; - if ( !keyOn ) { - if ( state != OFF ) { - SetState( RELEASE ); - } - } -} - -INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) { -#if ( DBOPL_WAVE == WAVE_HANDLER ) - return waveHandler( index, vol << ( 3 - ENV_EXTRA ) ); -#elif ( DBOPL_WAVE == WAVE_TABLEMUL ) - return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; -#elif ( DBOPL_WAVE == WAVE_TABLELOG ) - Bit32s wave = waveBase[ index & waveMask ]; - Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA ); - Bit32s sig = ExpTable[ total & 0xff ]; - Bit32u exp = total >> 8; - Bit32s neg = wave >> 16; - return ((sig ^ neg) - neg) >> exp; -#else -#error "No valid wave routine" -#endif -} - -Bits INLINE Operator::GetSample( Bits modulation ) { - Bitu vol = ForwardVolume(); - if ( ENV_SILENT( vol ) ) { - //Simply forward the wave - waveIndex += waveCurrent; - return 0; - } else { - Bitu index = ForwardWave(); - index += modulation; - return GetWave( index, vol ); - } -} - -Operator::Operator() { - chanData = 0; - freqMul = 0; - waveIndex = 0; - waveAdd = 0; - waveCurrent = 0; - keyOn = 0; - ksr = 0; - reg20 = 0; - reg40 = 0; - reg60 = 0; - reg80 = 0; - regE0 = 0; - SetState( OFF ); - rateZero = (1 << OFF); - sustainLevel = ENV_MAX; - currentLevel = ENV_MAX; - totalLevel = ENV_MAX; - volume = ENV_MAX; - releaseAdd = 0; -} - -/* - Channel -*/ - -Channel::Channel() { - old[0] = old[1] = 0; - chanData = 0; - regB0 = 0; - regC0 = 0; - maskLeft = -1; - maskRight = -1; - feedback = 31; - fourMask = 0; - synthHandler = &Channel::BlockTemplate< sm2FM >; -}; - -void Channel::SetChanData( const Chip* chip, Bit32u data ) { - Bit32u change = chanData ^ data; - chanData = data; - Op( 0 )->chanData = data; - Op( 1 )->chanData = data; - //Since a frequency update triggered this, always update frequency - Op( 0 )->UpdateFrequency(); - Op( 1 )->UpdateFrequency(); - if ( change & ( 0xff << SHIFT_KSLBASE ) ) { - Op( 0 )->UpdateAttenuation(); - Op( 1 )->UpdateAttenuation(); - } - if ( change & ( 0xff << SHIFT_KEYCODE ) ) { - Op( 0 )->UpdateRates( chip ); - Op( 1 )->UpdateRates( chip ); - } -} - -void Channel::UpdateFrequency( const Chip* chip, Bit8u fourOp ) { - //Extrace the frequency bits - Bit32u data = chanData & 0xffff; - Bit32u kslBase = KslTable[ data >> 6 ]; - Bit32u keyCode = ( data & 0x1c00) >> 9; - if ( chip->reg08 & 0x40 ) { - keyCode |= ( data & 0x100)>>8; /* notesel == 1 */ - } else { - keyCode |= ( data & 0x200)>>9; /* notesel == 0 */ - } - //Add the keycode and ksl into the highest bits of chanData - data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE ); - ( this + 0 )->SetChanData( chip, data ); - if ( fourOp & 0x3f ) { - ( this + 1 )->SetChanData( chip, data ); - } -} - -void Channel::WriteA0( const Chip* chip, Bit8u val ) { - Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; - //Don't handle writes to silent fourop channels - if ( fourOp > 0x80 ) - return; - Bit32u change = (chanData ^ val ) & 0xff; - if ( change ) { - chanData ^= change; - UpdateFrequency( chip, fourOp ); - } -} - -void Channel::WriteB0( const Chip* chip, Bit8u val ) { - Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; - //Don't handle writes to silent fourop channels - if ( fourOp > 0x80 ) - return; - Bitu change = (chanData ^ ( val << 8 ) ) & 0x1f00; - if ( change ) { - chanData ^= change; - UpdateFrequency( chip, fourOp ); - } - //Check for a change in the keyon/off state - if ( !(( val ^ regB0) & 0x20)) - return; - regB0 = val; - if ( val & 0x20 ) { - Op(0)->KeyOn( 0x1 ); - Op(1)->KeyOn( 0x1 ); - if ( fourOp & 0x3f ) { - ( this + 1 )->Op(0)->KeyOn( 1 ); - ( this + 1 )->Op(1)->KeyOn( 1 ); - } - } else { - Op(0)->KeyOff( 0x1 ); - Op(1)->KeyOff( 0x1 ); - if ( fourOp & 0x3f ) { - ( this + 1 )->Op(0)->KeyOff( 1 ); - ( this + 1 )->Op(1)->KeyOff( 1 ); - } - } -} - -void Channel::WriteC0( const Chip* chip, Bit8u val ) { - Bit8u change = val ^ regC0; - if ( !change ) - return; - regC0 = val; - feedback = ( val >> 1 ) & 7; - if ( feedback ) { - //We shift the input to the right 10 bit wave index value - feedback = 9 - feedback; - } else { - feedback = 31; - } - //Select the new synth mode - if ( chip->opl3Active ) { - //4-op mode enabled for this channel - if ( (chip->reg104 & fourMask) & 0x3f ) { - Channel* chan0, *chan1; - //Check if it's the 2nd channel in a 4-op - if ( !(fourMask & 0x80 ) ) { - chan0 = this; - chan1 = this + 1; - } else { - chan0 = this - 1; - chan1 = this; - } - - Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); - switch ( synth ) { - case 0: - chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >; - break; - case 1: - chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >; - break; - case 2: - chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >; - break; - case 3: - chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >; - break; - } - //Disable updating percussion channels - } else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) { - - //Regular dual op, am or fm - } else if ( val & 1 ) { - synthHandler = &Channel::BlockTemplate< sm3AM >; - } else { - synthHandler = &Channel::BlockTemplate< sm3FM >; - } - maskLeft = ( val & 0x10 ) ? -1 : 0; - maskRight = ( val & 0x20 ) ? -1 : 0; - //opl2 active - } else { - //Disable updating percussion channels - if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { - - //Regular dual op, am or fm - } else if ( val & 1 ) { - synthHandler = &Channel::BlockTemplate< sm2AM >; - } else { - synthHandler = &Channel::BlockTemplate< sm2FM >; - } - } -} - -void Channel::ResetC0( const Chip* chip ) { - Bit8u val = regC0; - regC0 ^= 0xff; - WriteC0( chip, val ); -}; - -template< bool opl3Mode> -INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) { - Channel* chan = this; - - //BassDrum - Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; - old[0] = old[1]; - old[1] = Op(0)->GetSample( mod ); - - //When bassdrum is in AM mode first operator is ignoed - if ( chan->regC0 & 1 ) { - mod = 0; - } else { - mod = old[0]; - } - Bit32s sample = Op(1)->GetSample( mod ); - - - //Precalculate stuff used by other outputs - Bit32u noiseBit = chip->ForwardNoise() & 0x1; - Bit32u c2 = Op(2)->ForwardWave(); - Bit32u c5 = Op(5)->ForwardWave(); - Bit32u phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00; - - //Hi-Hat - Bit32u hhVol = Op(2)->ForwardVolume(); - if ( !ENV_SILENT( hhVol ) ) { - Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 ))); - sample += Op(2)->GetWave( hhIndex, hhVol ); - } - //Snare Drum - Bit32u sdVol = Op(3)->ForwardVolume(); - if ( !ENV_SILENT( sdVol ) ) { - Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 ); - sample += Op(3)->GetWave( sdIndex, sdVol ); - } - //Tom-tom - sample += Op(4)->GetSample( 0 ); - - //Top-Cymbal - Bit32u tcVol = Op(5)->ForwardVolume(); - if ( !ENV_SILENT( tcVol ) ) { - Bit32u tcIndex = (1 + phaseBit) << 8; - sample += Op(5)->GetWave( tcIndex, tcVol ); - } - sample <<= 1; - if ( opl3Mode ) { - output[0] += sample; - output[1] += sample; - } else { - output[0] += sample; - } -} - -template -Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { - switch( mode ) { - case sm2AM: - case sm3AM: - if ( Op(0)->Silent() && Op(1)->Silent() ) { - old[0] = old[1] = 0; - return (this + 1); - } - break; - case sm2FM: - case sm3FM: - if ( Op(1)->Silent() ) { - old[0] = old[1] = 0; - return (this + 1); - } - break; - case sm3FMFM: - if ( Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm3AMFM: - if ( Op(0)->Silent() && Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm3FMAM: - if ( Op(1)->Silent() && Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm3AMAM: - if ( Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm2Percussion: - case sm3Percussion: - break; - } - //Init the operators with the the current vibrato and tremolo values - Op( 0 )->Prepare( chip ); - Op( 1 )->Prepare( chip ); - if ( mode > sm4Start ) { - Op( 2 )->Prepare( chip ); - Op( 3 )->Prepare( chip ); - } - if ( mode > sm6Start ) { - Op( 4 )->Prepare( chip ); - Op( 5 )->Prepare( chip ); - } - for ( Bitu i = 0; i < samples; i++ ) { - //Early out for percussion handlers - if ( mode == sm2Percussion ) { - GeneratePercussion( chip, output + i ); - continue; //Prevent some unitialized value bitching - } else if ( mode == sm3Percussion ) { - GeneratePercussion( chip, output + i * 2 ); - continue; //Prevent some unitialized value bitching - } - - //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise - Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; - old[0] = old[1]; - old[1] = Op(0)->GetSample( mod ); - Bit32s sample; - Bit32s out0 = old[0]; - if ( mode == sm2AM || mode == sm3AM ) { - sample = out0 + Op(1)->GetSample( 0 ); - } else if ( mode == sm2FM || mode == sm3FM ) { - sample = Op(1)->GetSample( out0 ); - } else if ( mode == sm3FMFM ) { - Bits next = Op(1)->GetSample( out0 ); - next = Op(2)->GetSample( next ); - sample = Op(3)->GetSample( next ); - } else if ( mode == sm3AMFM ) { - sample = out0; - Bits next = Op(1)->GetSample( 0 ); - next = Op(2)->GetSample( next ); - sample += Op(3)->GetSample( next ); - } else if ( mode == sm3FMAM ) { - sample = Op(1)->GetSample( out0 ); - Bits next = Op(2)->GetSample( 0 ); - sample += Op(3)->GetSample( next ); - } else if ( mode == sm3AMAM ) { - sample = out0; - Bits next = Op(1)->GetSample( 0 ); - sample += Op(2)->GetSample( next ); - sample += Op(3)->GetSample( 0 ); - } - switch( mode ) { - case sm2AM: - case sm2FM: - if (chip->is_opl3) - { - output[ i * 2 + 0 ] += sample; - output[ i * 2 + 1 ] += sample; - } - else - output[ i ] += sample; - break; - case sm3AM: - case sm3FM: - case sm3FMFM: - case sm3AMFM: - case sm3FMAM: - case sm3AMAM: - output[ i * 2 + 0 ] += sample & maskLeft; - output[ i * 2 + 1 ] += sample & maskRight; - break; - case sm2Percussion: - case sm3Percussion: - break; - } - } - switch( mode ) { - case sm2AM: - case sm2FM: - case sm3AM: - case sm3FM: - return ( this + 1 ); - case sm3FMFM: - case sm3AMFM: - case sm3FMAM: - case sm3AMAM: - return( this + 2 ); - case sm2Percussion: - case sm3Percussion: - return( this + 3 ); - } - return 0; -} - -/* - Chip -*/ - -Chip::Chip() { - reg08 = 0; - reg04 = 0; - regBD = 0; - reg104 = 0; - opl3Active = 0; -} - -INLINE Bit32u Chip::ForwardNoise() { - noiseCounter += noiseAdd; - Bitu count = noiseCounter >> LFO_SH; - noiseCounter &= WAVE_MASK; - for ( ; count > 0; --count ) { - //Noise calculation from mame - noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) ); - noiseValue >>= 1; - } - return noiseValue; -} - -INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) { - //Current vibrato value, runs 4x slower than tremolo - vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7; - vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength; - tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength; - - //Check hom many samples there can be done before the value changes - Bit32u todo = LFO_MAX - lfoCounter; - Bit32u count = (todo + lfoAdd - 1) / lfoAdd; - if ( count > samples ) { - count = samples; - lfoCounter += count * lfoAdd; - } else { - lfoCounter += count * lfoAdd; - lfoCounter &= (LFO_MAX - 1); - //Maximum of 7 vibrato value * 4 - vibratoIndex = ( vibratoIndex + 1 ) & 31; - //Clip tremolo to the the table size - if ( tremoloIndex + 1 < TREMOLO_TABLE ) - ++tremoloIndex; - else - tremoloIndex = 0; - } - return count; -} - - -void Chip::WriteBD( Bit8u val ) { - Bit8u change = regBD ^ val; - if ( !change ) - return; - regBD = val; - //TODO could do this with shift and xor? - vibratoStrength = (val & 0x40) ? 0x00 : 0x01; - tremoloStrength = (val & 0x80) ? 0x00 : 0x02; - if ( val & 0x20 ) { - //Drum was just enabled, make sure channel 6 has the right synth - if ( change & 0x20 ) { - // if ( opl3Active ) { - if ( is_opl3 ) { - chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >; - } else { - chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >; - } - } - //Bass Drum - if ( val & 0x10 ) { - chan[6].op[0].KeyOn( 0x2 ); - chan[6].op[1].KeyOn( 0x2 ); - } else { - chan[6].op[0].KeyOff( 0x2 ); - chan[6].op[1].KeyOff( 0x2 ); - } - //Hi-Hat - if ( val & 0x1 ) { - chan[7].op[0].KeyOn( 0x2 ); - } else { - chan[7].op[0].KeyOff( 0x2 ); - } - //Snare - if ( val & 0x8 ) { - chan[7].op[1].KeyOn( 0x2 ); - } else { - chan[7].op[1].KeyOff( 0x2 ); - } - //Tom-Tom - if ( val & 0x4 ) { - chan[8].op[0].KeyOn( 0x2 ); - } else { - chan[8].op[0].KeyOff( 0x2 ); - } - //Top Cymbal - if ( val & 0x2 ) { - chan[8].op[1].KeyOn( 0x2 ); - } else { - chan[8].op[1].KeyOff( 0x2 ); - } - //Toggle keyoffs when we turn off the percussion - } else if ( change & 0x20 ) { - //Trigger a reset to setup the original synth handler - chan[6].ResetC0( this ); - chan[6].op[0].KeyOff( 0x2 ); - chan[6].op[1].KeyOff( 0x2 ); - chan[7].op[0].KeyOff( 0x2 ); - chan[7].op[1].KeyOff( 0x2 ); - chan[8].op[0].KeyOff( 0x2 ); - chan[8].op[1].KeyOff( 0x2 ); - } -} - - -#define REGOP( _FUNC_ ) \ - index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \ - if ( OpOffsetTable[ index ] ) { \ - Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] ); \ - regOp->_FUNC_( this, val ); \ - } - -#define REGCHAN( _FUNC_ ) \ - index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \ - if ( ChanOffsetTable[ index ] ) { \ - Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] ); \ - regChan->_FUNC_( this, val ); \ - } - -void Chip::WriteReg( Bit32u reg, Bit8u val ) { - Bitu index; - switch ( (reg & 0xf0) >> 4 ) { - case 0x00 >> 4: - if ( reg == 0x01 ) { - waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0; - } else if ( reg == 0x104 ) { - //Only detect changes in lowest 6 bits - if ( !((reg104 ^ val) & 0x3f) ) - return; - //Always keep the highest bit enabled, for checking > 0x80 - reg104 = 0x80 | ( val & 0x3f ); - } else if ( reg == 0x105 ) { - //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register - if ( !((opl3Active ^ val) & 1 ) ) - return; - opl3Active = ( val & 1 ) ? 0xff : 0; - //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers - for ( int i = 0; i < 18;i++ ) { - chan[i].ResetC0( this ); - } - } else if ( reg == 0x08 ) { - reg08 = val; - } - case 0x10 >> 4: - break; - case 0x20 >> 4: - case 0x30 >> 4: - REGOP( Write20 ); - break; - case 0x40 >> 4: - case 0x50 >> 4: - REGOP( Write40 ); - break; - case 0x60 >> 4: - case 0x70 >> 4: - REGOP( Write60 ); - break; - case 0x80 >> 4: - case 0x90 >> 4: - REGOP( Write80 ); - break; - case 0xa0 >> 4: - REGCHAN( WriteA0 ); - break; - case 0xb0 >> 4: - if ( reg == 0xbd ) { - WriteBD( val ); - } else { - REGCHAN( WriteB0 ); - } - break; - case 0xc0 >> 4: - REGCHAN( WriteC0 ); - case 0xd0 >> 4: - break; - case 0xe0 >> 4: - case 0xf0 >> 4: - REGOP( WriteE0 ); - break; - } -} - - -Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) { - switch ( port & 3 ) { - case 0: - return val; - case 2: - if ( opl3Active || (val == 0x05) ) - return 0x100 | val; - else - return val; - } - return 0; -} - -void Chip::GenerateBlock2( Bitu total, Bit32s* output ) { - while ( total > 0 ) { - Bit32u samples = ForwardLFO( total ); - memset(output, 0, sizeof(Bit32s) * samples); - int count = 0; - for( Channel* ch = chan; ch < chan + 9; ) { - count++; - ch = (ch->*(ch->synthHandler))( this, samples, output ); - } - total -= samples; - output += samples; - } -} - -void Chip::GenerateBlock3( Bitu total, Bit32s* output ) { - while ( total > 0 ) { - Bit32u samples = ForwardLFO( total ); - memset(output, 0, sizeof(Bit32s) * samples *2); - int count = 0; - for( Channel* ch = chan; ch < chan + 18; ) { - count++; - ch = (ch->*(ch->synthHandler))( this, samples, output ); - } - total -= samples; - output += samples * 2; - } -} - -void Chip::Setup( Bit32u rate, int chip_is_opl3 ) { - double original = OPLRATE; -// double original = rate; - double scale = original / (double)rate; - - is_opl3 = chip_is_opl3; - - //Noise counter is run at the same precision as general waves - noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - noiseCounter = 0; - noiseValue = 1; //Make sure it triggers the noise xor the first time - //The low frequency oscillation counter - //Every time his overflows vibrato and tremoloindex are increased - lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - lfoCounter = 0; - vibratoIndex = 0; - tremoloIndex = 0; - - //With higher octave this gets shifted up - //-1 since the freqCreateTable = *2 -#ifdef WAVE_PRECISION - double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); - for ( int i = 0; i < 16; i++ ) { - freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] ); - } -#else - Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); - for ( int i = 0; i < 16; i++ ) { - freqMul[i] = freqScale * FreqCreateTable[ i ]; - } -#endif - - //-3 since the real envelope takes 8 steps to reach the single value we supply - for ( Bit8u i = 0; i < 76; i++ ) { - Bit8u index, shift; - EnvelopeSelect( i, index, shift ); - linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); - } - //Generate the best matching attack rate - for ( Bit8u i = 0; i < 62; i++ ) { - Bit8u index, shift; - EnvelopeSelect( i, index, shift ); - //Original amount of samples the attack would take - Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); - - Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); - Bit32s bestAdd = guessAdd; - Bit32u bestDiff = 1 << 30; - for( Bit32u passes = 0; passes < 16; passes ++ ) { - Bit32s volume = ENV_MAX; - Bit32s samples = 0; - Bit32u count = 0; - while ( volume > 0 && samples < original * 2 ) { - count += guessAdd; - Bit32s change = count >> RATE_SH; - count &= RATE_MASK; - if ( GCC_UNLIKELY(change) ) { // less than 1 % - volume += ( ~volume * change ) >> 3; - } - samples++; - - } - Bit32s diff = original - samples; - Bit32u lDiff = labs( diff ); - //Init last on first pass - if ( lDiff < bestDiff ) { - bestDiff = lDiff; - bestAdd = guessAdd; - if ( !bestDiff ) - break; - } - //Below our target - if ( diff < 0 ) { - //Better than the last time - Bit32s mul = ((original - diff) << 12) / original; - guessAdd = ((guessAdd * mul) >> 12); - guessAdd++; - } else if ( diff > 0 ) { - Bit32s mul = ((original - diff) << 12) / original; - guessAdd = (guessAdd * mul) >> 12; - guessAdd--; - } - } - attackRates[i] = bestAdd; - } - for ( Bit8u i = 62; i < 76; i++ ) { - //This should provide instant volume maximizing - attackRates[i] = 8 << RATE_SH; - } - //Setup the channels with the correct four op flags - //Channels are accessed through a table so they appear linear here - chan[ 0].fourMask = 0x00 | ( 1 << 0 ); - chan[ 1].fourMask = 0x80 | ( 1 << 0 ); - chan[ 2].fourMask = 0x00 | ( 1 << 1 ); - chan[ 3].fourMask = 0x80 | ( 1 << 1 ); - chan[ 4].fourMask = 0x00 | ( 1 << 2 ); - chan[ 5].fourMask = 0x80 | ( 1 << 2 ); - - chan[ 9].fourMask = 0x00 | ( 1 << 3 ); - chan[10].fourMask = 0x80 | ( 1 << 3 ); - chan[11].fourMask = 0x00 | ( 1 << 4 ); - chan[12].fourMask = 0x80 | ( 1 << 4 ); - chan[13].fourMask = 0x00 | ( 1 << 5 ); - chan[14].fourMask = 0x80 | ( 1 << 5 ); - - //mark the percussion channels - chan[ 6].fourMask = 0x40; - chan[ 7].fourMask = 0x40; - chan[ 8].fourMask = 0x40; - - //Clear Everything in opl3 mode - WriteReg( 0x105, 0x1 ); - for ( int i = 0; i < 512; i++ ) { - if ( i == 0x105 ) - continue; - WriteReg( i, 0xff ); - WriteReg( i, 0x0 ); - } - WriteReg( 0x105, 0x0 ); - //Clear everything in opl2 mode - for ( int i = 0; i < 255; i++ ) { - WriteReg( i, 0xff ); - WriteReg( i, 0x0 ); - } -} - -static bool doneTables = false; -void InitTables( void ) { - if ( doneTables ) - return; - doneTables = true; -#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) - //Exponential volume table, same as the real adlib - for ( int i = 0; i < 256; i++ ) { - //Save them in reverse - ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 ); - ExpTable[i] += 1024; //or remove the -1 oh well :) - //Preshift to the left once so the final volume can shift to the right - ExpTable[i] *= 2; - } -#endif -#if ( DBOPL_WAVE == WAVE_HANDLER ) - //Add 0.5 for the trunc rounding of the integer cast - //Do a PI sinetable instead of the original 0.5 PI - for ( int i = 0; i < 512; i++ ) { - SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); - } -#endif -#if ( DBOPL_WAVE == WAVE_TABLEMUL ) - //Multiplication based tables - for ( int i = 0; i < 384; i++ ) { - int s = i * 8; - //TODO maybe keep some of the precision errors of the original table? - double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH )); - MulTable[i] = (Bit16u)(val); - } - - //Sine Wave Base - for ( int i = 0; i < 512; i++ ) { - WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084); - WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ]; - } - //Exponential wave - for ( int i = 0; i < 256; i++ ) { - WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 ); - WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ]; - } -#endif -#if ( DBOPL_WAVE == WAVE_TABLELOG ) - //Sine Wave Base - for ( int i = 0; i < 512; i++ ) { - WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); - WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i]; - } - //Exponential wave - for ( int i = 0; i < 256; i++ ) { - WaveTable[ 0x700 + i ] = i * 8; - WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; - } -#endif - - // | |//\\|____|WAV7|//__|/\ |____|/\/\| - // |\\//| | |WAV7| | \/| | | - // |06 |0126|27 |7 |3 |4 |4 5 |5 | - -#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) - for ( int i = 0; i < 256; i++ ) { - //Fill silence gaps - WaveTable[ 0x400 + i ] = WaveTable[0]; - WaveTable[ 0x500 + i ] = WaveTable[0]; - WaveTable[ 0x900 + i ] = WaveTable[0]; - WaveTable[ 0xc00 + i ] = WaveTable[0]; - WaveTable[ 0xd00 + i ] = WaveTable[0]; - //Replicate sines in other pieces - WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ]; - //double speed sines - WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ]; - WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ]; - WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ]; - WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ]; - } -#endif - - //Create the ksl table - for ( int oct = 0; oct < 8; oct++ ) { - int base = oct * 8; - for ( int i = 0; i < 16; i++ ) { - int val = base - KslCreateTable[i]; - if ( val < 0 ) - val = 0; - //*4 for the final range to match attenuation range - KslTable[ oct * 16 + i ] = val * 4; - } - } - //Create the Tremolo table, just increase and decrease a triangle wave - for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) { - Bit8u val = i << ENV_EXTRA; - TremoloTable[i] = val; - TremoloTable[TREMOLO_TABLE - 1 - i] = val; - } - //Create a table with offsets of the channels from the start of the chip - DBOPL::Chip* chip = 0; - for ( Bitu i = 0; i < 32; i++ ) { - Bitu index = i & 0xf; - if ( index >= 9 ) { - ChanOffsetTable[i] = 0; - continue; - } - //Make sure the four op channels follow eachother - if ( index < 6 ) { - index = (index % 3) * 2 + ( index / 3 ); - } - //Add back the bits for highest ones - if ( i >= 16 ) - index += 9; - intptr_t blah = reinterpret_cast( &(chip->chan[ index ]) ); - ChanOffsetTable[i] = blah; - } - //Same for operators - for ( Bitu i = 0; i < 64; i++ ) { - if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { - OpOffsetTable[i] = 0; - continue; - } - Bitu chNum = (i / 8) * 3 + (i % 8) % 3; - //Make sure we use 16 and up for the 2nd range to match the chanoffset gap - if ( chNum >= 12 ) - chNum += 16 - 12; - Bitu opNum = ( i % 8 ) / 3; - DBOPL::Channel* chan = 0; - intptr_t blah = reinterpret_cast( &(chan->op[opNum]) ); - OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah; - } -#if 0 - //Stupid checks if table's are correct - for ( Bitu i = 0; i < 18; i++ ) { - Bit32u find = (Bit16u)( &(chip->chan[ i ]) ); - for ( Bitu c = 0; c < 32; c++ ) { - if ( ChanOffsetTable[c] == find ) { - find = 0; - break; - } - } - if ( find ) { - find = find; - } - } - for ( Bitu i = 0; i < 36; i++ ) { - Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) ); - for ( Bitu c = 0; c < 64; c++ ) { - if ( OpOffsetTable[c] == find ) { - find = 0; - break; - } - } - if ( find ) { - find = find; - } - } -#endif -} - -/*Bit32u Handler::WriteAddr( Bit32u port, Bit8u val ) { - return chip.WriteAddr( port, val ); - -} -void Handler::WriteReg( Bit32u addr, Bit8u val ) { - chip.WriteReg( addr, val ); -} - -void Handler::Generate( MixerChannel* chan, Bitu samples ) { - Bit32s buffer[ 512 * 2 ]; - if ( GCC_UNLIKELY(samples > 512) ) - samples = 512; - if ( !chip.opl3Active ) { - chip.GenerateBlock2( samples, buffer ); - chan->AddSamples_m32( samples, buffer ); - } else { - chip.GenerateBlock3( samples, buffer ); - chan->AddSamples_s32( samples, buffer ); - } -} - -void Handler::Init( Bitu rate ) { - InitTables(); - chip.Setup( rate ); -}*/ - - -}; //Namespace DBOPL - diff --git a/src/sound/dbopl.h b/src/sound/dbopl.h deleted file mode 100644 index 7507dd1a4..000000000 --- a/src/sound/dbopl.h +++ /dev/null @@ -1,259 +0,0 @@ -/* Copyright holders: The DOSBox Team - see COPYING for more details -*/ - -//#include "adlib.h" -//#include "dosbox.h" -#include -typedef signed int Bits; -typedef unsigned int Bitu; -typedef int8_t Bit8s; -typedef uint8_t Bit8u; -typedef int16_t Bit16s; -typedef uint16_t Bit16u; -typedef int32_t Bit32s; -typedef uint32_t Bit32u; - -#define INLINE inline - -#define GCC_UNLIKELY(x) (x) - -//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume -#define WAVE_HANDLER 10 -//Use a logarithmic wavetable with an exponential table for volume -#define WAVE_TABLELOG 11 -//Use a linear wavetable with a multiply table for volume -#define WAVE_TABLEMUL 12 - -//Select the type of wave generator routine -#define DBOPL_WAVE WAVE_TABLEMUL - -namespace DBOPL { - -struct Chip; -struct Operator; -struct Channel; - -#if (DBOPL_WAVE == WAVE_HANDLER) -typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); -#endif - -typedef Bits ( DBOPL::Operator::*VolumeHandler) ( ); -typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output ); - -//Different synth modes that can generate blocks of data -typedef enum { - sm2AM, - sm2FM, - sm3AM, - sm3FM, - sm4Start, - sm3FMFM, - sm3AMFM, - sm3FMAM, - sm3AMAM, - sm6Start, - sm2Percussion, - sm3Percussion, -} SynthMode; - -//Shifts for the values contained in chandata variable -enum { - SHIFT_KSLBASE = 16, - SHIFT_KEYCODE = 24, -}; - -struct Operator { -public: - //Masks for operator 20 values - enum { - MASK_KSR = 0x10, - MASK_SUSTAIN = 0x20, - MASK_VIBRATO = 0x40, - MASK_TREMOLO = 0x80, - }; - - typedef enum { - OFF, - RELEASE, - SUSTAIN, - DECAY, - ATTACK, - } State; - - VolumeHandler volHandler; - -#if (DBOPL_WAVE == WAVE_HANDLER) - WaveHandler waveHandler; //Routine that generate a wave -#else - Bit16s* waveBase; - Bit32u waveMask; - Bit32u waveStart; -#endif - Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index - Bit32u waveAdd; //The base frequency without vibrato - Bit32u waveCurrent; //waveAdd + vibratao - - Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this - Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove? - Bit32u vibrato; //Scaled up vibrato strength - Bit32s sustainLevel; //When stopping at sustain level stop here - Bit32s totalLevel; //totalLevel is added to every generated volume - Bit32u currentLevel; //totalLevel + tremolo - Bit32s volume; //The currently active volume - - Bit32u attackAdd; //Timers for the different states of the envelope - Bit32u decayAdd; - Bit32u releaseAdd; - Bit32u rateIndex; //Current position of the evenlope - - Bit8u rateZero; //Bits for the different states of the envelope having no changes - Bit8u keyOn; //Bitmask of different values that can generate keyon - //Registers, also used to check for changes - Bit8u reg20, reg40, reg60, reg80, regE0; - //Active part of the envelope we're in - Bit8u state; - //0xff when tremolo is enabled - Bit8u tremoloMask; - //Strength of the vibrato - Bit8u vibStrength; - //Keep track of the calculated KSR so we can check for changes - Bit8u ksr; -private: - void SetState( Bit8u s ); - void UpdateAttack( const Chip* chip ); - void UpdateRelease( const Chip* chip ); - void UpdateDecay( const Chip* chip ); -public: - void UpdateAttenuation(); - void UpdateRates( const Chip* chip ); - void UpdateFrequency( ); - - void Write20( const Chip* chip, Bit8u val ); - void Write40( const Chip* chip, Bit8u val ); - void Write60( const Chip* chip, Bit8u val ); - void Write80( const Chip* chip, Bit8u val ); - void WriteE0( const Chip* chip, Bit8u val ); - - bool Silent() const; - void Prepare( const Chip* chip ); - - void KeyOn( Bit8u mask); - void KeyOff( Bit8u mask); - - template< State state> - Bits TemplateVolume( ); - - Bit32s RateForward( Bit32u add ); - Bitu ForwardWave(); - Bitu ForwardVolume(); - - Bits GetSample( Bits modulation ); - Bits GetWave( Bitu index, Bitu vol ); -public: - Operator(); -}; - -struct Channel { - Operator op[2]; - inline Operator* Op( Bitu index ) { - return &( ( this + (index >> 1) )->op[ index & 1 ]); - } - SynthHandler synthHandler; - Bit32u chanData; //Frequency/octave and derived values - Bit32s old[2]; //Old data for feedback - - Bit8u feedback; //Feedback shift - Bit8u regB0; //Register values to check for changes - Bit8u regC0; - //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel - Bit8u fourMask; - Bit8s maskLeft; //Sign extended values for both channel's panning - Bit8s maskRight; - - //Forward the channel data to the operators of the channel - void SetChanData( const Chip* chip, Bit32u data ); - //Change in the chandata, check for new values and if we have to forward to operators - void UpdateFrequency( const Chip* chip, Bit8u fourOp ); - void WriteA0( const Chip* chip, Bit8u val ); - void WriteB0( const Chip* chip, Bit8u val ); - void WriteC0( const Chip* chip, Bit8u val ); - void ResetC0( const Chip* chip ); - - //call this for the first channel - template< bool opl3Mode > - void GeneratePercussion( Chip* chip, Bit32s* output ); - - //Generate blocks of data in specific modes - template - Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ); - Channel(); -}; - -struct Chip { - //This is used as the base counter for vibrato and tremolo - Bit32u lfoCounter; - Bit32u lfoAdd; - - - Bit32u noiseCounter; - Bit32u noiseAdd; - Bit32u noiseValue; - - //Frequency scales for the different multiplications - Bit32u freqMul[16]; - //Rates for decay and release for rate of this chip - Bit32u linearRates[76]; - //Best match attack rates for the rate of this chip - Bit32u attackRates[76]; - - //18 channels with 2 operators each - Channel chan[18]; - - Bit8u reg104; - Bit8u reg08; - Bit8u reg04; - Bit8u regBD; - Bit8u vibratoIndex; - Bit8u tremoloIndex; - Bit8s vibratoSign; - Bit8u vibratoShift; - Bit8u tremoloValue; - Bit8u vibratoStrength; - Bit8u tremoloStrength; - //Mask for allowed wave forms - Bit8u waveFormMask; - //0 or -1 when enabled - Bit8s opl3Active; - - int is_opl3; - - //Return the maximum amount of samples before and LFO change - Bit32u ForwardLFO( Bit32u samples ); - Bit32u ForwardNoise(); - - void WriteBD( Bit8u val ); - void WriteReg(Bit32u reg, Bit8u val ); - - Bit32u WriteAddr( Bit32u port, Bit8u val ); - - void GenerateBlock2( Bitu samples, Bit32s* output ); - void GenerateBlock3( Bitu samples, Bit32s* output ); - - void Generate( Bit32u samples ); - void Setup( Bit32u r, int chip_is_opl3 ); - - Chip(); -}; - -/*struct Handler : public Adlib::Handler { - DBOPL::Chip chip; - virtual Bit32u WriteAddr( Bit32u port, Bit8u val ); - virtual void WriteReg( Bit32u addr, Bit8u val ); - virtual void Generate( MixerChannel* chan, Bitu samples ); - virtual void Init( Bitu rate ); -};*/ - -void InitTables( void ); - -}; //Namespace diff --git a/src/sound/midi.c b/src/sound/midi.c index d49eb6b29..31a8b86bf 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -1,3 +1,25 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * MIDI device core module. + * + * Version: @(#)midi.c 1.0.2 2018/12/31 + * + * Authors: Sarah Walker, + * Miran Grca, + * Bit, + * DOSBox Team, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2018 Bit. + * Copyright 2008-2018 DOSBox Team. + */ #include #include #include @@ -15,246 +37,371 @@ #ifdef USE_MUNT # include "midi_mt32.h" #endif +#include "midi_input.h" int midi_device_current = 0; static int midi_device_last = 0; +int midi_input_device_current = 0; +static int midi_input_device_last = 0; +midi_t *midi = NULL, *midi_in = NULL; + +void (*input_msg)(void *p, uint8_t *msg); +int (*input_sysex)(void *p, uint8_t *buffer, uint32_t len, int abort); +void *midi_in_p; + +uint8_t MIDI_InSysexBuf[SYSEX_SIZE]; + +uint8_t MIDI_evt_len[256] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x00 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x10 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x20 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x30 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x40 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x50 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x60 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x70 */ + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0x80 */ + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0x90 */ + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0xa0 */ + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0xb0 */ + + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* 0xc0 */ + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* 0xd0 */ + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0xe0 */ + + 0,2,3,2, 0,0,1,0, 1,0,1,1, 1,0,1,0 /* 0xf0 */ +}; typedef struct { - const char *name; - const char *internal_name; - const device_t *device; -} MIDI_DEVICE; + const char *name, *internal_name; + const device_t *device; +} MIDI_DEVICE, MIDI_IN_DEVICE; static const MIDI_DEVICE devices[] = { - {"None", "none", NULL}, + {"None", "none", NULL}, #ifdef USE_FLUIDSYNTH - {"FluidSynth", "fluidsynth", &fluidsynth_device}, + {"FluidSynth", "fluidsynth", &fluidsynth_device}, #endif #ifdef USE_MUNT - {"Roland MT-32 Emulation", "mt32", &mt32_device}, - {"Roland CM-32L Emulation", "cm32l", &cm32l_device}, + {"Roland MT-32 Emulation", "mt32", &mt32_device}, + {"Roland CM-32L Emulation", "cm32l", &cm32l_device}, #endif - {SYSTEM_MIDI_NAME, SYSTEM_MIDI_INTERNAL_NAME, &system_midi_device}, - {"", "", NULL} + {SYSTEM_MIDI_NAME, SYSTEM_MIDI_INTERNAL_NAME, &system_midi_device}, + {"", "", NULL} }; -static midi_device_t* m_device = NULL; - -int midi_device_available(int card) +static const MIDI_IN_DEVICE midi_in_devices[] = { - if (devices[card].device) - return device_available(devices[card].device); + {"None", "none", NULL}, + {MIDI_INPUT_NAME, MIDI_INPUT_INTERNAL_NAME, &midi_input_device}, + {"", "", NULL} +}; - return 1; +int +midi_device_available(int card) +{ + if (devices[card].device) + return device_available(devices[card].device); + + return 1; } -char *midi_device_getname(int card) + +char * +midi_device_getname(int card) { - return (char *) devices[card].name; + return (char *) devices[card].name; } -const device_t *midi_device_getdevice(int card) + +const device_t * +midi_device_getdevice(int card) { - return devices[card].device; + return devices[card].device; } -int midi_device_has_config(int card) -{ - if (!devices[card].device) - return 0; - return devices[card].device->config ? 1 : 0; -} -char *midi_device_get_internal_name(int card) +int +midi_device_has_config(int card) { - return (char *) devices[card].internal_name; -} - -int midi_device_get_from_internal_name(char *s) -{ - int c = 0; - - while (strlen(devices[c].internal_name)) - { - if (!strcmp(devices[c].internal_name, s)) - return c; - c++; - } - + if (!devices[card].device) return 0; + return devices[card].device->config ? 1 : 0; } -void midi_device_init() + +char * +midi_device_get_internal_name(int card) { - if (devices[midi_device_current].device) - device_add(devices[midi_device_current].device); - midi_device_last = midi_device_current; + return (char *) devices[card].internal_name; } -static uint8_t midi_rt_buf[1024]; -static uint8_t midi_cmd_buf[1024]; -static int midi_cmd_pos = 0; -static int midi_cmd_len = 0; -static uint8_t midi_status = 0; -static unsigned int midi_sysex_start = 0; -static unsigned int midi_sysex_delay = 0; -uint8_t MIDI_evt_len[256] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x00 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x10 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x20 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x30 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x40 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x50 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x60 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x70 - - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x80 - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x90 - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xa0 - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xb0 - - 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xc0 - 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xd0 - - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xe0 - - 0,2,3,2, 0,0,1,0, 1,0,1,1, 1,0,1,0 // 0xf0 -}; - -static unsigned int midi_pos; -static uint8_t midi_sysex_data[1024+2]; - -void midi_init(midi_device_t* device) +int +midi_device_get_from_internal_name(char *s) { - memset(midi_rt_buf, 0, sizeof(midi_rt_buf)); - memset(midi_cmd_buf, 0, sizeof(midi_cmd_buf)); + int c = 0; - midi_cmd_pos = midi_cmd_len = 0; - midi_status = 0; - - midi_sysex_start = midi_sysex_delay = 0; - - m_device = device; + while (strlen(devices[c].internal_name)) { + if (!strcmp(devices[c].internal_name, s)) + return c; + c++; + } + return 0; } -void midi_close() + +void +midi_device_init() { - m_device = NULL; + if (devices[midi_device_current].device) + device_add(devices[midi_device_current].device); + midi_device_last = midi_device_current; } -void midi_poll() + +void +midi_init(midi_device_t* device) { - if (m_device && m_device->poll) m_device->poll(); + midi = (midi_t *) malloc(sizeof(midi_t)); + memset(midi, 0, sizeof(midi_t)); + + midi->m_out_device = device; } -void play_msg(uint8_t *msg) +void +midi_in_init(midi_device_t* device, midi_t **mididev) { - if (m_device->play_msg) m_device->play_msg(msg); + *mididev = (midi_t *)malloc(sizeof(midi_t)); + memset(*mididev, 0, sizeof(midi_t)); + + (*mididev)->m_in_device = device; } -void play_sysex(uint8_t *sysex, unsigned int len) +void +midi_close(void) { - if (m_device->play_sysex) m_device->play_sysex(sysex, len); + if (midi && midi->m_out_device) { + free(midi->m_out_device); + midi->m_out_device = NULL; + } + + if (midi) { + free(midi); + midi = NULL; + } } -#define SYSEX_SIZE 1024 -#define RAWBUF 1024 - -void midi_write(uint8_t val) +void +midi_in_close(void) { - if (!m_device) return; + if (midi_in && midi_in->m_in_device) { + free(midi_in->m_in_device); + midi_in->m_in_device = NULL; + } - if (m_device->write && m_device->write(val)) return; - - uint32_t passed_ticks; - - if (midi_sysex_start) - { - passed_ticks = plat_get_ticks() - midi_sysex_start; - if (passed_ticks < midi_sysex_delay) - { - plat_delay_ms(midi_sysex_delay - passed_ticks); - } - } - - /* Test for a realtime MIDI message */ - if (val >= 0xf8) - { - midi_rt_buf[0] = val; - play_msg(midi_rt_buf); - return; - } - - /* Test for a active sysex transfer */ - - if (midi_status == 0xf0) - { - if (!(val & 0x80)) - { - if (midi_pos < (SYSEX_SIZE-1)) midi_sysex_data[midi_pos++] = val; - return; - } - else - { - midi_sysex_data[midi_pos++] = 0xf7; - - if ((midi_sysex_start) && (midi_pos >= 4) && (midi_pos <= 9) && (midi_sysex_data[1] == 0x41) && (midi_sysex_data[3] == 0x16)) - { - /* pclog("MIDI: Skipping invalid MT-32 SysEx MIDI message\n"); */ - } - else - { - play_sysex(midi_sysex_data, midi_pos); - if (midi_sysex_start) - { - if (midi_sysex_data[5] == 0x7f) - { - midi_sysex_delay = 290; /* All parameters reset */ - } - else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x04)) - { - midi_sysex_delay = 145; /* Viking Child */ - } - else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x01)) - { - midi_sysex_delay = 30; /* Dark Sun 1 */ - } - else - midi_sysex_delay = (unsigned int) (((float) (midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; - - midi_sysex_start = plat_get_ticks(); - } - } - } - } - - - if (val & 0x80) - { - midi_status = val; - midi_cmd_pos = 0; - midi_cmd_len = MIDI_evt_len[val]; - if (midi_status == 0xf0) - { - midi_sysex_data[0] = 0xf0; - midi_pos = 1; - } - } - - if (midi_cmd_len) - { - midi_cmd_buf[midi_cmd_pos++] = val; - if (midi_cmd_pos >= midi_cmd_len) - { - play_msg(midi_cmd_buf); - midi_cmd_pos = 1; - } - } + if (midi_in) { + free(midi_in); + midi_in = NULL; + } } + + +void +midi_poll(void) +{ + if (midi && midi->m_out_device && midi->m_out_device->poll) + midi->m_out_device->poll(); +} + + +void +play_msg(uint8_t *msg) +{ + if (midi->m_out_device->play_msg) + midi->m_out_device->play_msg(msg); +} + + +void +play_sysex(uint8_t *sysex, unsigned int len) +{ + if (midi->m_out_device->play_sysex) + midi->m_out_device->play_sysex(sysex, len); +} + + +int +midi_in_device_available(int card) +{ + if (midi_in_devices[card].device) + return device_available(midi_in_devices[card].device); + + return 1; +} + +char * +midi_in_device_getname(int card) +{ + return (char *) midi_in_devices[card].name; +} + +const device_t * +midi_in_device_getdevice(int card) +{ + return midi_in_devices[card].device; +} + +int +midi_in_device_has_config(int card) +{ + if (!midi_in_devices[card].device) + return 0; + return midi_in_devices[card].device->config ? 1 : 0; +} + + +char * +midi_in_device_get_internal_name(int card) +{ + return (char *) midi_in_devices[card].internal_name; +} + + +int +midi_in_device_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(midi_in_devices[c].internal_name)) { + if (!strcmp(midi_in_devices[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + +void +midi_in_device_init() +{ + if (midi_in_devices[midi_input_device_current].device) + device_add(midi_in_devices[midi_input_device_current].device); + midi_input_device_last = midi_input_device_current; +} + +void +midi_raw_out_rt_byte(uint8_t val) +{ + if (!midi_in->midi_realtime) + return; + + if ((!midi_in->midi_clockout && (val == 0xf8))) + return; + + midi_in->midi_cmd_r = val << 24; + pclog("Play RT Byte msg\n"); + play_msg((uint8_t *)&midi_in->midi_cmd_r); +} + +void +midi_raw_out_thru_rt_byte(uint8_t val) +{ + if (midi_in->thruchan) + midi_raw_out_rt_byte(val); +} + +void +midi_raw_out_byte(uint8_t val) +{ + uint32_t passed_ticks; + + if (!midi || !midi->m_out_device) { + return; + } + + if ((midi->m_out_device->write && midi->m_out_device->write(val))) { + return; + } + + if (midi->midi_sysex_start) { + passed_ticks = plat_get_ticks() - midi->midi_sysex_start; + if (passed_ticks < midi->midi_sysex_delay) + plat_delay_ms(midi->midi_sysex_delay - passed_ticks); + } + + /* Test for a realtime MIDI message */ + if (val >= 0xf8) { + midi->midi_rt_buf[0] = val; + play_msg(midi->midi_rt_buf); + return; + } + + /* Test for a active sysex transfer */ + if (midi->midi_status == 0xf0) { + if (!(val & 0x80)) { + if (midi->midi_pos < (SYSEX_SIZE-1)) + midi->midi_sysex_data[midi->midi_pos++] = val; + return; + } else { + midi->midi_sysex_data[midi->midi_pos++] = 0xf7; + + if ((midi->midi_sysex_start) && (midi->midi_pos >= 4) && (midi->midi_pos <= 9) && + (midi->midi_sysex_data[1] == 0x41) && (midi->midi_sysex_data[3] == 0x16)) { + /* pclog("MIDI: Skipping invalid MT-32 SysEx MIDI message\n"); */ + } else { + play_sysex(midi->midi_sysex_data, midi->midi_pos); + if (midi->midi_sysex_start) { + if (midi-> midi_sysex_data[5] == 0x7f) + midi->midi_sysex_delay = 290; /* All parameters reset */ + else if ((midi->midi_sysex_data[5] == 0x10) && (midi->midi_sysex_data[6] == 0x00) && + (midi->midi_sysex_data[7] == 0x04)) + midi->midi_sysex_delay = 145; /* Viking Child */ + else if ((midi->midi_sysex_data[5] == 0x10) && (midi->midi_sysex_data[6] == 0x00) && + (midi->midi_sysex_data[7] == 0x01)) + midi->midi_sysex_delay = 30; /* Dark Sun 1 */ + else + midi->midi_sysex_delay = (unsigned int) (((float) (midi->midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; + + midi->midi_sysex_start = plat_get_ticks(); + } + } + } + } + + if (val & 0x80) { + midi->midi_status = val; + midi->midi_cmd_pos = 0; + midi->midi_cmd_len = MIDI_evt_len[val]; + if (midi->midi_status == 0xf0) { + midi->midi_sysex_data[0] = 0xf0; + midi->midi_pos = 1; + } + } + + if (midi->midi_cmd_len) { + midi->midi_cmd_buf[midi->midi_cmd_pos++] = val; + if (midi->midi_cmd_pos >= midi->midi_cmd_len) { + play_msg(midi->midi_cmd_buf); + midi->midi_cmd_pos = 1; + } + } +} + +void +midi_clear_buffer(void) +{ + if (!midi) return; + midi->midi_pos = 0; + midi->midi_status = 0x00; + midi->midi_cmd_pos = 0; + midi->midi_cmd_len = 0; +} \ No newline at end of file diff --git a/src/sound/midi.h b/src/sound/midi.h index 6268a0e0c..8e516c2a3 100644 --- a/src/sound/midi.h +++ b/src/sound/midi.h @@ -2,18 +2,35 @@ # define EMU_SOUND_MIDI_H -extern int midi_device_current; +#define SYSEX_SIZE 8192 +extern uint8_t MIDI_InSysexBuf[SYSEX_SIZE]; +extern uint8_t MIDI_evt_len[256]; + +extern int midi_device_current; +extern int midi_input_device_current; + +extern void (*input_msg)(void *p, uint8_t *msg); +extern int (*input_sysex)(void *p, uint8_t *buffer, uint32_t len, int abort); +extern void *midi_in_p; int midi_device_available(int card); +int midi_in_device_available(int card); char *midi_device_getname(int card); +char *midi_in_device_getname(int card); #ifdef EMU_DEVICE_H const device_t *midi_device_getdevice(int card); +const device_t *midi_in_device_getdevice(int card); #endif int midi_device_has_config(int card); +int midi_in_device_has_config(int card); char *midi_device_get_internal_name(int card); +char *midi_in_device_get_internal_name(int card); int midi_device_get_from_internal_name(char *s); +int midi_in_device_get_from_internal_name(char *s); void midi_device_init(); +void midi_in_device_init(); + typedef struct midi_device_t { @@ -23,9 +40,27 @@ typedef struct midi_device_t int (*write)(uint8_t val); } midi_device_t; +typedef struct midi_t +{ + uint8_t midi_rt_buf[8], midi_cmd_buf[8], + midi_status, midi_sysex_data[SYSEX_SIZE]; + int midi_cmd_pos, midi_cmd_len, midi_cmd_r, + midi_realtime, thruchan, midi_clockout; + unsigned int midi_sysex_start, midi_sysex_delay, + midi_pos; + midi_device_t *m_out_device, *m_in_device; +} midi_t; + +extern midi_t *midi, *midi_in; + void midi_init(midi_device_t* device); +void midi_in_init(midi_device_t* device, midi_t **mididev); void midi_close(); -void midi_write(uint8_t val); +void midi_in_close(void); +void midi_raw_out_rt_byte(uint8_t val); +void midi_raw_out_thru_rt_byte(uint8_t val); +void midi_raw_out_byte(uint8_t val); +void midi_clear_buffer(void); void midi_poll(); #if 0 @@ -41,5 +76,7 @@ void midi_poll(); #define SYSTEM_MIDI_INTERNAL_NAME "system_midi" #endif +#define MIDI_INPUT_NAME "MIDI Input Device" +#define MIDI_INPUT_INTERNAL_NAME "midi_in" #endif /*EMU_SOUND_MIDI_H*/ diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index 22d318fbf..822213d11 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -43,7 +43,6 @@ enum fluid_interp { extern void givealbuffer_midi(void *buf, uint32_t size); extern void al_set_midi(int freq, int buf_size); -extern int soundon; static void *fluidsynth_handle; /* handle to FluidSynth DLL */ @@ -61,7 +60,6 @@ static int (*f_fluid_synth_sysex)(void *synth, const char *data, int len, char static int (*f_fluid_synth_pitch_bend)(void *synth, int chan, int val); static int (*f_fluid_synth_program_change)(void *synth, int chan, int program); static int (*f_fluid_synth_sfload)(void *synth, const char *filename, int reset_presets); -static int (*f_fluid_synth_sfunload)(void *synth, unsigned int id, int reset_presets); static int (*f_fluid_synth_set_interp_method)(void *synth, int chan, int interp_method); static void (*f_fluid_synth_set_reverb)(void *synth, double roomsize, double damping, double width, double level); static void (*f_fluid_synth_set_reverb_on)(void *synth, int on); @@ -84,7 +82,6 @@ static dllimp_t fluidsynth_imports[] = { { "fluid_synth_pitch_bend", &f_fluid_synth_pitch_bend }, { "fluid_synth_program_change", &f_fluid_synth_program_change }, { "fluid_synth_sfload", &f_fluid_synth_sfload }, - { "fluid_synth_sfunload", &f_fluid_synth_sfunload }, { "fluid_synth_set_interp_method", &f_fluid_synth_set_interp_method }, { "fluid_synth_set_reverb", &f_fluid_synth_set_reverb }, { "fluid_synth_set_reverb_on", &f_fluid_synth_set_reverb_on }, @@ -104,13 +101,14 @@ typedef struct fluidsynth int samplerate; int sound_font; - thread_t* thread_h; - event_t* event; + thread_t *thread_h; + event_t *event, *start_event; int buf_size; float* buffer; int16_t* buffer_int16; int midi_pos; + int on; } fluidsynth_t; fluidsynth_t fsdev; @@ -136,9 +134,14 @@ static void fluidsynth_thread(void *param) fluidsynth_t* data = (fluidsynth_t*)param; int buf_pos = 0; int buf_size = data->buf_size / BUFFER_SEGMENTS; - while (1) + + thread_set_event(data->start_event); + + while (data->on) { thread_wait_event(data->event, -1); + thread_reset_event(data->event); + if (sound_is_float) { float *buf = (float*)((uint8_t*)data->buffer + buf_pos); @@ -148,8 +151,7 @@ static void fluidsynth_thread(void *param) buf_pos += buf_size; if (buf_pos >= data->buf_size) { - if (soundon) - givealbuffer_midi(data->buffer, data->buf_size / sizeof(float)); + givealbuffer_midi(data->buffer, data->buf_size / sizeof(float)); buf_pos = 0; } } @@ -162,30 +164,10 @@ static void fluidsynth_thread(void *param) buf_pos += buf_size; if (buf_pos >= data->buf_size) { - if (soundon) - givealbuffer_midi(data->buffer_int16, data->buf_size / sizeof(int16_t)); + givealbuffer_midi(data->buffer_int16, data->buf_size / sizeof(int16_t)); buf_pos = 0; } } - -#if 0 - if (sound_is_float) - { - memset(data->buffer, 0, data->buf_size * sizeof(float)); - if (data->synth) - f_fluid_synth_write_float(data->synth, data->buf_size/2, data->buffer, 0, 2, data->buffer, 1, 2); - if (soundon) - givealbuffer_midi(data->buffer, data->buf_size); - } - else - { - memset(data->buffer, 0, data->buf_size * sizeof(int16_t)); - if (data->synth) - f_fluid_synth_write_s16(data->synth, data->buf_size/2, data->buffer_int16, 0, 2, data->buffer_int16, 1, 2); - if (soundon) - givealbuffer_midi(data->buffer_int16, data->buf_size); - } -#endif } } @@ -237,11 +219,13 @@ void fluidsynth_sysex(uint8_t* data, unsigned int len) void* fluidsynth_init(const device_t *info) { fluidsynth_t* data = &fsdev; + midi_device_t* dev; + memset(data, 0, sizeof(fluidsynth_t)); /* Try loading the DLL. */ #ifdef _WIN32 - fluidsynth_handle = dynld_module("libfluidsynth-1.dll", fluidsynth_imports); + fluidsynth_handle = dynld_module("libfluidsynth.dll", fluidsynth_imports); #else fluidsynth_handle = dynld_module("libfluidsynth.so", fluidsynth_imports); #endif @@ -258,7 +242,7 @@ void* fluidsynth_init(const device_t *info) data->synth = f_new_fluid_synth(data->settings); - char* sound_font = device_get_config_string("sound_font"); + char* sound_font = (char *) device_get_config_string("sound_font"); data->sound_font = f_fluid_synth_sfload(data->synth, sound_font, 1); if (device_get_config_int("chorus")) @@ -324,12 +308,10 @@ void* fluidsynth_init(const device_t *info) data->buffer = NULL; data->buffer_int16 = malloc(data->buf_size); } - data->event = thread_create_event(); - data->thread_h = thread_create(fluidsynth_thread, data); al_set_midi(data->samplerate, data->buf_size); - midi_device_t* dev = malloc(sizeof(midi_device_t)); + dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); dev->play_msg = fluidsynth_msg; @@ -338,6 +320,16 @@ void* fluidsynth_init(const device_t *info) midi_init(dev); + data->on = 1; + + data->start_event = thread_create_event(); + + data->event = thread_create_event(); + data->thread_h = thread_create(fluidsynth_thread, data); + + thread_wait_event(data->start_event, -1); + thread_reset_event(data->start_event); + return dev; } @@ -347,10 +339,9 @@ void fluidsynth_close(void* p) fluidsynth_t* data = &fsdev; - if (data->sound_font != -1) { - f_fluid_synth_sfunload(data->synth, data->sound_font, 1); - data->sound_font = -1; - } + data->on = 0; + thread_set_event(data->event); + thread_wait(data->thread_h, -1); if (data->synth) { f_delete_fluid_synth(data->synth); @@ -362,8 +353,6 @@ void fluidsynth_close(void* p) data->settings = NULL; } - midi_close(); - if (data->buffer) { free(data->buffer); diff --git a/src/sound/midi_input.h b/src/sound/midi_input.h new file mode 100644 index 000000000..163d6fa91 --- /dev/null +++ b/src/sound/midi_input.h @@ -0,0 +1 @@ +extern const device_t midi_input_device; diff --git a/src/sound/midi_mt32.c b/src/sound/midi_mt32.c index 7903b2b05..c62d98da2 100644 --- a/src/sound/midi_mt32.c +++ b/src/sound/midi_mt32.c @@ -83,6 +83,8 @@ int cm32l_available() static thread_t *thread_h = NULL; static event_t *event = NULL; +static event_t *start_event = NULL; +static int mt32_on = 0; #define RENDER_RATE 100 #define BUFFER_SEGMENTS 10 @@ -113,39 +115,41 @@ void mt32_poll() } } -extern int soundon; - static void mt32_thread(void *param) { int buf_pos = 0; int bsize = buf_size / BUFFER_SEGMENTS; - while (1) + float *buf; + int16_t *buf16; + + thread_set_event(start_event); + + while (mt32_on) { thread_wait_event(event, -1); + thread_reset_event(event); if (sound_is_float) { - float *buf = (float *) ((uint8_t*)buffer + buf_pos); + buf = (float *) ((uint8_t*)buffer + buf_pos); memset(buf, 0, bsize); mt32_stream(buf, bsize / (2 * sizeof(float))); buf_pos += bsize; if (buf_pos >= buf_size) { - if (soundon) - givealbuffer_midi(buffer, buf_size / sizeof(float)); + givealbuffer_midi(buffer, buf_size / sizeof(float)); buf_pos = 0; } } else { - int16_t *buf = (int16_t *) ((uint8_t*)buffer_int16 + buf_pos); - memset(buf, 0, bsize); - mt32_stream_int16(buf, bsize / (2 * sizeof(int16_t))); + buf16 = (int16_t *) ((uint8_t*)buffer_int16 + buf_pos); + memset(buf16, 0, bsize); + mt32_stream_int16(buf16, bsize / (2 * sizeof(int16_t))); buf_pos += bsize; if (buf_pos >= buf_size) { - if (soundon) - givealbuffer_midi(buffer_int16, buf_size / sizeof(int16_t)); + givealbuffer_midi(buffer_int16, buf_size / sizeof(int16_t)); buf_pos = 0; } } @@ -164,9 +168,12 @@ void mt32_sysex(uint8_t* data, unsigned int len) void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) { + midi_device_t* dev; wchar_t s[512]; char fn[512]; + context = mt32emu_create_context(handler, NULL); + if (!rom_getfile(control_rom, s, 512)) return 0; wcstombs(fn, s, (wcslen(s) << 1) + 2); if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_CONTROL_ROM)) return 0; @@ -176,8 +183,6 @@ void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) if (!mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) return 0; - event = thread_create_event(); - thread_h = thread_create(mt32_thread, 0); samplerate = mt32emu_get_actual_stereo_output_samplerate(context); /* buf_size = samplerate/RENDER_RATE*2; */ if (sound_is_float) @@ -201,7 +206,7 @@ void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) al_set_midi(samplerate, buf_size); - midi_device_t* dev = malloc(sizeof(midi_device_t)); + dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); dev->play_msg = mt32_msg; @@ -210,6 +215,16 @@ void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) midi_init(dev); + mt32_on = 1; + + start_event = thread_create_event(); + + event = thread_create_event(); + thread_h = thread_create(mt32_thread, 0); + + thread_wait_event(start_event, -1); + thread_reset_event(start_event); + return dev; } @@ -227,15 +242,15 @@ void mt32_close(void* p) { if (!p) return; - if (thread_h) - thread_kill(thread_h); - if (event) - thread_destroy_event(event); + mt32_on = 0; + thread_set_event(event); + thread_wait(thread_h, -1); + event = NULL; + start_event = NULL; thread_h = NULL; - if (context) - { + if (context) { mt32emu_close_synth(context); mt32emu_free_context(context); } @@ -248,10 +263,6 @@ void mt32_close(void* p) if (buffer_int16) free(buffer_int16); buffer_int16 = NULL; - - midi_close(); - - free((midi_device_t*)p); } static const device_config_t mt32_config[] = diff --git a/src/sound/midi_system.c b/src/sound/midi_system.c index d9a15c6a9..6ee56b01a 100644 --- a/src/sound/midi_system.c +++ b/src/sound/midi_system.c @@ -9,6 +9,7 @@ #include "../plat_midi.h" #include "midi.h" #include "midi_system.h" +#include "midi_input.h" void* system_midi_init(const device_t *info) @@ -27,6 +28,22 @@ void* system_midi_init(const device_t *info) return dev; } +void* midi_input_init(const device_t *info) +{ + midi_device_t* dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + plat_midi_input_init(); + + midi_in_init(dev, &midi_in); + + midi_in->midi_realtime = device_get_config_int("realtime"); + midi_in->thruchan = device_get_config_int("thruchan"); + midi_in->midi_clockout = device_get_config_int("clockout"); + + return dev; +} + void system_midi_close(void* p) { plat_midi_close(); @@ -34,11 +51,23 @@ void system_midi_close(void* p) midi_close(); } +void midi_input_close(void* p) +{ + plat_midi_input_close(); + + midi_close(); +} + int system_midi_available(void) { return plat_midi_get_num_devs(); } +int midi_input_available(void) +{ + return plat_midi_in_get_num_devs(); +} + static const device_config_t system_midi_config[] = { { @@ -52,6 +81,37 @@ static const device_config_t system_midi_config[] = } }; +static const device_config_t midi_input_config[] = +{ + { + .name = "midi_input", + .description = "MIDI in device", + .type = CONFIG_MIDI_IN, + .default_int = 0 + }, + { + .name = "realtime", + .description = "MIDI Real time", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "thruchan", + .description = "MIDI Thru", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "clockout", + .description = "MIDI Clockout", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = -1 + } +}; + const device_t system_midi_device = { SYSTEM_MIDI_NAME, @@ -64,3 +124,17 @@ const device_t system_midi_device = NULL, system_midi_config }; + + +const device_t midi_input_device = +{ + MIDI_INPUT_NAME, + 0, 0, + midi_input_init, + midi_input_close, + NULL, + midi_input_available, + NULL, + NULL, + midi_input_config +}; \ No newline at end of file diff --git a/src/sound/nukedopl.cpp b/src/sound/nukedopl.c similarity index 94% rename from src/sound/nukedopl.cpp rename to src/sound/nukedopl.c index 0039a63bc..a2bc192c5 100644 --- a/src/sound/nukedopl.cpp +++ b/src/sound/nukedopl.c @@ -179,7 +179,7 @@ static const Bit8u ch_slot[18] = { // typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); -typedef void(*envelope_genfunc)(opl3_slot *slott); +typedef void(*envelope_genfunc)(struct opl3_slot *slott); static Bit16s OPL3_EnvelopeCalcExp(Bit32u level) { @@ -346,7 +346,7 @@ enum envelope_gen_num envelope_gen_num_release = 3 }; -static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) +static void OPL3_EnvelopeUpdateKSL(struct opl3_slot *slot) { Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); @@ -357,7 +357,7 @@ static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) slot->eg_ksl = (Bit8u)ksl; } -static void OPL3_EnvelopeCalc(opl3_slot *slot) +static void OPL3_EnvelopeCalc(struct opl3_slot *slot) { Bit8u nonzero; Bit8u rate; @@ -504,12 +504,12 @@ static void OPL3_EnvelopeCalc(opl3_slot *slot) } } -static void OPL3_EnvelopeKeyOn(opl3_slot *slot, Bit8u type) +static void OPL3_EnvelopeKeyOn(struct opl3_slot *slot, Bit8u type) { slot->key |= type; } -static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) +static void OPL3_EnvelopeKeyOff(struct opl3_slot *slot, Bit8u type) { slot->key &= ~type; } @@ -518,9 +518,9 @@ static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) // Phase Generator // -static void OPL3_PhaseGenerate(opl3_slot *slot) +static void OPL3_PhaseGenerate(struct opl3_slot *slot) { - opl3_chip *chip; + struct opl3_chip *chip; Bit16u f_num; Bit32u basefreq; Bit8u rm_xor, n_bit; @@ -612,7 +612,7 @@ static void OPL3_PhaseGenerate(opl3_slot *slot) // Slot // -static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) +static void OPL3_SlotWrite20(struct opl3_slot *slot, Bit8u data) { if ((data >> 7) & 0x01) { @@ -628,20 +628,20 @@ static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) slot->reg_mult = data & 0x0f; } -static void OPL3_SlotWrite40(opl3_slot *slot, Bit8u data) +static void OPL3_SlotWrite40(struct 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) +static void OPL3_SlotWrite60(struct opl3_slot *slot, Bit8u data) { slot->reg_ar = (data >> 4) & 0x0f; slot->reg_dr = data & 0x0f; } -static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) +static void OPL3_SlotWrite80(struct opl3_slot *slot, Bit8u data) { slot->reg_sl = (data >> 4) & 0x0f; if (slot->reg_sl == 0x0f) @@ -651,7 +651,7 @@ static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) slot->reg_rr = data & 0x0f; } -static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) +static void OPL3_SlotWriteE0(struct opl3_slot *slot, Bit8u data) { slot->reg_wf = data & 0x07; if (slot->chip->newm == 0x00) @@ -660,12 +660,12 @@ static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) } } -static void OPL3_SlotGenerate(opl3_slot *slot) +static void OPL3_SlotGenerate(struct opl3_slot *slot) { slot->out = envelope_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, slot->eg_out); } -static void OPL3_SlotCalcFB(opl3_slot *slot) +static void OPL3_SlotCalcFB(struct opl3_slot *slot) { if (slot->channel->fb != 0x00) { @@ -682,13 +682,13 @@ static void OPL3_SlotCalcFB(opl3_slot *slot) // Channel // -static void OPL3_ChannelSetupAlg(opl3_channel *channel); +static void OPL3_ChannelSetupAlg(struct opl3_channel *channel); -static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) +static void OPL3_ChannelUpdateRhythm(struct opl3_chip *chip, Bit8u data) { - opl3_channel *channel6; - opl3_channel *channel7; - opl3_channel *channel8; + struct opl3_channel *channel6; + struct opl3_channel *channel7; + struct opl3_channel *channel8; Bit8u chnum; chip->rhy = data & 0x3f; @@ -776,7 +776,7 @@ static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) } } -static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) +static void OPL3_ChannelWriteA0(struct opl3_channel *channel, Bit8u data) { if (channel->chip->newm && channel->chtype == ch_4op2) { @@ -796,7 +796,7 @@ static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) } } -static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) +static void OPL3_ChannelWriteB0(struct opl3_channel *channel, Bit8u data) { if (channel->chip->newm && channel->chtype == ch_4op2) { @@ -818,7 +818,7 @@ static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) } } -static void OPL3_ChannelSetupAlg(opl3_channel *channel) +static void OPL3_ChannelSetupAlg(struct opl3_channel *channel) { if (channel->chtype == ch_drum) { @@ -919,7 +919,7 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel) } } -static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) +static void OPL3_ChannelWriteC0(struct opl3_channel *channel, Bit8u data) { channel->fb = (data & 0x0e) >> 1; channel->con = data & 0x01; @@ -958,7 +958,7 @@ static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) } } -static void OPL3_ChannelKeyOn(opl3_channel *channel) +static void OPL3_ChannelKeyOn(struct opl3_channel *channel) { if (channel->chip->newm) { @@ -982,7 +982,7 @@ static void OPL3_ChannelKeyOn(opl3_channel *channel) } } -static void OPL3_ChannelKeyOff(opl3_channel *channel) +static void OPL3_ChannelKeyOff(struct opl3_channel *channel) { if (channel->chip->newm) { @@ -1006,7 +1006,7 @@ static void OPL3_ChannelKeyOff(opl3_channel *channel) } } -static void OPL3_ChannelSet4Op(opl3_chip *chip, Bit8u data) +static void OPL3_ChannelSet4Op(struct opl3_chip *chip, Bit8u data) { Bit8u bit; Bit8u chnum; @@ -1043,7 +1043,7 @@ static Bit16s OPL3_ClipSample(Bit32s sample) return (Bit16s)sample; } -void OPL3_Generate(opl3_chip *chip, Bit16s *buf) +void OPL3_Generate(struct opl3_chip *chip, Bit16s *buf) { Bit8u ii; Bit8u jj; @@ -1175,7 +1175,7 @@ void OPL3_Generate(opl3_chip *chip, Bit16s *buf) chip->writebuf_samplecnt++; } -void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf) +void OPL3_GenerateResampled(struct opl3_chip *chip, Bit32s *buf) { while (chip->samplecnt >= chip->rateratio) { @@ -1184,19 +1184,19 @@ void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf) OPL3_Generate(chip, chip->samples); chip->samplecnt -= chip->rateratio; } - buf[0] = (Bit16s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + buf[0] = (Bit32s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + chip->samples[0] * chip->samplecnt) / chip->rateratio); - buf[1] = (Bit16s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + buf[1] = (Bit32s)((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) +void OPL3_Reset(struct opl3_chip *chip, Bit32u samplerate) { Bit8u slotnum; Bit8u channum; - memset(chip, 0, sizeof(opl3_chip)); + memset(chip, 0, sizeof(struct opl3_chip)); for (slotnum = 0; slotnum < 36; slotnum++) { chip->slot[slotnum].chip = chip; @@ -1238,7 +1238,7 @@ void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) chip->vibshift = 1; } -Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val) +Bit32u OPL3_WriteAddr(struct opl3_chip *chip, Bit32u port, Bit8u val) { Bit16u addr; addr = val; @@ -1248,7 +1248,7 @@ Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val) return addr; } -void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) +void OPL3_WriteReg(struct opl3_chip *chip, Bit16u reg, Bit8u v) { Bit8u high = (reg >> 8) & 0x01; Bit8u regm = reg & 0xff; @@ -1347,7 +1347,7 @@ void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) } } -void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v) +void OPL3_WriteRegBuffered(struct opl3_chip *chip, Bit16u reg, Bit8u v) { Bit64u time1, time2; @@ -1375,7 +1375,7 @@ void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v) chip->writebuf_last = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; } -void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) +void OPL3_GenerateStream(struct opl3_chip *chip, Bit32s *sndptr, Bit32u numsamples) { Bit32u i; diff --git a/src/sound/nukedopl.h b/src/sound/nukedopl.h index 9570298fb..6b3f09228 100644 --- a/src/sound/nukedopl.h +++ b/src/sound/nukedopl.h @@ -46,11 +46,12 @@ typedef uint64_t Bit64u; struct opl3_slot; struct opl3_channel; +struct opl3_writebuf; struct opl3_chip; struct opl3_slot { - opl3_channel *channel; - opl3_chip *chip; + struct opl3_channel *channel; + struct opl3_chip *chip; Bit16s out; Bit16s fbmod; Bit16s *mod; @@ -81,9 +82,9 @@ struct opl3_slot { }; struct opl3_channel { - opl3_slot *slots[2]; - opl3_channel *pair; - opl3_chip *chip; + struct opl3_slot *slots[2]; + struct opl3_channel *pair; + struct opl3_chip *chip; Bit16s *out[4]; Bit8u chtype; Bit16u f_num; @@ -103,8 +104,8 @@ struct opl3_writebuf { }; struct opl3_chip { - opl3_channel channel[18]; - opl3_slot slot[36]; + struct opl3_channel channel[18]; + struct opl3_slot slot[36]; Bit16u timer; Bit64u eg_timer; Bit8u eg_timerrem; @@ -137,14 +138,14 @@ struct opl3_chip { Bit32u writebuf_cur; Bit32u writebuf_last; Bit64u writebuf_lasttime; - opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; + struct opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; }; -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_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); +void OPL3_Generate(struct opl3_chip *chip, Bit16s *buf); +void OPL3_GenerateResampled(struct opl3_chip *chip, Bit32s *buf); +void OPL3_Reset(struct opl3_chip *chip, Bit32u samplerate); +Bit32u OPL3_WriteAddr(struct opl3_chip *chip, Bit32u port, Bit8u val); +void OPL3_WriteReg(struct opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_WriteRegBuffered(struct opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_GenerateStream(struct opl3_chip *chip, Bit32s *sndptr, Bit32u numsamples); #endif diff --git a/src/sound/openal.c b/src/sound/openal.c index 319623816..185730a57 100644 --- a/src/sound/openal.c +++ b/src/sound/openal.c @@ -8,13 +8,13 @@ * * Interface to the OpenAL sound processing library. * - * Version: @(#)openal.c 1.0.6 2018/04/23 + * Version: @(#)openal.c 1.0.7 2019/10/31 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -47,7 +47,9 @@ static ALuint source[3]; /* audio source */ static int midi_freq = 44100; static int midi_buf_size = 4410; static int initialized = 0; - +static int sources = 2; +static ALCcontext *Context; +static ALCdevice *Device; void al_set_midi(int freq, int buf_size) @@ -60,9 +62,6 @@ al_set_midi(int freq, int buf_size) void closeal(void); ALvoid alutInit(ALint *argc,ALbyte **argv) { - ALCcontext *Context; - ALCdevice *Device; - /* Open device */ Device = alcOpenDevice((ALCchar *)""); if (Device != NULL) { @@ -79,24 +78,17 @@ ALvoid alutInit(ALint *argc,ALbyte **argv) ALvoid alutExit(ALvoid) { - ALCcontext *Context; - ALCdevice *Device; - - /* Get active context */ - Context = alcGetCurrentContext(); if (Context != NULL) { - /* Get device for active context */ - Device = alcGetContextsDevice(Context); - if (Device != NULL) { - /* Disable context */ - alcMakeContextCurrent(NULL); - - /* Close device */ - alcCloseDevice(Device); - } + /* Disable context */ + alcMakeContextCurrent(NULL); /* Release context(s) */ alcDestroyContext(Context); + + if (Device != NULL) { + /* Close device */ + alcCloseDevice(Device); + } } } @@ -104,7 +96,16 @@ alutExit(ALvoid) void closeal(void) { - if (!initialized) return; + if (!initialized) + return; + + alSourceStopv(sources, source); + alDeleteSources(sources, source); + + if (sources == 3) + alDeleteBuffers(4, buffers_midi); + alDeleteBuffers(4, buffers_cd); + alDeleteBuffers(4, buffers); alutExit(); @@ -122,7 +123,8 @@ inital(void) char *mdn; int init_midi = 0; - if (initialized) return; + if (initialized) + return; alutInit(0, 0); atexit(closeal); @@ -131,6 +133,7 @@ inital(void) if (strcmp(mdn, "none") && strcmp(mdn, SYSTEM_MIDI_INTERNAL_NAME)) init_midi = 1; /* If the device is neither none, nor system MIDI, initialize the MIDI buffer and source, otherwise, do not. */ + sources = 2 + !!init_midi; if (sound_is_float) { buf = (float *) malloc((BUFLEN << 1) * sizeof(float)); @@ -231,6 +234,9 @@ givealbuffer_common(void *buf, uint8_t src, int size, int freq) ALuint buffer; double gain; + if (!initialized) + return; + alGetSourcei(source[src], AL_SOURCE_STATE, &state); if (state == 0x1014) { @@ -244,11 +250,10 @@ givealbuffer_common(void *buf, uint8_t src, int size, int freq) alSourceUnqueueBuffers(source[src], 1, &buffer); - if (sound_is_float) { + if (sound_is_float) alBufferData(buffer, AL_FORMAT_STEREO_FLOAT32, buf, size * sizeof(float), freq); - } else { + else alBufferData(buffer, AL_FORMAT_STEREO16, buf, size * sizeof(int16_t), freq); - } alSourceQueueBuffers(source[src], 1, &buffer); } diff --git a/src/sound/resid-fp/sid.cc b/src/sound/resid-fp/sid.cc index eda01ab2f..431d5712d 100644 --- a/src/sound/resid-fp/sid.cc +++ b/src/sound/resid-fp/sid.cc @@ -96,7 +96,7 @@ static int host_cpu_features(void) static int features = 0; static int features_detected = 0; /* 32-bit only */ -#if defined(__i386__) || (defined(_MSC_VER) && defined(_WIN32)) +#if defined(__i386__) || (defined(_MSC_VER) && defined(_M_IX86)) unsigned long temp1, temp2; #endif @@ -104,7 +104,7 @@ static int host_cpu_features(void) return features; features_detected = 1; -#if defined(_MSC_VER) && defined(_WIN32) /* MSVC compatible assembly appropriate for 32-bit Windows */ +#if defined(_MSC_VER) && defined(_M_IX86) /* MSVC compatible assembly appropriate for 32-bit Windows */ /* see if we are dealing with a cpu that has the cpuid instruction */ __asm { pushf @@ -127,7 +127,7 @@ static int host_cpu_features(void) : : "eax"); #endif -#if defined(__i386__) || (defined(_MSC_VER) && defined(_WIN32)) +#if defined(__i386__) || (defined(_MSC_VER) && defined(_M_IX86)) temp1 &= 0x200000; temp2 &= 0x200000; if (temp1 == temp2) { diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index a35646dc9..fd5631b12 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -75,13 +75,21 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) case 7: freq /= 2560; break; } ad1848->freq = freq; - ad1848->timer_latch = (int64_t)((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_count, ad1848->timer_latch); + else + timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); + } ad1848->enable = ((val & 0x41) == 0x01); - if (!ad1848->enable) + if (!ad1848->enable) { + timer_disable(&ad1848->timer_count); ad1848->out_l = ad1848->out_r = 0; + } break; case 12: @@ -101,7 +109,7 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) void ad1848_speed_changed(ad1848_t *ad1848) { - ad1848->timer_latch = (int64_t)((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) @@ -118,10 +126,10 @@ 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_count, ad1848->timer_latch); else - ad1848->timer_count = TIMER_USEC; - + timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); + ad1848_update(ad1848); if (ad1848->enable) @@ -183,8 +191,6 @@ void ad1848_init(ad1848_t *ad1848) { int c; double attenuation; - - ad1848->enable = 0; ad1848->status = 0xcc; ad1848->index = ad1848->trd = 0; @@ -219,5 +225,5 @@ void ad1848_init(ad1848_t *ad1848) ad1848_vols[c] = (int)(attenuation * 65536); } - timer_add(ad1848_poll, &ad1848->timer_count, &ad1848->enable, ad1848); + timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); } diff --git a/src/sound/snd_ad1848.h b/src/sound/snd_ad1848.h index 39dc60a5e..6ec719475 100644 --- a/src/sound/snd_ad1848.h +++ b/src/sound/snd_ad1848.h @@ -11,13 +11,14 @@ typedef struct ad1848_t int16_t out_l, out_r; - int64_t enable; + int enable; int irq, dma; - int64_t freq; + int freq; - int64_t timer_count, timer_latch; + pc_timer_t timer_count; + uint64_t timer_latch; int16_t buffer[SOUNDBUFLEN * 2]; int pos; diff --git a/src/sound/snd_adlib.c b/src/sound/snd_adlib.c index 0628ec932..c0417f69d 100644 --- a/src/sound/snd_adlib.c +++ b/src/sound/snd_adlib.c @@ -7,6 +7,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mca.h" #include "../device.h" #include "sound.h" @@ -16,13 +17,11 @@ #ifdef ENABLE_ADLIB_LOG int adlib_do_log = ENABLE_ADLIB_LOG; -#endif static void adlib_log(const char *fmt, ...) { -#ifdef ENABLE_ADLIB_LOG va_list ap; if (adlib_do_log) { @@ -30,8 +29,10 @@ adlib_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define adlib_log(fmt, ...) +#endif typedef struct adlib_t @@ -85,6 +86,14 @@ void adlib_mca_write(int port, uint8_t val, void *p) adlib->pos_regs[port & 7] = val; } +uint8_t adlib_mca_feedb(void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + return (adlib->pos_regs[2] & 1); +} + + void *adlib_init(const device_t *info) { adlib_t *adlib = malloc(sizeof(adlib_t)); @@ -102,7 +111,7 @@ void *adlib_mca_init(const device_t *info) adlib_t *adlib = adlib_init(info); 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, adlib_mca_feedb, adlib); adlib->pos_regs[0] = 0xd7; adlib->pos_regs[1] = 0x70; diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 178095702..06a4fcee5 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -5,14 +5,11 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../dma.h" #include "../pic.h" -#include "../pit.h" -#include "../mem.h" -#include "../rom.h" #include "../device.h" #include "../nvr.h" -#include "../timer.h" #include "sound.h" #include "filters.h" #include "snd_opl.h" @@ -40,7 +37,7 @@ typedef struct adgold_t int16_t adgold_mma_out[2]; int adgold_mma_intpos[2]; - int64_t adgold_mma_timer_count; + pc_timer_t adgold_mma_timer_count; struct { @@ -579,67 +576,64 @@ void adgold_timer_poll(void *p) { adgold_t *adgold = (adgold_t *)p; - while (adgold->adgold_mma_timer_count <= 0LL) - { - adgold->adgold_mma_timer_count += (int64_t)((double)TIMER_USEC * 1.88964); - if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ - { - adgold->adgold_mma.timer0_count--; - if (!adgold->adgold_mma.timer0_count) - { - adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; - adgold->adgold_mma_status |= 0x10; - adgold_update_irq_status(adgold); - } - } - if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ - { - adgold->adgold_mma.timerbase_count--; - if (!adgold->adgold_mma.timerbase_count) - { - adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; - if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ - { - adgold->adgold_mma.timer1_count--; - if (!adgold->adgold_mma.timer1_count) - { - adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; - adgold->adgold_mma_status |= 0x20; - adgold_update_irq_status(adgold); - } - } - if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ - { - adgold->adgold_mma.timer2_count--; - if (!adgold->adgold_mma.timer2_count) - { - adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; - adgold->adgold_mma_status |= 0x40; - adgold_update_irq_status(adgold); - } - } - } - } + timer_advance_u64(&adgold->adgold_mma_timer_count, (uint64_t)((double)TIMER_USEC * 1.88964)); + if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ + { + adgold->adgold_mma.timer0_count--; + if (!adgold->adgold_mma.timer0_count) + { + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; + adgold->adgold_mma_status |= 0x10; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ + { + adgold->adgold_mma.timerbase_count--; + if (!adgold->adgold_mma.timerbase_count) + { + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ + { + adgold->adgold_mma.timer1_count--; + if (!adgold->adgold_mma.timer1_count) + { + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; + adgold->adgold_mma_status |= 0x20; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ + { + adgold->adgold_mma.timer2_count--; + if (!adgold->adgold_mma.timer2_count) + { + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + adgold->adgold_mma_status |= 0x40; + adgold_update_irq_status(adgold); + } + } + } + } - if (adgold->adgold_mma_enable[0]) - { - adgold->adgold_mma.voice_count[0]--; - if (!adgold->adgold_mma.voice_count[0]) - { - adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; - adgold_mma_poll(adgold, 0); - } - } - if (adgold->adgold_mma_enable[1]) - { - adgold->adgold_mma.voice_count[1]--; - if (!adgold->adgold_mma.voice_count[1]) - { - adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; - adgold_mma_poll(adgold, 1); - } - } - } + if (adgold->adgold_mma_enable[0]) + { + adgold->adgold_mma.voice_count[0]--; + if (!adgold->adgold_mma.voice_count[0]) + { + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + adgold_mma_poll(adgold, 0); + } + } + if (adgold->adgold_mma_enable[1]) + { + adgold->adgold_mma.voice_count[1]--; + if (!adgold->adgold_mma.voice_count[1]) + { + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + adgold_mma_poll(adgold, 1); + } + } } static void adgold_get_buffer(int32_t *buffer, int len, void *p) @@ -805,7 +799,7 @@ void *adgold_init(const device_t *info) /*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_count, adgold_timer_poll, adgold, 1); sound_add_handler(adgold_get_buffer, adgold); diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 999c91d4e..f24a383d3 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -13,6 +13,8 @@ #include "../pci.h" #include "../timer.h" #include "sound.h" +#include "midi.h" +#include "snd_mpu401.h" #include "snd_audiopci.h" @@ -23,6 +25,8 @@ static float low_fir_es1371_coef[ES1371_NCoef]; typedef struct { + mpu_t mpu; + uint8_t pci_command, pci_serr; uint32_t base_addr; @@ -53,9 +57,11 @@ typedef struct { uint32_t addr, addr_latch; uint16_t count, size; - uint16_t samp_ct, curr_samp_ct; + uint16_t samp_ct; + int curr_samp_ct; - int64_t time, latch; + pc_timer_t timer; + uint64_t latch; uint32_t vf, ac; @@ -114,14 +120,21 @@ typedef struct { #define INT_DAC1_EN (1<<6) #define INT_DAC2_EN (1<<5) +#define INT_UART_EN (1<<3) #define SI_P2_INTR_EN (1<<9) #define SI_P1_INTR_EN (1<<8) #define INT_STATUS_INTR (1<<31) +#define INT_STATUS_UART (1<<3) #define INT_STATUS_DAC1 (1<<2) #define INT_STATUS_DAC2 (1<<1) +#define UART_CTRL_TXINTEN (1<<5) + +#define UART_STATUS_TXINT (1<<2) +#define UART_STATUS_TXRDY (1<<1) + #define FORMAT_MONO_8 0 #define FORMAT_STEREO_8 1 #define FORMAT_MONO_16 2 @@ -138,13 +151,11 @@ static void update_legacy(es1371_t *es1371); #ifdef ENABLE_AUDIOPCI_LOG int audiopci_do_log = ENABLE_AUDIOPCI_LOG; -#endif static void audiopci_log(const char *fmt, ...) { -#ifdef ENABLE_AUDIOPCI_LOG va_list ap; if (audiopci_do_log) { @@ -152,8 +163,10 @@ audiopci_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define audiopci_log(fmt, ...) +#endif static void es1371_update_irqs(es1371_t *es1371) @@ -162,8 +175,13 @@ static void es1371_update_irqs(es1371_t *es1371) 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)) + if ((es1371->int_status & INT_STATUS_DAC2) && (es1371->si_cr & SI_P2_INTR_EN)) { irq = 1; + } + /*MIDI input is unsupported for now*/ + if ((es1371->int_status & INT_STATUS_UART) && (es1371->uart_status & UART_STATUS_TXINT)) { + irq = 1; + } if (irq) es1371->int_status |= INT_STATUS_INTR; @@ -217,10 +235,10 @@ static uint8_t es1371_inb(uint16_t port, void *p) case 0x07: ret = (es1371->int_status >> 24) & 0xff; break; - - + case 0x09: - ret = es1371->uart_status; + ret = es1371->uart_status & 0xc7; + audiopci_log("ES1371 UART Status = %02x\n", es1371->uart_status); break; case 0x0c: @@ -251,7 +269,7 @@ static uint8_t es1371_inb(uint16_t port, void *p) audiopci_log("Bad es1371_inb: port=%04x\n", port); } -// audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret); + audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret); // output = 3; return ret; } @@ -338,31 +356,51 @@ static uint32_t es1371_inl(uint16_t port, void *p) ret |= CODEC_READY; break; - case 0x34: - switch (es1371->mem_page) - { + case 0x30: + switch (es1371->mem_page) { + case 0xe: case 0xf: + audiopci_log("ES1371 0x30 read UART FIFO: val = %02x\n", ret & 0xff); + break; + } + 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; + case 0xe: case 0xf: + audiopci_log("ES1371 0x34 read UART FIFO: val = %02x\n", ret & 0xff); + break; + default: audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); } break; + case 0x38: + switch (es1371->mem_page) { + case 0xe: case 0xf: + audiopci_log("ES1371 0x38 read UART FIFO: val = %02x\n", ret & 0xff); + break; + } + break; + case 0x3c: - switch (es1371->mem_page) - { + switch (es1371->mem_page) { case 0xc: ret = es1371->dac[1].size | (es1371->dac[1].count << 16); break; - + + case 0xe: case 0xf: + audiopci_log("ES1371 0x3c read UART FIFO: val = %02x\n", ret & 0xff); + break; + default: audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); } @@ -372,7 +410,7 @@ static uint32_t es1371_inl(uint16_t port, void *p) audiopci_log("Bad es1371_inl: port=%04x\n", port); } -// audiopci_log("es1371_inl: port=%04x ret=%08x %08x\n", port, ret, cpu_state.pc); + audiopci_log("es1371_inl: port=%04x ret=%08x\n", port, ret); return ret; } @@ -380,7 +418,7 @@ static void es1371_outb(uint16_t port, uint8_t val, void *p) { es1371_t *es1371 = (es1371_t *)p; -// audiopci_log("es1371_outb: port=%04x val=%02x %04x:%08x\n", port, val, cs, cpu_state.pc); + audiopci_log("es1371_outb: port=%04x val=%02x\n", port, val); switch (port & 0x3f) { case 0x00: @@ -410,8 +448,13 @@ static void es1371_outb(uint16_t port, uint8_t val, void *p) es1371->int_ctrl = (es1371->int_ctrl & 0x00ffffff) | (val << 24); break; + case 0x08: + midi_raw_out_byte(val); + break; + case 0x09: - es1371->uart_ctrl = val; + es1371->uart_ctrl = val & 0xe3; + audiopci_log("ES1371 UART Cntrl = %02x\n", es1371->uart_ctrl); break; case 0x0c: @@ -479,7 +522,7 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) { es1371_t *es1371 = (es1371_t *)p; -// audiopci_log("es1371_outl: port=%04x val=%08x %04x:%08x\n", port, val, CS, cpu_state.pc); + audiopci_log("es1371_outl: port=%04x val=%08x\n", port, val); switch (port & 0x3f) { case 0x04: @@ -591,6 +634,10 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) // audiopci_log("DAC1 addr %08x\n", val); break; + case 0xe: case 0xf: + audiopci_log("ES1371 0x30 write UART FIFO: val = %02x\n", val & 0xff); + break; + default: audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); } @@ -606,8 +653,6 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0xc: es1371->dac[0].size = val & 0xffff; es1371->dac[0].count = val >> 16; - if (es1371->dac[0].count) - es1371->dac[0].count -= 4; break; case 0xd: @@ -615,6 +660,10 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) es1371->adc.count = val >> 16; break; + case 0xe: case 0xf: + audiopci_log("ES1371 0x34 write UART FIFO: val = %02x\n", val & 0xff); + break; + default: audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); } @@ -633,6 +682,10 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0xd: break; + + case 0xe: case 0xf: + audiopci_log("ES1371 0x38 write UART FIFO: val = %02x\n", val & 0xff); + break; default: audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); @@ -649,6 +702,10 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0xc: es1371->dac[1].size = val & 0xffff; es1371->dac[1].count = val >> 16; + break; + + case 0xe: case 0xf: + audiopci_log("ES1371 0x3c write UART FIFO: val = %02x\n", val & 0xff); break; default: @@ -1105,12 +1162,35 @@ static void es1371_poll(void *p) { es1371_t *es1371 = (es1371_t *)p; - es1371->dac[1].time += es1371->dac[1].latch; - - es1371_update(es1371); - - if (es1371->int_ctrl & INT_DAC1_EN) - { + timer_advance_u64(&es1371->dac[1].timer, es1371->dac[1].latch); + + es1371_update(es1371); + + if (es1371->int_ctrl & INT_UART_EN) { + audiopci_log("UART INT Enabled\n"); + if (es1371->uart_ctrl & 0x80) { /*We currently don't implement MIDI Input.*/ + /*But if anything sets MIDI Input and Output together we'd have to take account + of the MIDI Output case, and disable IRQ's and RX bits when MIDI Input is enabled as well but not in the MIDI Output portion*/ + if (es1371->uart_ctrl & UART_CTRL_TXINTEN) + es1371->int_status |= INT_STATUS_UART; + else + es1371->int_status &= ~INT_STATUS_UART; + } else if (!(es1371->uart_ctrl & 0x80) && ((es1371->uart_ctrl & UART_CTRL_TXINTEN))) { /*Or enable the UART IRQ and the respective TX bits only when the MIDI Output is enabled*/ + es1371->int_status |= INT_STATUS_UART; + } + + if (es1371->uart_ctrl & 0x80) { + if (es1371->uart_ctrl & UART_CTRL_TXINTEN) + es1371->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); + else + es1371->uart_status &= ~(UART_STATUS_TXINT | UART_STATUS_TXRDY); + } else + es1371->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); + + es1371_update_irqs(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]; @@ -1120,7 +1200,6 @@ static void es1371_poll(void *p) 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; -// audiopci_log("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) @@ -1128,16 +1207,12 @@ static void es1371_poll(void *p) 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 == es1371->dac[0].samp_ct) + es1371->dac[0].curr_samp_ct--; + if (es1371->dac[0].curr_samp_ct < 0) { -// audiopci_log("DAC1 IRQ\n"); es1371->int_status |= INT_STATUS_DAC1; es1371_update_irqs(es1371); - } - if (es1371->dac[0].curr_samp_ct > es1371->dac[0].samp_ct) - { - es1371->dac[0].curr_samp_ct = 0; + es1371->dac[0].curr_samp_ct = es1371->dac[0].samp_ct; } } } @@ -1153,7 +1228,6 @@ static void es1371_poll(void *p) 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; -// audiopci_log("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) @@ -1161,16 +1235,13 @@ static void es1371_poll(void *p) 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 > es1371->dac[1].samp_ct) + es1371->dac[1].curr_samp_ct--; + if (es1371->dac[1].curr_samp_ct < 0) { -// es1371->dac[1].curr_samp_ct = 0; -// audiopci_log("DAC2 IRQ\n"); es1371->int_status |= INT_STATUS_DAC2; es1371_update_irqs(es1371); + es1371->dac[1].curr_samp_ct = es1371->dac[1].samp_ct; } - if (es1371->dac[1].curr_samp_ct > es1371->dac[1].samp_ct) - es1371->dac[1].curr_samp_ct = 0; } } } @@ -1232,8 +1303,8 @@ static void *es1371_init() sound_add_handler(es1371_get_buffer, es1371); es1371->card = pci_add_card(PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371); - - timer_add(es1371_poll, &es1371->dac[1].time, TIMER_ALWAYS_ENABLED, es1371); + + timer_add(&es1371->dac[1].timer, es1371_poll, es1371, 1); generate_es1371_filter(); @@ -1251,7 +1322,7 @@ static void es1371_speed_changed(void *p) { es1371_t *es1371 = (es1371_t *)p; - es1371->dac[1].latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); + 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) diff --git a/src/sound/snd_dbopl.cc b/src/sound/snd_dbopl.cc deleted file mode 100644 index 78840f4a6..000000000 --- a/src/sound/snd_dbopl.cc +++ /dev/null @@ -1,187 +0,0 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ -#include "dbopl.h" -#include "nukedopl.h" -#include "sound.h" -#include "snd_dbopl.h" - - -int opl_type = 0; - - -static struct -{ - DBOPL::Chip chip; - opl3_chip opl3chip; - int addr; - int timer[2]; - uint8_t timer_ctrl; - uint8_t status_mask; - uint8_t status; - int is_opl3; - - void (*timer_callback)(void *param, int timer, int64_t period); - void *timer_param; -} opl[2]; - -enum -{ - STATUS_TIMER_1 = 0x40, - STATUS_TIMER_2 = 0x20, - STATUS_TIMER_ALL = 0x80 -}; - -enum -{ - CTRL_IRQ_RESET = 0x80, - CTRL_TIMER1_MASK = 0x40, - CTRL_TIMER2_MASK = 0x20, - CTRL_TIMER2_CTRL = 0x02, - CTRL_TIMER1_CTRL = 0x01 -}; - -void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3) -{ - opl[nr].timer_callback = timer_callback; - opl[nr].timer_param = timer_param; - opl[nr].is_opl3 = is_opl3; - - if (!opl_type) - { - DBOPL::InitTables(); - opl[nr].chip.Setup(48000, is_opl3); - } - else - { - opl[nr].opl3chip.newm = 0; - OPL3_Reset(&opl[nr].opl3chip, 48000); - } -} - -void opl_status_update(int nr) -{ - if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask) - opl[nr].status |= STATUS_TIMER_ALL; - else - opl[nr].status &= ~STATUS_TIMER_ALL; -} - -void opl_timer_over(int nr, int timer) -{ - if (!timer) - { - opl[nr].status |= STATUS_TIMER_1; - opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); - } - else - { - opl[nr].status |= STATUS_TIMER_2; - opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); - } - - opl_status_update(nr); -} - -void opl_write(int nr, uint16_t addr, uint8_t val) -{ - if (!(addr & 1)) - { - if (!opl_type) - opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & 0x1ff; - else - opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; - if (!opl[nr].is_opl3) - opl[nr].addr &= 0xff; - } - else - { - if (!opl_type) - opl[nr].chip.WriteReg(opl[nr].addr, val); - else { - OPL3_WriteRegBuffered(&opl[nr].opl3chip, (uint16_t) opl[nr].addr, val); - if (opl[nr].addr == 0x105) - opl[nr].opl3chip.newm = opl[nr].addr & 0x01; - } - - switch (opl[nr].addr) - { - case 0x02: /*Timer 1*/ - opl[nr].timer[0] = 256 - val; - break; - case 0x03: /*Timer 2*/ - opl[nr].timer[1] = 256 - val; - break; - case 0x04: /*Timer control*/ - if (val & CTRL_IRQ_RESET) /*IRQ reset*/ - { - opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); - opl_status_update(nr); - return; - } - if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL) - { - if (val & CTRL_TIMER1_CTRL) - opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); - else - opl[nr].timer_callback(opl[nr].timer_param, 0, 0); - } - if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL) - { - if (val & CTRL_TIMER2_CTRL) - opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); - else - opl[nr].timer_callback(opl[nr].timer_param, 1, 0); - } - opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; - opl[nr].timer_ctrl = val; - break; - } - } - -} - -uint8_t opl_read(int nr, uint16_t addr) -{ - if (!(addr & 1)) - { - return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06); - } - return opl[nr].is_opl3 ? 0 : 0xff; -} - -void opl2_update(int nr, int16_t *buffer, int samples) -{ - int c; - Bit32s buffer_32[SOUNDBUFLEN]; - - if (opl_type) - { - OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); - } - else - { - opl[nr].chip.GenerateBlock2(samples, buffer_32); - - for (c = 0; c < samples; c++) - buffer[c*2] = (int16_t)buffer_32[c]; - } -} - -void opl3_update(int nr, int16_t *buffer, int samples) -{ - int c; - Bit32s buffer_32[SOUNDBUFLEN*2]; - - if (opl_type) - { - 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/snd_emu8k.c b/src/sound/snd_emu8k.c index d273e4953..f5d19daac 100644 --- a/src/sound/snd_emu8k.c +++ b/src/sound/snd_emu8k.c @@ -295,13 +295,11 @@ uint32_t rep_count_w = 0; #ifdef ENABLE_EMU8K_LOG int emu8k_do_log = ENABLE_EMU8K_LOG; -#endif static void emu8k_log(const char *fmt, ...) { -#ifdef ENABLE_EMU8K_LOG va_list ap; if (emu8k_do_log) { @@ -309,8 +307,10 @@ emu8k_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define emu8k_log(fmt, ...) +#endif static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr) diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 3bd367e63..1f8fcfd3b 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -13,8 +13,39 @@ #include "../timer.h" #include "../device.h" #include "sound.h" +#include "midi.h" #include "snd_gus.h" +enum +{ + MIDI_INT_RECEIVE = 0x01, + MIDI_INT_TRANSMIT = 0x02, + MIDI_INT_MASTER = 0x80 +}; + +enum +{ + MIDI_CTRL_TRANSMIT_MASK = 0x60, + MIDI_CTRL_TRANSMIT = 0x20, + MIDI_CTRL_RECEIVE = 0x80 +}; + +enum +{ + GUS_INT_MIDI_TRANSMIT = 0x01, + GUS_INT_MIDI_RECEIVE = 0x02 +}; + +enum +{ + GUS_TIMER_CTRL_AUTO = 0x01 +}; + +enum +{ + GUS_CLASSIC = 0, + GUS_MAX = 1, +}; typedef struct gus_t { @@ -47,15 +78,18 @@ typedef struct gus_t int16_t buffer[2][SOUNDBUFLEN]; int pos; - int64_t samp_timer, samp_latch; + pc_timer_t samp_timer; + uint64_t samp_latch; uint8_t *ram; + uint32_t gus_end_ram; int irqnext; - int64_t timer_1, timer_2; + pc_timer_t timer_1, timer_2; int irq, dma, irq_midi; + uint16_t base; int latch_enable; uint8_t sb_2xa, sb_2xc, sb_2xe; @@ -67,9 +101,9 @@ typedef struct gus_t uint8_t ad_status, ad_data; uint8_t ad_timer_ctrl; - uint8_t midi_ctrl, midi_status; - uint8_t midi_data; - int midi_loopback; + uint8_t midi_ctrl, midi_status, midi_queue[64], midi_data; + int midi_r, midi_w; + int uart_in, uart_out, sysex; uint8_t gp1, gp2; uint16_t gp1_addr, gp2_addr; @@ -77,8 +111,8 @@ typedef struct gus_t uint8_t usrr; } gus_t; -static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; -static int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_gf1_irqs[8] = {0, 2, 5, 3, 7, 11, 12, 15}; +static int gus_midi_irqs[8] = {0, 2, 5, 3, 7, 11, 12, 15}; static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; int gusfreqs[]= @@ -101,48 +135,26 @@ void pollgusirqs(gus_t *gus) gus->irqstatus2=0x60|c; if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; gus->irqstatus|=0x20; - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); return; } if (gus->rampirqs[c]) { gus->irqstatus2=0xA0|c; gus->irqstatus|=0x40; - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); return; } } gus->irqstatus2=0xE0; - if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); + if (!gus->irqstatus) { + if (gus->irq != 0) + picintc(1 << gus->irq); + } } -enum -{ - MIDI_INT_RECEIVE = 0x01, - MIDI_INT_TRANSMIT = 0x02, - MIDI_INT_MASTER = 0x80 -}; - -enum -{ - MIDI_CTRL_TRANSMIT_MASK = 0x60, - MIDI_CTRL_TRANSMIT = 0x20, - MIDI_CTRL_RECEIVE = 0x80 -}; - -enum -{ - GUS_INT_MIDI_TRANSMIT = 0x01, - GUS_INT_MIDI_RECEIVE = 0x02 -}; - -enum -{ - GUS_TIMER_CTRL_AUTO = 0x01 -}; - void gus_midi_update_int_status(gus_t *gus) { gus->midi_status &= ~MIDI_INT_MASTER; @@ -156,57 +168,63 @@ void gus_midi_update_int_status(gus_t *gus) if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) { - gus->midi_status |= MIDI_INT_MASTER; - gus->irqstatus |= GUS_INT_MIDI_RECEIVE; + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_RECEIVE; } else gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; - if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) + if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != 0)) { picint(1 << gus->irq_midi); } } - + void writegus(uint16_t addr, uint8_t val, void *p) { gus_t *gus = (gus_t *)p; int c, d; int old; - if (gus->latch_enable && addr != 0x24b) - gus->latch_enable = 0; - switch (addr) + uint16_t port; + + if ((addr == 0x388) || (addr == 0x389)) + port = addr; + else + port = addr & 0xf0f; + + switch (port) { - case 0x340: /*MIDI control*/ + case 0x300: /*MIDI control*/ old = gus->midi_ctrl; gus->midi_ctrl = val; - - if ((val & 3) == 3) - gus->midi_status = 0; - else if ((old & 3) == 3) - { - gus->midi_status |= MIDI_INT_TRANSMIT; - } + gus->uart_out = 1; + + if ((val & 3) == 3) { /*Master reset*/ + gus->uart_in = 0; + gus->midi_status = 0; + gus->midi_r = 0; + gus->midi_w = 0; + } else if ((old & 3) == 3) { + gus->midi_status |= MIDI_INT_TRANSMIT; + } else if (gus->midi_ctrl & MIDI_CTRL_RECEIVE) { + gus->uart_in = 1; + } gus_midi_update_int_status(gus); break; - - case 0x341: /*MIDI data*/ - if (gus->midi_loopback) - { - gus->midi_status |= MIDI_INT_RECEIVE; - gus->midi_data = val; + case 0x301: /*MIDI data*/ + gus->midi_data = val; + if (gus->uart_out) { + midi_raw_out_byte(val); } - else - gus->midi_status |= MIDI_INT_TRANSMIT; + if (gus->latch_enable & 0x20) { + gus->midi_status |= MIDI_INT_RECEIVE; + } else + gus->midi_status |= MIDI_INT_TRANSMIT; break; - - case 0x342: /*Voice select*/ - gus->voice=val&31; - break; - case 0x343: /*Global select*/ + case 0x303: /*Global select*/ gus->global=val; break; - case 0x344: /*Global low*/ + case 0x304: /*Global low*/ switch (gus->global) { case 0: /*Voice control*/ @@ -230,11 +248,11 @@ void writegus(uint16_t addr, uint8_t val, void *p) gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val; break; - case 0x6: /*Ramp frequency*/ + case 6: /*Ramp frequency*/ gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); break; - case 0x9: /*Current volume*/ + case 9: /*Current volume*/ gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); break; @@ -258,14 +276,10 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); break; } break; - case 0x345: /*Global high*/ + case 0x305: /*Global high*/ switch (gus->global) { case 0: /*Voice control*/ - if (!(val&1) && gus->ctrl[gus->voice]&1) - { - } - gus->ctrl[gus->voice] = val & 0x7f; old = gus->waveirqs[gus->voice]; @@ -293,16 +307,16 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8); break; - case 0x6: /*Ramp frequency*/ + case 6: /*Ramp frequency*/ gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); break; - case 0x7: /*Ramp start*/ + case 7: /*Ramp start*/ gus->rstart[gus->voice] = val << 14; break; - case 0x8: /*Ramp end*/ + case 8: /*Ramp end*/ gus->rend[gus->voice] = val << 14; break; - case 0x9: /*Current volume*/ + case 9: /*Current volume*/ gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); break; @@ -332,9 +346,9 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); if (gus->voices<14) gus->voices=14; gus->global=val; 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*/ @@ -448,11 +462,12 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); break; } break; - case 0x347: /*DRAM access*/ - gus->ram[gus->addr]=val; + case 0x307: /*DRAM access*/ gus->addr&=0xFFFFF; + if (gus->addr < gus->gus_end_ram) + gus->ram[gus->addr]=val; break; - case 0x248: case 0x388: + case 0x208: case 0x388: gus->adcommand = val; break; @@ -465,7 +480,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); { if (gus->sb_nmi) nmi = 1; - else if (gus->irq != -1) + else picint(1 << gus->irq); } } @@ -492,34 +507,76 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); } break; - case 0x240: - gus->midi_loopback = val & 0x20; - gus->latch_enable = (val & 0x40) ? 2 : 1; + case 0x200: + gus->latch_enable = val; break; - case 0x24b: + case 0x20b: switch (gus->reg_ctrl & 0x07) { case 0: - if (gus->latch_enable == 1) - gus->dma = gus_dmas[val & 7]; - if (gus->latch_enable == 2) - { - gus->irq = gus_irqs[val & 7]; - - if (val & 0x40) - { - if (gus->irq == -1) - gus->irq = gus->irq_midi = gus_irqs[(val >> 3) & 7]; - else - gus->irq_midi = gus->irq; - } - else - gus->irq_midi = gus_irqs_midi[(val >> 3) & 7]; - - gus->sb_nmi = val & 0x80; - } - gus->latch_enable = 0; + if (gus->latch_enable & 0x40) { + // GUS SDK: IRQ Control Register + // Channel 1 GF1 IRQ selector (bits 2-0) + // 0=reserved, do not use + // 1=IRQ2 + // 2=IRQ5 + // 3=IRQ3 + // 4=IRQ7 + // 5=IRQ11 + // 6=IRQ12 + // 7=IRQ15 + // Channel 2 MIDI IRQ selector (bits 5-3) + // 0=no interrupt + // 1=IRQ2 + // 2=IRQ5 + // 3=IRQ3 + // 4=IRQ7 + // 5=IRQ11 + // 6=IRQ12 + // 7=IRQ15 + // Combine both IRQs using channel 1 (bit 6) + // Reserved (bit 7) + // + // "If both channels are sharing an IRQ, channel 2's IRQ must be set to 0 and turn on bit 6. A + // bus conflict will occur if both latches are programmed with the same IRQ #." + if ((val & 7) != 0) + gus->irq = gus_gf1_irqs[val & 7]; + + if (val & 0x40) // "Combine both IRQs" + gus->irq_midi = gus->irq; + else + gus->irq_midi = gus_midi_irqs[(val >> 3) & 7]; + + gus->sb_nmi = val & 0x80; + } else { + // GUS SDK: DMA Control Register + // Channel 1 (bits 2-0) + // 0=NO DMA + // 1=DMA1 + // 2=DMA3 + // 3=DMA5 + // 4=DMA6 + // 5=DMA7 + // 6=? + // 7=? + // Channel 2 (bits 5-3) + // 0=NO DMA + // 1=DMA1 + // 2=DMA3 + // 3=DMA5 + // 4=DMA6 + // 5=DMA7 + // 6=? + // 7=? + // Combine both DMA channels using channel 1 (bit 6) + // Reserved (bit 7) + // + // "If both channels are sharing an DMA, channel 2's DMA must be set to 0 and turn on bit 6. A + // bus conflict will occur if both latches are programmed with the same DMA #." + if (gus_dmas[val & 7] != -1) + gus->dma = gus_dmas[val & 7]; + } break; case 1: gus->gp1 = val; @@ -541,67 +598,97 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); } break; - case 0x246: - gus->ad_status |= 0x08; - if (gus->sb_ctrl & 0x20) - { + case 0x206: + if (gus->sb_ctrl & 0x20) { + gus->ad_status |= 0x08; if (gus->sb_nmi) - nmi = 1; - else if (gus->irq != -1) - picint(1 << gus->irq); + nmi = 1; + else if (gus->irq != 0) + picint(1 << gus->irq); } break; - case 0x24a: + case 0x20a: gus->sb_2xa = val; break; - case 0x24c: + case 0x20c: gus->ad_status |= 0x10; if (gus->sb_ctrl & 0x20) { if (gus->sb_nmi) nmi = 1; - else if (gus->irq != -1) + else if (gus->irq != 0) picint(1 << gus->irq); } - case 0x24d: + case 0x20d: gus->sb_2xc = val; break; - case 0x24e: + case 0x20e: gus->sb_2xe = val; break; - case 0x24f: + case 0x20f: gus->reg_ctrl = val; break; } } + uint8_t readgus(uint16_t addr, void *p) { gus_t *gus = (gus_t *)p; uint8_t val = 0xff; - switch (addr) + uint16_t port; + + if ((addr == 0x388) || (addr == 0x389)) + port = addr; + else + port = addr & 0xf0f; + + switch (port) { - case 0x340: /*MIDI status*/ - val = gus->midi_status; + case 0x300: /*MIDI status*/ + val = gus->midi_status; break; - case 0x341: /*MIDI data*/ - val = gus->midi_data; - gus->midi_status &= ~MIDI_INT_RECEIVE; - gus_midi_update_int_status(gus); + case 0x301: /*MIDI data*/ + val = 0; + if (gus->uart_in) { + if ((gus->midi_data == 0xaa) && (gus->midi_ctrl & MIDI_CTRL_RECEIVE)) /*Handle master reset*/ + val = gus->midi_data; + else { + val = gus->midi_queue[gus->midi_r]; + if (gus->midi_r != gus->midi_w) { + gus->midi_r++; + gus->midi_r &= 63; + } + } + gus->midi_status &= ~MIDI_INT_RECEIVE; + gus_midi_update_int_status(gus); + } break; - case 0x240: return 0; - case 0x246: /*IRQ status*/ + case 0x200: + val = 0xff; + break; + + case 0x206: /*IRQ status*/ val = gus->irqstatus & ~0x10; if (gus->ad_status & 0x19) val |= 0x10; - return val; + break; - case 0x24F: return 0; - case 0x342: return gus->voice; - case 0x343: return gus->global; - case 0x344: /*Global low*/ + case 0x20F: + val = 0; + break; + + case 0x302: + val = gus->voice; + break; + + case 0x303: + val = gus->global; + break; + + case 0x304: /*Global low*/ switch (gus->global) { case 0x82: /*Start addr high*/ @@ -631,7 +718,7 @@ uint8_t readgus(uint16_t addr, void *p) break; } break; - case 0x345: /*Global high*/ + case 0x305: /*Global high*/ switch (gus->global) { case 0x80: /*Voice control*/ @@ -680,16 +767,20 @@ uint8_t readgus(uint16_t addr, void *p) break; } break; - case 0x346: return 0xff; - case 0x347: /*DRAM access*/ + case 0x306: case 0x706: /*Revision level*/ + val = 0xff; + break; + case 0x307: /*DRAM access*/ val=gus->ram[gus->addr]; gus->addr&=0xFFFFF; - return val; - case 0x349: return 0; - case 0x746: /*Revision level*/ - return 0xff; /*Pre 3.7 - no mixer*/ + if (gus->addr < gus->gus_end_ram) + val = gus->ram[gus->addr]; + else + val = 0; + break; + case 0x309: return 0; - case 0x24b: + case 0x20b: switch (gus->reg_ctrl & 0x07) { case 1: @@ -707,15 +798,15 @@ uint8_t readgus(uint16_t addr, void *p) } break; - case 0x24c: + case 0x20c: val = gus->sb_2xc; if (gus->reg_ctrl & 0x20) gus->sb_2xc &= 0x80; break; - case 0x24e: + case 0x20e: return gus->sb_2xe; - case 0x248: case 0x388: + case 0x208: case 0x388: if (gus->tctrl & GUS_TIMER_CTRL_AUTO) val = gus->sb_2xa; else @@ -726,14 +817,14 @@ uint8_t readgus(uint16_t addr, void *p) } break; - case 0x249: + case 0x209: gus->ad_status &= ~0x01; nmi = 0; case 0x389: val = gus->ad_data; break; - case 0x24A: + case 0x20A: val = gus->adcommand; break; @@ -745,7 +836,7 @@ void gus_poll_timer_1(void *p) { gus_t *gus = (gus_t *)p; - gus->timer_1 += (TIMER_USEC * 80LL); + timer_advance_u64(&gus->timer_1, (uint64_t)(TIMER_USEC * 80)); if (gus->t1on) { gus->t1++; @@ -755,9 +846,9 @@ 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; + if (gus->irq != 0) + picint(1 << gus->irq); + gus->ad_status |= 0x04; gus->irqstatus |= 0x04; } } @@ -766,17 +857,18 @@ void gus_poll_timer_1(void *p) { gus->irqnext=0; gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); } - gus_midi_update_int_status(gus); + + gus_midi_update_int_status(gus); } void gus_poll_timer_2(void *p) { gus_t *gus = (gus_t *)p; - gus->timer_2 += (TIMER_USEC * 320LL); + timer_advance_u64(&gus->timer_2, (uint64_t)(TIMER_USEC * 320)); if (gus->t2on) { gus->t2++; @@ -786,8 +878,8 @@ void gus_poll_timer_2(void *p) gus->ad_status |= 0x20; if (gus->tctrl&8) { - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); gus->ad_status |= 0x02; gus->irqstatus |= 0x08; } @@ -797,8 +889,8 @@ void gus_poll_timer_2(void *p) { gus->irqnext=0; gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); } } @@ -832,7 +924,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; @@ -997,16 +1089,57 @@ static void gus_get_buffer(int32_t *buffer, int len, void *p) gus->pos = 0; } +static void gus_input_msg(void *p, uint8_t *msg) +{ + gus_t *gus = (gus_t *)p; + uint8_t i; + + if (gus->sysex) + return; + + if (gus->uart_in) { + gus->midi_status |= MIDI_INT_RECEIVE; + + for (i=0;imidi_queue[gus->midi_w++] = msg[i]; + gus->midi_w &= 63; + } + + gus_midi_update_int_status(gus); + } +} + +static int gus_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) +{ + gus_t *gus = (gus_t *)p; + uint32_t i; + + if (abort) { + gus->sysex = 0; + return 0; + } + gus->sysex = 1; + for (i=0;imidi_r == gus->midi_w) + return (len-i); + gus->midi_queue[gus->midi_w++] = buffer[i]; + gus->midi_w &= 63; + } + gus->sysex = 0; + return 0; +} void *gus_init(const device_t *info) { int c; double out = 1.0; + uint8_t gus_ram = device_get_config_int("gus_ram"); gus_t *gus = malloc(sizeof(gus_t)); memset(gus, 0, sizeof(gus_t)); - gus->ram = malloc(1 << 20); - memset(gus->ram, 0, 1 << 20); + gus->gus_end_ram = 1 << (18 + gus_ram); + gus->ram = (uint8_t *)malloc(gus->gus_end_ram); + memset(gus->ram, 0x00, (gus->gus_end_ram)); for (c=0;c<32;c++) { @@ -1022,20 +1155,28 @@ void *gus_init(const device_t *info) gus->voices=14; - gus->samp_timer = gus->samp_latch = (int64_t)(TIMER_USEC * (1000000.0 / 44100.0)); + gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); gus->t1l = gus->t2l = 0xff; + + gus->uart_out = 1; + + gus->base = device_get_config_hex16("base"); - io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0100+gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0506+gus->base, 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); + input_msg = gus_input_msg; + input_sysex = gus_input_sysex; + midi_in_p = gus; + return gus; } @@ -1052,16 +1193,81 @@ 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 const device_config_t gus_config[] = { + { + "type", "GUS type", CONFIG_SELECTION, "", 0, + { + { + "Classic", GUS_CLASSIC + }, +#if 0 + { + "MAX", GUS_MAX + }, +#endif + { + NULL + } + }, + }, + { + "base", "Address", CONFIG_HEX16, "", 0x220, + { + { + "210H", 0x210 + }, + { + "220H", 0x220 + }, + { + "230H", 0x230 + }, + { + "240H", 0x240 + }, + { + "250H", 0x250 + }, + { + "260H", 0x260 + }, + }, + }, + { + "gus_ram", "Onboard RAM", CONFIG_SELECTION, "", 0, + { + { + "256 KB", 0 + }, + { + "512 KB", 1 + }, + { + "1 MB", 2 + }, + { + NULL + } + } + }, + { + "", "", -1 + } +}; + const device_t gus_device = { "Gravis UltraSound", - 0, 0, - gus_init, gus_close, NULL, NULL, - gus_speed_changed, NULL, - NULL + DEVICE_ISA, + 0, + gus_init, gus_close, NULL, + NULL, + gus_speed_changed, + NULL, + gus_config }; diff --git a/src/sound/snd_lpt_dac.c b/src/sound/snd_lpt_dac.c index 0e271ea2d..f368e3a21 100644 --- a/src/sound/snd_lpt_dac.c +++ b/src/sound/snd_lpt_dac.c @@ -14,6 +14,8 @@ typedef struct lpt_dac_t { + void *lpt; + uint8_t dac_val_l, dac_val_r; int is_stereo; @@ -36,8 +38,6 @@ static void dac_update(lpt_dac_t *lpt_dac) static void dac_write_data(uint8_t val, void *p) { lpt_dac_t *lpt_dac = (lpt_dac_t *)p; - - timer_clock(); if (lpt_dac->is_stereo) { @@ -80,18 +80,20 @@ static void dac_get_buffer(int32_t *buffer, int len, void *p) lpt_dac->pos = 0; } -static void *dac_init() +static void *dac_init(void *lpt) { lpt_dac_t *lpt_dac = malloc(sizeof(lpt_dac_t)); memset(lpt_dac, 0, sizeof(lpt_dac_t)); + lpt_dac->lpt = lpt; + sound_add_handler(dac_get_buffer, lpt_dac); return lpt_dac; } -static void *dac_stereo_init() +static void *dac_stereo_init(void *lpt) { - lpt_dac_t *lpt_dac = dac_init(); + lpt_dac_t *lpt_dac = dac_init(lpt); lpt_dac->is_stereo = 1; @@ -111,7 +113,9 @@ const lpt_device_t lpt_dac_device = dac_close, dac_write_data, dac_write_ctrl, - dac_read_status + NULL, + dac_read_status, + NULL }; const lpt_device_t lpt_dac_stereo_device = { @@ -120,5 +124,7 @@ const lpt_device_t lpt_dac_stereo_device = dac_close, dac_write_data, dac_write_ctrl, - dac_read_status + NULL, + dac_read_status, + NULL }; diff --git a/src/sound/snd_lpt_dss.c b/src/sound/snd_lpt_dss.c index bacd1e706..72b5574af 100644 --- a/src/sound/snd_lpt_dss.c +++ b/src/sound/snd_lpt_dss.c @@ -14,12 +14,15 @@ typedef struct dss_t { + void *lpt; + uint8_t fifo[16]; int read_idx, write_idx; - uint8_t dac_val; + uint8_t dac_val, + status; - int64_t time; + pc_timer_t timer; int16_t buffer[SOUNDBUFLEN]; int pos; @@ -32,16 +35,29 @@ static void dss_update(dss_t *dss) } +static void dss_update_status(dss_t *dss) +{ + uint8_t old = dss->status; + + dss->status &= ~0x40; + + if ((dss->write_idx - dss->read_idx) >= 16) + dss->status |= 0x40; + + if ((old & 0x40) && !(dss->status & 0x40)) + lpt_irq(dss->lpt, 1); +} + + static void dss_write_data(uint8_t val, void *p) { dss_t *dss = (dss_t *)p; - timer_clock(); - if ((dss->write_idx - dss->read_idx) < 16) { dss->fifo[dss->write_idx & 15] = val; dss->write_idx++; + dss_update_status(dss); } } @@ -53,9 +69,7 @@ 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; + return dss->status; } @@ -63,12 +77,15 @@ static void dss_get_buffer(int32_t *buffer, int len, void *p) { dss_t *dss = (dss_t *)p; int c; + int16_t val; + float fval; dss_update(dss); for (c = 0; c < len*2; c += 2) { - int16_t val = (int16_t)dss_iir((float)dss->buffer[c >> 1]); + fval = dss_iir((float)dss->buffer[c >> 1]); + val = (float) fval; buffer[c] += val; buffer[c+1] += val; @@ -87,19 +104,22 @@ static void dss_callback(void *p) { dss->dac_val = dss->fifo[dss->read_idx & 15]; dss->read_idx++; + dss_update_status(dss); } - - dss->time += (int64_t) (TIMER_USEC * (1000000.0 / 7000.0)); + + timer_advance_u64(&dss->timer, (TIMER_USEC * (1000000.0 / 7000.0))); } -static void *dss_init() +static void *dss_init(void *lpt) { dss_t *dss = malloc(sizeof(dss_t)); memset(dss, 0, sizeof(dss_t)); + dss->lpt = lpt; + sound_add_handler(dss_get_buffer, dss); - timer_add(dss_callback, &dss->time, TIMER_ALWAYS_ENABLED, dss); - + timer_add(&dss->timer, dss_callback, dss, 1); + return dss; } static void dss_close(void *p) @@ -116,5 +136,7 @@ const lpt_device_t dss_device = dss_close, dss_write_data, dss_write_ctrl, - dss_read_status + NULL, + dss_read_status, + NULL }; diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index 4bc619d90..1ffc067f1 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -8,7 +8,7 @@ * * Roland MPU-401 emulation. * - * Version: @(#)snd_mpu401.c 1.0.10 2018/04/29 + * Version: @(#)snd_mpu401.c 1.0.18 2018/10/18 * * Authors: Sarah Walker, * DOSBox Team, @@ -29,13 +29,18 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../device.h" +#include "../plat.h" #include "../io.h" +#include "../machine/machine.h" +#include "../mca.h" #include "../pic.h" #include "../timer.h" #include "sound.h" #include "snd_mpu401.h" #include "midi.h" +static uint32_t MPUClockBase[8] = {48,72,96,120,144,168,192}; +static uint8_t cth_data[16] = {0,0,0,0,1,0,0,0,1,0,1,0,1,1,1,0}; enum { STATUS_OUTPUT_NOT_READY = 0x40, @@ -45,24 +50,20 @@ enum { int mpu401_standalone_enable = 0; -static int64_t mpu401_event_callback = 0LL; -static int64_t mpu401_eoi_callback = 0LL; -static int64_t mpu401_reset_callback = 0LL; - - static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val); +static void MPU401_IntelligentOut(mpu_t *mpu, uint8_t track); +static void MPU401_EOIHandler(void *priv); static void MPU401_EOIHandlerDispatch(void *p); +static void MPU401_NotesOff(mpu_t *mpu, int i); #ifdef ENABLE_MPU401_LOG int mpu401_do_log = ENABLE_MPU401_LOG; -#endif static void mpu401_log(const char *fmt, ...) { -#ifdef ENABLE_MPU401_LOG va_list ap; if (mpu401_do_log) { @@ -70,43 +71,148 @@ mpu401_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define mpu401_log(fmt, ...) #endif + + +static void +MPU401_ReCalcClock(mpu_t *mpu) +{ + int32_t maxtempo = 240, mintempo = 16; + int32_t freq; + + if (mpu->clock.timebase >= 168) + maxtempo = 179; + if (mpu->clock.timebase == 144) + maxtempo = 208; + if (mpu->clock.timebase >= 120) + maxtempo = 8; + + mpu->clock.freq = ((uint32_t)(mpu->clock.tempo * 2 * mpu->clock.tempo_rel)) >> 6; + mpu->clock.freq = mpu->clock.timebase * (mpu->clock.freq < (mintempo * 2) ? mintempo : + ((mpu->clock.freq / 2) < maxtempo ? (mpu->clock.freq / 2) : maxtempo)); + + if (mpu->state.sync_in) { + freq = (int32_t)((float)(mpu->clock.freq) * mpu->clock.freq_mod); + if ((freq > (mpu->clock.timebase * mintempo)) && (freq < (mpu->clock.timebase * maxtempo))) + mpu->clock.freq = freq; + } } static void -QueueByte(mpu_t *mpu, uint8_t data) +MPU401_StartClock(mpu_t *mpu) { - if (mpu->state.block_ack) { - mpu->state.block_ack=0; + if (mpu->clock.active) + return; + if (!(mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON))) + return; + + mpu->clock.active = 1; + timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); +} + + +static void +MPU401_StopClock(mpu_t *mpu) +{ + if (mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON)) + return; + mpu->clock.active = 0; + timer_disable(&mpu->mpu401_event_callback); +} + + +static void +MPU401_RunClock(mpu_t *mpu) +{ + if (!mpu->clock.active) { + timer_disable(&mpu->mpu401_event_callback); return; } - - if (mpu->queue_used == 0 && mpu->intelligent) { - mpu->state.irq_pending=1; + timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT/mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); +} + + +static void +MPU401_QueueByte(mpu_t *mpu, uint8_t data) +{ + if (mpu->state.block_ack) { + mpu->state.block_ack = 0; + return; + } + + if (mpu->queue_used == 0) { + mpu->state.irq_pending = 1; picint(1 << mpu->irq); } + if (mpu->queue_used < MPU401_QUEUE) { int pos = mpu->queue_used+mpu->queue_pos; if (mpu->queue_pos >= MPU401_QUEUE) mpu->queue_pos -= MPU401_QUEUE; - if (pos>=MPU401_QUEUE) pos-=MPU401_QUEUE; mpu->queue_used++; - mpu->queue[pos]=data; - } else - mpu401_log("MPU401:Data queue full\n"); + mpu->queue[pos] = data; + } } static void -ClrQueue(mpu_t *mpu) +MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) { - mpu->queue_used=0; - mpu->queue_pos=0; + uint32_t cnt = 0; + int pos; + + while (cnt < len) { + if (mpu->rec_queue_used < MPU401_INPUT_QUEUE) { + pos = mpu->rec_queue_used + mpu->rec_queue_pos; + if (pos >= MPU401_INPUT_QUEUE) + pos -= MPU401_INPUT_QUEUE; + mpu->rec_queue[pos] = buf[cnt]; + mpu->rec_queue_used++; + if ((!mpu->state.sysex_in_finished) && (buf[cnt] == MSG_EOX)) { + /* finish sysex */ + mpu->state.sysex_in_finished = 1; + break; + } + cnt++; + } + } + + if (mpu->queue_used == 0) { + if (mpu->state.rec_copy || mpu->state.irq_pending) { + if (mpu->state.irq_pending) { + picintc(1 << mpu->irq); + mpu->state.irq_pending = 0; + } + return; + } + mpu->state.rec_copy = 1; + if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE) + mpu->rec_queue_pos -= MPU401_INPUT_QUEUE; + MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); + mpu->rec_queue_used--; + mpu->rec_queue_pos++; + } +} + + +static void +MPU401_ClrQueue(mpu_t *mpu) +{ + mpu->queue_used = 0; + mpu->queue_pos = 0; + mpu->rec_queue_used = 0; + mpu->rec_queue_pos = 0; + mpu->state.sysex_in_finished = 1; + mpu->state.irq_pending = 0; } @@ -115,9 +221,14 @@ MPU401_Reset(mpu_t *mpu) { uint8_t i; - picintc(1 << mpu->irq); - - mpu->mode = (mpu->intelligent ? M_INTELLIGENT : M_UART); + if (mpu->mode == M_INTELLIGENT) { + picintc(1 << mpu->irq); + mpu->state.irq_pending = 0; + } + + mpu->mode = M_INTELLIGENT; + mpu->midi_thru = 0; + mpu->state.rec = M_RECOFF; mpu->state.eoi_scheduled = 0; mpu->state.wsd = 0; mpu->state.wsm = 0; @@ -126,31 +237,67 @@ MPU401_Reset(mpu_t *mpu) mpu->state.cond_set = 0; mpu->state.playing = 0; mpu->state.run_irq = 0; - mpu->state.irq_pending = 0; mpu->state.cmask = 0xff; mpu->state.amask = mpu->state.tmask = 0; mpu->state.midi_mask = 0xffff; - mpu->state.data_onoff = 0; mpu->state.command_byte = 0; mpu->state.block_ack = 0; mpu->clock.tempo = mpu->clock.old_tempo = 100; mpu->clock.timebase = mpu->clock.old_timebase = 120; - mpu->clock.tempo_rel = mpu->clock.old_tempo_rel = 40; + mpu->clock.tempo_rel = mpu->clock.old_tempo_rel = 0x40; + mpu->clock.freq_mod = 1.0; mpu->clock.tempo_grad = 0; - mpu->clock.clock_to_host = 0; - mpu->clock.cth_rate = 60; - mpu->clock.cth_counter = 0; + MPU401_StopClock(mpu); + MPU401_ReCalcClock(mpu); - ClrQueue(mpu); + for (i = 0; i < 4; i++) + mpu->clock.cth_rate[i] = 60; + + mpu->clock.cth_counter = 0; + mpu->clock.midimetro = 12; + mpu->clock.metromeas = 8; + mpu->filter.rec_measure_end = 1; + mpu->filter.rt_out = 1; + mpu->filter.rt_affection = 1; + mpu->filter.allnotesoff_out = 1; + mpu->filter.all_thru = 1; + mpu->filter.midi_thru = 1; + mpu->filter.commonmsgs_thru = 1; + + /* Reset channel reference and input tables. */ + for (i = 0; i < 4; i++) { + mpu->chanref[i].on = 1; + mpu->chanref[i].chan = i; + mpu->ch_toref[i] = i; + } + + for (i = 0; i < 16; i++) { + mpu->inputref[i].on = 1; + mpu->inputref[i].chan = i; + if (i > 3) + mpu->ch_toref[i] = 4; /* Dummy reftable. */ + } + + MPU401_ClrQueue(mpu); + mpu->state.data_onoff = -1; mpu->state.req_mask = 0; - mpu->condbuf.counter = 0; + mpu->condbuf.counter = 0; mpu->condbuf.type = T_OVERFLOW; - for (i=0;i<8;i++) { + for (i = 0; i < 8; i++) { mpu->playbuf[i].type = T_OVERFLOW; mpu->playbuf[i].counter = 0; } + + /* Clear MIDI buffers, terminate notes. */ + midi_clear_buffer(); + + for (i = 0xb0; i <= 0xbf; i++) { + midi_raw_out_byte(i); + midi_raw_out_byte(0x7b); + midi_raw_out_byte(0); + } } @@ -161,12 +308,13 @@ MPU401_ResetDone(void *priv) mpu401_log("MPU-401 reset callback\n"); - mpu401_reset_callback = 0LL; + timer_disable(&mpu->mpu401_reset_callback); - mpu->state.reset=0; + mpu->state.reset = 0; + if (mpu->state.cmd_pending) { - MPU401_WriteCommand(mpu, mpu->state.cmd_pending-1); - mpu->state.cmd_pending=0; + MPU401_WriteCommand(mpu, mpu->state.cmd_pending - 1); + mpu->state.cmd_pending = 0; } } @@ -174,307 +322,461 @@ MPU401_ResetDone(void *priv) static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val) { - uint8_t i; + uint8_t i, j, was_uart, recmsg[3]; - if (mpu->state.reset) { - mpu->state.cmd_pending=val+1; - } + if (mpu->state.reset) + mpu->state.cmd_pending = val + 1; - if (val <= 0x2f) { - switch (val&3) { /* MIDI stop, start, continue */ - case 1: - midi_write(0xfc); - break; + /* The only command recognized in UART mode is 0xFF: Reset and return to Intelligent mode. */ + if ((val != 0xff) && (mpu->mode == M_UART)) + return; - case 2: - midi_write(0xfa); - break; + /* In Intelligent mode, UART-only variants of the MPU-401 only support commands 0x3F and 0xFF. */ + if ((val != 0x3f) && (val != 0xff) && !mpu->intelligent) + return; - case 3: - midi_write(0xfb); - break; + /* Hack: Enable midi through after the first mpu401 command is written. */ + mpu->midi_thru = 1; + + if (val <= 0x2f) { /* Sequencer state */ + int send_prchg = 0; + if ((val & 0xf) < 0xc) { + switch (val & 3) { /* MIDI realtime messages */ + case 1: + mpu->state.last_rtcmd = 0xfc; + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xfc); + mpu->clock.meas_old = mpu->clock.measure_counter; + mpu->clock.cth_old = mpu->clock.cth_counter; + break; + case 2: + mpu->state.last_rtcmd = 0xfa; + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xfb); + mpu->clock.measure_counter = mpu->clock.meas_old = 0; + mpu->clock.cth_counter = mpu->clock.cth_old = 0; + break; + case 3: + mpu->state.last_rtcmd = 0xfc; + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xfa); + mpu->clock.measure_counter = mpu->clock.meas_old; + mpu->clock.cth_counter = mpu->clock.cth_old; + break; + } + switch (val & 0xc) { /* Playing */ + case 0x4: /* Stop */ + mpu->state.playing = 0; + MPU401_StopClock(mpu); + for (i = 0; i < 16; i++) + MPU401_NotesOff(mpu, i); + mpu->filter.prchg_mask = 0; + break; + case 0x8: /* Start */ + mpu->state.playing = 1; + MPU401_StartClock(mpu); + break; + } + switch (val & 0x30) { /* Recording */ + case 0: /* check if it waited for MIDI RT command */ + if (((val & 3) < 2) || !mpu->filter.rt_affection || (mpu->state.rec != M_RECSTB)) + break; + mpu->state.rec = M_RECON; + MPU401_StartClock(mpu); + if (mpu->filter.prchg_mask) + send_prchg = 1; + break; + case 0x10: /* Stop */ + mpu->state.rec = M_RECOFF; + MPU401_StopClock(mpu); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, mpu->clock.rec_counter); + MPU401_QueueByte(mpu, MSG_MPU_END); + mpu->filter.prchg_mask = 0; + mpu->clock.rec_counter = 0; + return; + case 0x20: /* Start */ + if (!(mpu->state.rec == M_RECON)) { + mpu->clock.rec_counter = 0; + mpu->state.rec = M_RECSTB; + } + if ((mpu->state.last_rtcmd == 0xfa) || (mpu->state.last_rtcmd == 0xfb)) { + mpu->clock.rec_counter = 0; + mpu->state.rec = M_RECON; + if (mpu->filter.prchg_mask) + send_prchg = 1; + MPU401_StartClock(mpu); + } + break; + } } - - switch (val & 0xc) { - case 0x4: /* Stop */ - mpu->state.playing = 0; - mpu401_event_callback = 0LL; - - for (i=0xb0; i<0xbf; i++) { - /* All notes off */ - midi_write(i); - midi_write(0x7b); - midi_write(0); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + /* record counter hack: needed by Prism, but sent only on cmd 0x20/0x26 (or breaks Ballade) */ + uint8_t rec_cnt = mpu->clock.rec_counter; + if (((val == 0x20) || (val == 0x26)) && (mpu->state.rec == M_RECON)) + MPU401_RecQueueBuffer(mpu, &rec_cnt, 1, 0); + + if (send_prchg) { + for (i = 0; i < 16; i++) { + if (mpu->filter.prchg_mask & (1 << i)) { + recmsg[0] = mpu->clock.rec_counter; + recmsg[1] = 0xc0 | i; + recmsg[2] = mpu->filter.prchg_buf[i]; + MPU401_RecQueueBuffer(mpu, recmsg, 3, 0); + mpu->filter.prchg_mask &= ~(1 << i); } - break; - - case 0x8: /* Play */ - mpu->state.playing = 1; - mpu401_event_callback = (MPU401_TIMECONSTANT / (mpu->clock.tempo*mpu->clock.timebase)) * 1000LL * TIMER_USEC; - ClrQueue(mpu); - break; + } } - } else if (val>=0xa0 && val<=0xa7) { /* Request play counter */ - if (mpu->state.cmask&(1<<(val&7))) QueueByte(mpu, mpu->playbuf[val&7].counter); - } else if (val>=0xd0 && val<=0xd7) { /* Send data */ - mpu->state.old_chan = mpu->state.channel; - mpu->state.channel= val & 7; + } else if ((val >= 0xa0) && (val <= 0xa7)) /* Request play counter */ + MPU401_QueueByte(mpu, mpu->playbuf[val & 7].counter); + else if ((val >= 0xd0) && (val <= 0xd7)) { /* Send data */ + mpu->state.old_track = mpu->state.track; + mpu->state.track= val & 7; mpu->state.wsd = 1; mpu->state.wsm = 0; mpu->state.wsd_start = 1; + } else if ((val < 0x80) && (val >= 0x40)) { /* Set reference table channel */ + mpu->chanref[(val >> 4) - 4].on = 1; + mpu->chanref[(val >> 4) - 4].chan = val & 0x0f; + mpu->chanref[(val >> 4) - 4].trmask = 0; + for (i = 0; i < 4; i++) + mpu->chanref[(val >> 4) - 4].key[i] = 0; + for (i = 0; i < 16; i++) { + if (mpu->ch_toref[i] == ((val >> 4) - 4)) + mpu->ch_toref[i] = 4; + } + mpu->ch_toref[val & 0x0f] = (val >> 4) - 4; } else switch (val) { + case 0x30: /* Configuration 0x30 - 0x39 */ + mpu->filter.allnotesoff_out = 0; + break; + case 0x32: + mpu->filter.rt_out = 0; + break; + case 0x33: + mpu->filter.all_thru = 0; + mpu->filter.commonmsgs_thru = 0; + mpu->filter.midi_thru = 0; + for (i = 0; i < 16; i++) { + mpu->inputref[i].on = 0; + for (j = 0; i < 4; j++) + mpu->inputref[i].key[j] = 0; + } + break; + case 0x34: + mpu->filter.timing_in_stop = 1; + break; + case 0x35: + mpu->filter.modemsgs_in = 1; + break; + case 0x37: + mpu->filter.sysex_thru = 1; + break; + case 0x38: + mpu->filter.commonmsgs_in = 1; + break; + case 0x39: + mpu->filter.rt_in = 1; + break; + case 0x3f: /* UART mode */ + mpu401_log("MPU-401: Set UART mode %X\n",val); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + mpu->mode = M_UART; + return; + case 0x80: /* Internal clock */ + if (mpu->clock.active && mpu->state.sync_in) { + timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + mpu->clock.freq_mod = 1.0; + } + mpu->state.sync_in = 0; + break; + case 0x81: /* Sync to tape signal */ + case 0x82: /* Sync to MIDI */ + mpu->clock.ticks_in = 0; + mpu->state.sync_in = 1; + break; + case 0x86: case 0x87: /* Bender */ + mpu->filter.bender_in = !!(val & 1); + break; + case 0x88: case 0x89: /* MIDI through */ + mpu->filter.midi_thru = !!(val & 1); + for (i = 0; i < 16; i++) { + mpu->inputref[i].on = mpu->filter.midi_thru; + if (!(val & 1)) { + for (j = 0; j < 4; j++) + mpu->inputref[i].key[j] = 0; + } + } + break; + case 0x8a: case 0x8b: /* Data in stop */ + mpu->filter.data_in_stop = !!(val & 1); + break; + case 0x8c: case 0x8d: /* Send measure end */ + mpu->filter.rec_measure_end = !!(val & 1); + break; + case 0x8e: case 0x8f: /* Conductor */ + mpu->state.cond_set = !!(val & 1); + break; + case 0x90: case 0x91: /* Realtime affection */ + mpu->filter.rt_affection = !!(val & 1); + break; + case 0x94: /* Clock to host */ + mpu->state.clock_to_host = 0; + MPU401_StopClock(mpu); + break; + case 0x95: + mpu->state.clock_to_host = 1; + MPU401_StartClock(mpu); + break; + case 0x96: case 0x97: /* Sysex input allow */ + mpu->filter.sysex_in = !!(val & 1); + if (val & 1) + mpu->filter.sysex_thru = 0; + break; + case 0x98: case 0x99: case 0x9a: case 0x9b: /* Reference tables on/off */ + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + mpu->chanref[(val - 0x98) / 2].on = !!(val & 1); + break; + /* Commands 0xa# returning data */ + case 0xab: /* Request and clear recording counter */ + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, 0); + return; + case 0xac: /* Request version */ + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MPU401_VERSION); + return; + case 0xad: /* Request revision */ + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MPU401_REVISION); + return; + case 0xaf: /* Request tempo */ + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, mpu->clock.tempo); + return; + case 0xb1: /* Reset relative tempo */ + mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; + mpu->clock.tempo_rel = 0x40; + break; + case 0xb8: /* Clear play counters */ + mpu->state.last_rtcmd = 0; + for (i = 0; i < 8; i++) { + mpu->playbuf[i].counter = 0; + mpu->playbuf[i].type = T_OVERFLOW; + } + mpu->condbuf.counter = 0; + mpu->condbuf.type = T_OVERFLOW; + mpu->state.amask = mpu->state.tmask; + mpu->state.conductor = mpu->state.cond_set; + mpu->clock.cth_counter = mpu->clock.cth_old = 0; + mpu->clock.measure_counter = mpu->clock.meas_old = 0; + break; + case 0xb9: /* Clear play map */ + for (i = 0; i < 16; i++) + MPU401_NotesOff(mpu, i); + for (i = 0; i < 8; i++) { + mpu->playbuf[i].counter = 0; + mpu->playbuf[i].type = T_OVERFLOW; + } + mpu->state.last_rtcmd = 0; + mpu->clock.cth_counter = mpu->clock.cth_old = 0; + mpu->clock.measure_counter = mpu->clock.meas_old = 0; + break; + case 0xba: /* Clear record counter */ + mpu->clock.rec_counter = 0; + break; + case 0xc2: case 0xc3: case 0xc4: /* Internal timebase */ + case 0xc5: case 0xc6: case 0xc7: case 0xc8: + mpu->clock.timebase = MPUClockBase[val-0xc2]; + MPU401_ReCalcClock(mpu); + break; case 0xdf: /* Send system message */ mpu->state.wsd = 0; mpu->state.wsm = 1; mpu->state.wsd_start = 1; break; - - case 0x8e: /* Conductor */ - mpu->state.cond_set = 0; - break; - - case 0x8f: - mpu->state.cond_set = 1; - break; - - case 0x94: /* Clock to host */ - mpu->clock.clock_to_host=0; - break; - - case 0x95: - mpu->clock.clock_to_host=1; - break; - - case 0xc2: /* Internal timebase */ - mpu->clock.timebase=48; - break; - - case 0xc3: - mpu->clock.timebase=72; - break; - - case 0xc4: - mpu->clock.timebase=96; - break; - - case 0xc5: - mpu->clock.timebase=120; - break; - - case 0xc6: - mpu->clock.timebase=144; - break; - - case 0xc7: - mpu->clock.timebase=168; - break; - case 0xc8: - mpu->clock.timebase=192; - break; - /* Commands with data byte */ case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: - mpu->state.command_byte=val; + mpu->state.command_byte = val; break; - - /* Commands 0xa# returning data */ - case 0xab: /* Request and clear recording counter */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, 0); - return; - - case 0xac: /* Request version */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, MPU401_VERSION); - return; - - case 0xad: /* Request revision */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, MPU401_REVISION); - return; - - case 0xaf: /* Request tempo */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, mpu->clock.tempo); - return; - - case 0xb1: /* Reset relative tempo */ - mpu->clock.tempo_rel=40; - break; - - case 0xb9: /* Clear play map */ - case 0xb8: /* Clear play counters */ - for (i=0xb0;i<0xbf;i++) { - /* All notes off */ - midi_write(i); - midi_write(0x7b); - midi_write(0); - } - for (i=0;i<8;i++) { - mpu->playbuf[i].counter=0; - mpu->playbuf[i].type=T_OVERFLOW; - } - mpu->condbuf.counter=0; - mpu->condbuf.type=T_OVERFLOW; - if (!(mpu->state.conductor=mpu->state.cond_set)) - mpu->state.cond_req=0; - mpu->state.amask=mpu->state.tmask; - mpu->state.req_mask=0; - mpu->state.irq_pending=1; - break; - case 0xff: /* Reset MPU-401 */ - mpu401_log("MPU-401:Reset %X\n",val); - mpu401_reset_callback = MPU401_RESETBUSY * 33LL * TIMER_USEC; - mpu->state.reset=1; + mpu401_log("MPU-401: Reset %X\n", val); + timer_set_delay_u64(&mpu->mpu401_reset_callback, MPU401_RESETBUSY * 33LL * TIMER_USEC); + mpu->state.reset = 1; + was_uart = (mpu->mode == M_UART); MPU401_Reset(mpu); -#if 0 - if (mpu->mode==M_UART) return;//do not send ack in UART mode -#endif + if (was_uart) + return; /* do not send ack in UART mode */ break; - case 0x3f: /* UART mode */ - mpu401_log("MPU-401:Set UART mode %X\n",val); - mpu->mode=M_UART; - break; - - default:; - //mpu401_log("MPU-401:Unhandled command %X",val); + /* default: + mpu401_log("MPU-401:Unhandled command %X",val); */ } - QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MSG_MPU_ACK); } static void MPU401_WriteData(mpu_t *mpu, uint8_t val) { - if (mpu->mode==M_UART) {midi_write(val); return;} + static int length, cnt; + uint8_t i; + + if (mpu->mode == M_UART) { + midi_raw_out_byte(val); + return; + } + + if (!mpu->intelligent) { + mpu->state.command_byte = 0; + return; + } switch (mpu->state.command_byte) { /* 0xe# command data */ case 0x00: break; - case 0xe0: /* Set tempo */ - mpu->state.command_byte=0; - mpu->clock.tempo=val; + mpu->state.command_byte = 0; + if (mpu->clock.tempo < 8) + mpu->clock.tempo = 8; + else if (mpu->clock.tempo > 250) + mpu->clock.tempo = 250; + else + mpu->clock.tempo = val; + MPU401_ReCalcClock(mpu); return; - case 0xe1: /* Set relative tempo */ - mpu->state.command_byte=0; - if (val!=0x40) //default value - mpu401_log("MPU-401:Relative tempo change not implemented\n"); + mpu->state.command_byte = 0; + mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; + mpu->clock.tempo_rel = val; + MPU401_ReCalcClock(mpu); return; - + case 0xe2: /* Set gradation for relative tempo */ + mpu->clock.tempo_grad = val; + MPU401_ReCalcClock(mpu); + return; + case 0xe4: /* Set MIDI clocks for metronome ticks */ + mpu->state.command_byte = 0; + mpu->clock.midimetro = val; + return; + case 0xe6: /* Set metronome ticks per measure */ + mpu->state.command_byte = 0; + mpu->clock.metromeas = val; + return; case 0xe7: /* Set internal clock to host interval */ - mpu->state.command_byte=0; - mpu->clock.cth_rate=val>>2; + mpu->state.command_byte = 0; + if (!val) + val = 64; + for (i = 0; i < 4; i++) + mpu->clock.cth_rate[i] = (val >> 2) + cth_data[(val & 3) * 4 + i]; + mpu->clock.cth_mode = 0; return; - case 0xec: /* Set active track mask */ - mpu->state.command_byte=0; - mpu->state.tmask=val; + mpu->state.command_byte = 0; + mpu->state.tmask = val; return; - case 0xed: /* Set play counter mask */ - mpu->state.command_byte=0; - mpu->state.cmask=val; + mpu->state.command_byte = 0; + mpu->state.cmask = val; return; - case 0xee: /* Set 1-8 MIDI channel mask */ - mpu->state.command_byte=0; - mpu->state.midi_mask&=0xff00; - mpu->state.midi_mask|=val; + mpu->state.command_byte = 0; + mpu->state.midi_mask &= 0xff00; + mpu->state.midi_mask |= val; return; - case 0xef: /* Set 9-16 MIDI channel mask */ - mpu->state.command_byte=0; - mpu->state.midi_mask&=0x00ff; - mpu->state.midi_mask|=((uint16_t)val)<<8; + mpu->state.command_byte = 0; + mpu->state.midi_mask &= 0x00ff; + mpu->state.midi_mask |= ((uint16_t) val) << 8; return; - //case 0xe2: /* Set graduation for relative tempo */ - //case 0xe4: /* Set metronome */ - //case 0xe6: /* Set metronome measure length */ default: - mpu->state.command_byte=0; + mpu->state.command_byte = 0; return; } - static int length,cnt,posd; - - if (mpu->state.wsd) { + if (mpu->state.wsd && !mpu->state.track_req && !mpu->state.cond_req) { /* Directly send MIDI message */ if (mpu->state.wsd_start) { - mpu->state.wsd_start=0; - cnt=0; - switch (val&0xf0) { - case 0xc0:case 0xd0: - mpu->playbuf[mpu->state.channel].value[0]=val; - length=2; + mpu->state.wsd_start = 0; + cnt = 0; + switch (val & 0xf0) { + case 0xc0: case 0xd0: + length = mpu->playbuf[mpu->state.track].length = 2; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; break; - - case 0x80:case 0x90:case 0xa0:case 0xb0:case 0xe0: - mpu->playbuf[mpu->state.channel].value[0]=val; - length=3; + case 0x80: case 0x90: case 0xa0: case 0xb0:case 0xe0: + length = mpu->playbuf[mpu->state.track].length = 3; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; break; case 0xf0: - //mpu401_log("MPU-401:Illegal WSD byte\n"); - mpu->state.wsd=0; - mpu->state.channel=mpu->state.old_chan; + /* mpu401_log("MPU-401:Illegal WSD byte\n"); */ + mpu->state.wsd = 0; + mpu->state.track = mpu->state.old_track; return; default: /* MIDI with running status */ cnt++; - midi_write(mpu->playbuf[mpu->state.channel].value[0]); + length = mpu->playbuf[mpu->state.track].length; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; } } - if (cntplaybuf[mpu->state.track].value[cnt] = val; + cnt++; + } - if (cnt==length) { - mpu->state.wsd=0; - mpu->state.channel=mpu->state.old_chan; + if (cnt == length) { + MPU401_IntelligentOut(mpu, mpu->state.track); + mpu->state.wsd = 0; + mpu->state.track = mpu->state.old_track; } return; } - if (mpu->state.wsm) { /* Directly send system message */ - if (val==MSG_EOX) {midi_write(MSG_EOX);mpu->state.wsm=0;return;} + if (mpu->state.wsm && !mpu->state.track_req && !mpu->state.cond_req) { /* Send system message */ if (mpu->state.wsd_start) { - mpu->state.wsd_start=0; - cnt=0; + mpu->state.wsd_start = 0; + cnt = 0; switch (val) { case 0xf2: - length=3; + length = 3; break; case 0xf3: - length=2; + length = 2; break; case 0xf6: - length=1; + length = 1; break; case 0xf0: - length=0; + length = 0; break; default: - length=0; + mpu->state.wsm = 0; + return; } + } else if (val & 0x80) { + midi_raw_out_byte(MSG_EOX); + mpu->state.wsm = 0; + return; } - if (!length || cntstate.wsm=0; + if (cnt == length) + mpu->state.wsm = 0; return; } @@ -484,35 +786,39 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) switch (mpu->state.data_onoff) { case -1: return; - case 0: /* Timing byte */ - mpu->condbuf.vlength=0; - if (val<0xf0) mpu->state.data_onoff++; - else { - mpu->state.data_onoff=-1; + mpu->condbuf.length = 0; + if (val < 0xf0) + mpu->state.data_onoff++; + else { + mpu->state.cond_req = 0; + mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); - return; + break; } - - if (val==0) mpu->state.send_now=1; - else mpu->state.send_now=0; - mpu->condbuf.counter=val; + mpu->state.send_now = !val ? 1 : 0; + mpu->condbuf.counter = val; break; - case 1: /* Command byte #1 */ - mpu->condbuf.type=T_COMMAND; - if (val==0xf8 || val==0xf9) - mpu->condbuf.type=T_OVERFLOW; - mpu->condbuf.value[mpu->condbuf.vlength]=val; - mpu->condbuf.vlength++; - if ((val&0xf0)!=0xe0) MPU401_EOIHandlerDispatch(mpu); - else mpu->state.data_onoff++; + mpu->condbuf.type = T_COMMAND; + if ((val == 0xf8) || (val == 0xf9) || (val == 0xfc)) + mpu->condbuf.type = T_OVERFLOW; + mpu->condbuf.value[mpu->condbuf.length] = val; + mpu->condbuf.length++; + if ((val & 0xf0) != 0xe0) { /*no cmd data byte*/ + MPU401_EOIHandler(mpu); + mpu->state.data_onoff = -1; + mpu->state.cond_req = 0; + } else + mpu->state.data_onoff++; break; case 2:/* Command byte #2 */ - mpu->condbuf.value[mpu->condbuf.vlength]=val; - mpu->condbuf.vlength++; - MPU401_EOIHandlerDispatch(mpu); + mpu->condbuf.value[mpu->condbuf.length]=val; + mpu->condbuf.length++; + MPU401_EOIHandler(mpu); + mpu->state.data_onoff = -1; + mpu->state.cond_req = 0; break; } return; @@ -521,86 +827,126 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) switch (mpu->state.data_onoff) { /* Data */ case -1: - return; - + break; case 0: /* Timing byte */ - if (val<0xf0) mpu->state.data_onoff=1; - else { - mpu->state.data_onoff=-1; + if (val < 0xf0) + mpu->state.data_onoff++; + else { + mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); + mpu->state.track_req = 0; return; } - if (val==0) mpu->state.send_now=1; - else mpu->state.send_now=0; - mpu->playbuf[mpu->state.channel].counter=val; + mpu->state.send_now = !val ? 1 : 0; + mpu->playbuf[mpu->state.track].counter = val; break; - case 1: /* MIDI */ - mpu->playbuf[mpu->state.channel].vlength++; - posd=mpu->playbuf[mpu->state.channel].vlength; - if (posd==1) switch (val&0xf0) { - case 0xf0: /* System message or mark */ - if (val>0xf7) { - mpu->playbuf[mpu->state.channel].type=T_MARK; - mpu->playbuf[mpu->state.channel].sys_val=val; - length=1; - } else { - //LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal message"); - mpu->playbuf[mpu->state.channel].type=T_MIDI_SYS; - mpu->playbuf[mpu->state.channel].sys_val=val; - length=1; - } - break; - + cnt = 0; + mpu->state.data_onoff++; + switch (val & 0xf0) { case 0xc0: case 0xd0: /* MIDI Message */ - mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; - length=mpu->playbuf[mpu->state.channel].length=2; + length = mpu->playbuf[mpu->state.track].length = 2; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; break; - - case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0: - mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; - length=mpu->playbuf[mpu->state.channel].length=3; + case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0: + length = mpu->playbuf[mpu->state.track].length = 3; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; break; - - default: /* MIDI data with running status */ - posd++; - mpu->playbuf[mpu->state.channel].vlength++; - mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; - length=mpu->playbuf[mpu->state.channel].length; + case 0xf0: /* System message or mark */ + mpu->playbuf[mpu->state.track].sys_val = val; + if (val > 0xf7) { + mpu->playbuf[mpu->state.track].type = T_MARK; + if (val == 0xf9) + mpu->clock.measure_counter = 0; + } else { + /* mpu401_log("MPU-401:Illegal message"); */ + mpu->playbuf[mpu->state.track].type = T_OVERFLOW; + } + mpu->state.data_onoff = -1; + MPU401_EOIHandler(mpu); + mpu->state.track_req = 0; + return; + default: /* MIDI with running status */ + cnt++; + length = mpu->playbuf[mpu->state.track].length; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; break; } - - if (!(posd==1 && val>=0xf0)) - mpu->playbuf[mpu->state.channel].value[posd-1]=val; - if (posd==length) MPU401_EOIHandlerDispatch(mpu); + break; + case 2: + if (cnt < length) { + mpu->playbuf[mpu->state.track].value[cnt] = val; + cnt++; + } + if (cnt == length) { + mpu->state.data_onoff = -1; + mpu->state.track_req = 0; + MPU401_EOIHandler(mpu); + } + break; } + + return; } static void -MPU401_IntelligentOut(mpu_t *mpu, uint8_t chan) +MPU401_IntelligentOut(mpu_t *mpu, uint8_t track) { - uint8_t val; + uint8_t chan, chrefnum, key, msg; + int send, retrigger; uint8_t i; - switch (mpu->playbuf[chan].type) { + switch (mpu->playbuf[track].type) { case T_OVERFLOW: break; case T_MARK: - val=mpu->playbuf[chan].sys_val; - if (val==0xfc) { - midi_write(val); - mpu->state.amask&=~(1<state.req_mask&=~(1<playbuf[track].sys_val == 0xfc) { + midi_raw_out_rt_byte(mpu->playbuf[track].sys_val); + mpu->state.amask&=~(1<playbuf[chan].vlength;i++) - midi_write(mpu->playbuf[chan].value[i]); + chan = mpu->playbuf[track].value[0] & 0xf; + key = mpu->playbuf[track].value[1] & 0x7f; + chrefnum = mpu->ch_toref[chan]; + send = 1; + retrigger = 0; + switch (msg = mpu->playbuf[track].value[0] & 0xf0) { + case 0x80: /* note off */ + if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY)) + send = 0; + if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY))) + send = 0; + mpu->chanref[chrefnum].M_DELKEY; + break; + case 0x90: /* note on */ + if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY)) + retrigger = 1; + if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY))) + retrigger = 1; + mpu->chanref[chrefnum].M_SETKEY; + break; + case 0xb0: + if (mpu->playbuf[track].value[1] == 123) { /* All notes off */ + MPU401_NotesOff(mpu, mpu->playbuf[track].value[0] & 0xf); + return; + } + break; + } + if (retrigger) { + midi_raw_out_byte(0x80 | chan); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } + if (send) { + for (i = 0; i < mpu->playbuf[track].length; i++) + midi_raw_out_byte(mpu->playbuf[track].value[i]); + } break; - + default: break; } @@ -608,41 +954,42 @@ MPU401_IntelligentOut(mpu_t *mpu, uint8_t chan) static void -UpdateTrack(mpu_t *mpu, uint8_t chan) +UpdateTrack(mpu_t *mpu, uint8_t track) { - MPU401_IntelligentOut(mpu, chan); + MPU401_IntelligentOut(mpu, track); - if (mpu->state.amask&(1<playbuf[chan].vlength=0; - mpu->playbuf[chan].type=T_OVERFLOW; - mpu->playbuf[chan].counter=0xf0; - mpu->state.req_mask|=(1<state.amask&(1<playbuf[track].type = T_OVERFLOW; + mpu->playbuf[track].counter = 0xf0; + mpu->state.req_mask |= (1 << track); } else { - if (mpu->state.amask==0 && !mpu->state.conductor) - mpu->state.req_mask|=(1<<12); + if ((mpu->state.amask == 0) && !mpu->state.conductor) + mpu->state.req_mask |= (1 << 12); } } +#if 0 static void UpdateConductor(mpu_t *mpu) { - if (mpu->condbuf.value[0]==0xfc) { - mpu->condbuf.value[0]=0; - mpu->state.conductor=0; - mpu->state.req_mask&=~(1<<9); - if (mpu->state.amask==0) - mpu->state.req_mask|=(1<<12); + if (mpu->condbuf.value[0] == 0xfc) { + mpu->condbuf.value[0] = 0; + mpu->state.conductor = 0; + mpu->state.req_mask &= ~(1 << 9); + if (mpu->state.amask == 0) + mpu->state.req_mask |= (1 << 12); return; } - mpu->condbuf.vlength=0; - mpu->condbuf.counter=0xf0; - mpu->state.req_mask|=(1<<9); + mpu->condbuf.vlength = 0; + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); } +#endif -//Updates counters and requests new data on "End of Input" +/* Updates counters and requests new data on "End of Input" */ static void MPU401_EOIHandler(void *priv) { @@ -651,26 +998,32 @@ MPU401_EOIHandler(void *priv) mpu401_log("MPU-401 end of input callback\n"); - mpu401_eoi_callback = 0LL; - mpu->state.eoi_scheduled=0; + timer_disable(&mpu->mpu401_eoi_callback); + mpu->state.eoi_scheduled = 0; if (mpu->state.send_now) { - mpu->state.send_now=0; - if (mpu->state.cond_req) UpdateConductor(mpu); - else UpdateTrack(mpu, mpu->state.channel); + mpu->state.send_now = 0; + if (mpu->state.cond_req) { + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); + } else UpdateTrack(mpu, mpu->state.track); } - mpu->state.irq_pending=0; + if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) + return; - if (!mpu->state.playing || !mpu->state.req_mask) return; + mpu->state.irq_pending = 0; - i=0; + if (!(mpu->state.req_mask && mpu->clock.active)) + return; + + i = 0; do { - if (mpu->state.req_mask&(1<state.req_mask&=~(1<state.req_mask & (1 << i)) { + MPU401_QueueByte(mpu, 0xf0 + i); + mpu->state.req_mask &= ~(1 << i); break; } - } while ((i++)<16); + } while ((i++) < 16); } @@ -679,9 +1032,10 @@ MPU401_EOIHandlerDispatch(void *priv) { mpu_t *mpu = (mpu_t *)priv; + mpu401_log("EOI handler dispatch\n"); if (mpu->state.send_now) { - mpu->state.eoi_scheduled=1; - mpu401_eoi_callback = 60LL * TIMER_USEC; /* Possible a bit longer */ + mpu->state.eoi_scheduled = 1; + timer_advance_u64(&mpu->mpu401_eoi_callback, 60LL * TIMER_USEC); /* Possibly a bit longer */ } else if (!mpu->state.eoi_scheduled) MPU401_EOIHandler(mpu); } @@ -694,47 +1048,84 @@ imf_write(uint16_t addr, uint8_t val, void *priv) } +void +MPU401_ReadRaiseIRQ(mpu_t *mpu) +{ + /* Clear IRQ. */ + picintc(1 << mpu->irq); + mpu->state.irq_pending = 0; + + if (mpu->queue_used) { + /* Bytes remaining in queue, raise IRQ again. */ + mpu->state.irq_pending = 1; + picint(1 << mpu->irq); + } +} + + uint8_t MPU401_ReadData(mpu_t *mpu) { uint8_t ret; ret = MSG_MPU_ACK; + if (mpu->queue_used) { - if (mpu->queue_pos>=MPU401_QUEUE) mpu->queue_pos-=MPU401_QUEUE; - ret=mpu->queue[mpu->queue_pos]; - mpu->queue_pos++;mpu->queue_used--; + if (mpu->queue_pos >= MPU401_QUEUE) + mpu->queue_pos -= MPU401_QUEUE; + ret = mpu->queue[mpu->queue_pos]; + mpu->queue_pos++; + mpu->queue_used--; } - if (!mpu->intelligent) return ret; + /* Shouldn't this check mpu->mode? */ + if (mpu->mode == M_UART) { + MPU401_ReadRaiseIRQ(mpu); + return ret; + } - if (mpu->queue_used == 0) picintc(1 << mpu->irq); + if (mpu->state.rec_copy && !mpu->rec_queue_used) { + mpu->state.rec_copy = 0; + MPU401_EOIHandler(mpu); + return ret; + } - if (ret>=0xf0 && ret<=0xf7) { + /* Copy from recording buffer. */ + if (!mpu->queue_used && mpu->rec_queue_used) { + mpu->state.rec_copy = 1; + if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE) + mpu->rec_queue_pos -= MPU401_INPUT_QUEUE; + MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); + mpu->rec_queue_pos++; + mpu->rec_queue_used--; + } + + MPU401_ReadRaiseIRQ(mpu); + + if ((ret >= 0xf0) && (ret <= 0xf7)) { /* MIDI data request */ - mpu->state.channel=ret&7; - mpu->state.data_onoff=0; - mpu->state.cond_req=0; + mpu->state.track = ret & 7; + mpu->state.data_onoff = 0; + mpu->state.cond_req = 0; + mpu->state.track_req = 1; } - if (ret==MSG_MPU_COMMAND_REQ) { - mpu->state.data_onoff=0; - mpu->state.cond_req=1; - if (mpu->condbuf.type!=T_OVERFLOW) { - mpu->state.block_ack=1; + if (ret == MSG_MPU_COMMAND_REQ) { + mpu->state.data_onoff = 0; + mpu->state.cond_req = 1; + if (mpu->condbuf.type != T_OVERFLOW) { + mpu->state.block_ack = 1; MPU401_WriteCommand(mpu, mpu->condbuf.value[0]); if (mpu->state.command_byte) MPU401_WriteData(mpu, mpu->condbuf.value[1]); + mpu->condbuf.type = T_OVERFLOW; } - mpu->condbuf.type=T_OVERFLOW; } - if (ret==MSG_MPU_END || ret==MSG_MPU_CLOCK || ret==MSG_MPU_ACK) { - mpu->state.data_onoff=-1; + if ((ret == MSG_MPU_END) || (ret == MSG_MPU_CLOCK) || (ret == MSG_MPU_ACK) || (ret == MSG_MPU_OVERFLOW)) MPU401_EOIHandlerDispatch(mpu); - } - return(ret); + return ret; } @@ -765,15 +1156,17 @@ mpu401_read(uint16_t addr, void *priv) uint8_t ret = 0; switch (addr & 1) { - case 0: //Read Data + case 0: /* Read Data */ ret = MPU401_ReadData(mpu); mpu401_log("Read Data (0x330) %X\n", ret); break; - case 1: //Read Status - if (mpu->state.cmd_pending) ret=STATUS_OUTPUT_NOT_READY; - if (!mpu->queue_used) ret=STATUS_INPUT_NOT_READY; - ret |= 0x3f; //FIXME: check with MPU401 TechRef + case 1: /* Read Status */ + if (mpu->state.cmd_pending) + ret = STATUS_OUTPUT_NOT_READY; + if (!mpu->queue_used) + ret = STATUS_INPUT_NOT_READY; + ret |= 0x3f; mpu401_log("Read Status (0x331) %x\n", ret); break; @@ -788,50 +1181,371 @@ static void MPU401_Event(void *priv) { mpu_t *mpu = (mpu_t *)priv; - int new_time; uint8_t i; + int max_meascnt; mpu401_log("MPU-401 event callback\n"); - if (mpu->mode==M_UART) { - mpu401_event_callback = 0LL; + if (mpu->mode == M_UART) { + timer_disable(&mpu->mpu401_event_callback); return; } if (mpu->state.irq_pending) goto next_event; + + if (mpu->state.playing) { + for (i = 0; i < 8; i++) { + /* Decrease counters. */ + if (mpu->state.amask & (1 << i)) { + mpu->playbuf[i].counter--; + if (mpu->playbuf[i].counter <= 0) + UpdateTrack(mpu, i); + } + } - for (i=0;i<8;i++) { /* Decrease counters */ - if (mpu->state.amask&(1<playbuf[i].counter--; - if (mpu->playbuf[i].counter<=0) UpdateTrack(mpu, i); + if (mpu->state.conductor) { + mpu->condbuf.counter--; + if (mpu->condbuf.counter <= 0) { + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); + } } } - if (mpu->state.conductor) { - mpu->condbuf.counter--; - if (mpu->condbuf.counter<=0) UpdateConductor(mpu); - } - - if (mpu->clock.clock_to_host) { + if (mpu->state.clock_to_host) { mpu->clock.cth_counter++; - if (mpu->clock.cth_counter >= mpu->clock.cth_rate) { - mpu->clock.cth_counter=0; - mpu->state.req_mask|=(1<<13); + if (mpu->clock.cth_counter >= mpu->clock.cth_rate[mpu->clock.cth_mode]) { + mpu->clock.cth_counter = 0; + mpu->clock.cth_mode++; + mpu->clock.cth_mode %= 4; + mpu->state.req_mask |= (1 << 13); } } + if (mpu->state.rec == M_RECON) { + /* Recording. */ + mpu->clock.rec_counter++; + if (mpu->clock.rec_counter>=240) { + mpu->clock.rec_counter=0; + mpu->state.req_mask|=(1<<8); + } + } + + if (mpu->state.playing || (mpu->state.rec == M_RECON)) { + max_meascnt = (mpu->clock.timebase * mpu->clock.midimetro * mpu->clock.metromeas) / 24; + if (max_meascnt != 0) { + /* Measure end. */ + if (++mpu->clock.measure_counter >= max_meascnt) { + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xf8); + mpu->clock.measure_counter = 0; + if (mpu->filter.rec_measure_end && (mpu->state.rec == M_RECON)) + mpu->state.req_mask |= (1 << 12); + } + } + } if (!mpu->state.irq_pending && mpu->state.req_mask) - MPU401_EOIHandler(mpu); + MPU401_EOIHandler(mpu); next_event: - /* mpu401_event_callback = 0LL; */ - new_time = (mpu->clock.tempo * mpu->clock.timebase); - if (new_time == 0) { - mpu401_event_callback = 0LL; + MPU401_RunClock(mpu); + if (mpu->state.sync_in) + mpu->clock.ticks_in++; +} + + +static void +MPU401_NotesOff(mpu_t *mpu, int i) +{ + int j; + uint8_t key; + + if (mpu->filter.allnotesoff_out && !(mpu->inputref[i].on && + (mpu->inputref[i].key[0] | mpu->inputref[i].key[1] | + mpu->inputref[i].key[2] | mpu->inputref[i].key[3]))) { + for (j=0;j<4;j++) + mpu->chanref[mpu->ch_toref[i]].key[j]=0; + midi_raw_out_byte(0xb0 | i); + midi_raw_out_byte(123); + midi_raw_out_byte(0); + } else if (mpu->chanref[mpu->ch_toref[i]].on) { + for (key = 0; key < 128; key++) { + if ((mpu->chanref[mpu->ch_toref[i]].M_GETKEY) && + !(mpu->inputref[i].on && (mpu->inputref[i].M_GETKEY))) { + midi_raw_out_byte(0x80|i); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } + mpu->chanref[mpu->ch_toref[i]].M_DELKEY; + } + } +} + + +/*Input handler for SysEx */ +static int +MPU401_InputSysex(void *p, uint8_t *buffer, uint32_t len, int abort) +{ + mpu_t *mpu = (mpu_t *)p; + int i; + uint8_t val_ff = 0xff; + + mpu401_log("MPU401 Input Sysex\n"); + + if (mpu->filter.sysex_in) { + if (abort) { + mpu->state.sysex_in_finished=1; + mpu->rec_queue_used=0;/*reset also the input queue*/ + return 0; + } + if (mpu->state.sysex_in_finished) { + if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE) + return len; + MPU401_RecQueueBuffer(mpu, &val_ff, 1, 1); + mpu->state.sysex_in_finished=0; + mpu->clock.rec_counter=0; + } + if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE) + return len; + int available = MPU401_INPUT_QUEUE - mpu->rec_queue_used; + + if (available >= len) { + MPU401_RecQueueBuffer(mpu, buffer, len, 1); + return 0; + } else { + MPU401_RecQueueBuffer(mpu,buffer, available, 1); + if (mpu->state.sysex_in_finished) + return 0; + return (len - available); + } + } else if (mpu->filter.sysex_thru && mpu->midi_thru) { + midi_raw_out_byte(0xf0); + for (i = 0; i < len; i++) + midi_raw_out_byte(*(buffer+i)); + } + return 0; +} + + +/*Input handler for MIDI*/ +static void +MPU401_InputMsg(void *p, uint8_t *msg) +{ + mpu_t *mpu = (mpu_t *)p; + int i, tick; + static uint8_t old_msg = 0; + uint8_t len = msg[3], key; + uint8_t recdata[2], recmsg[4]; + int send = 1, send_thru = 0; + int retrigger_thru = 0, midistatus = 0, chan, chrefnum; + + /* Abort if sysex transfer is in progress. */ + if (!mpu->state.sysex_in_finished) { + mpu401_log("SYSEX in progress\n"); return; - } else { - mpu401_event_callback += (MPU401_TIMECONSTANT/new_time) * 1000LL * TIMER_USEC; - mpu401_log("Next event after %i us (time constant: %i)\n", (int) ((MPU401_TIMECONSTANT/new_time) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); + } + + mpu401_log("MPU401 Input Msg\n"); + + if (mpu->mode == M_INTELLIGENT) { + if (msg[0] < 0x80) { + /* Expand running status */ + midistatus = 1; + msg[2] = msg[1]; + msg[1] = msg[0]; + msg[0] = old_msg; + } + old_msg = msg[0]; + chan = msg[0] & 0xf; + chrefnum = mpu->ch_toref[chan]; + key = msg[1] & 0x7f; + if (msg[0] < 0xf0) { + /* If non-system msg. */ + if (!(mpu->state.midi_mask & (1 << chan)) && mpu->filter.all_thru) + send_thru = 1; + else if (mpu->filter.midi_thru) + send_thru = 1; + switch (msg[0] & 0xf0) { + case 0x80: /* Note off. */ + if (send_thru) { + if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) + send_thru = 0; + if (!mpu->filter.midi_thru) + break; + if (!(mpu->inputref[chan].M_GETKEY)) + send_thru = 0; + mpu->inputref[chan].M_DELKEY; + } + break; + case 0x90: /* Note on. */ + if (send_thru) { + if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) + retrigger_thru = 1; + if (!mpu->filter.midi_thru) + break; + if (mpu->inputref[chan].M_GETKEY) + retrigger_thru = 1; + mpu->inputref[chan].M_SETKEY; + } + break; + case 0xb0: + if (msg[1] >= 120) { + send_thru = 0; + if (msg[1] == 123) { + /* All notes off. */ + for (key = 0; key < 128; key++) { + if (!(mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))) { + if (mpu->inputref[chan].on && mpu->inputref[chan].M_GETKEY) { + midi_raw_out_byte(0x80 | chan); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } + mpu->inputref[chan].M_DELKEY; + } + } + } + break; + } + } + } + if ((msg[0] >= 0xf0) || (mpu->state.midi_mask & (1 << chan))) { + switch (msg[0] & 0xf0) { + case 0xa0: /* Aftertouch. */ + if (!mpu->filter.bender_in) + send = 0; + break; + case 0xb0: /* Control change. */ + if (!mpu->filter.bender_in && (msg[1] < 64)) + send = 0; + if (msg[1] >= 120) { + if (mpu->filter.modemsgs_in) + send = 1; + } + break; + case 0xc0: /* Program change. */ + if ((mpu->state.rec != M_RECON) && !mpu->filter.data_in_stop) { + mpu->filter.prchg_buf[chan] = msg[1]; + mpu->filter.prchg_mask |= 1 << chan; + } + break; + case 0xd0: /* Ch pressure. */ + case 0xe0: /* Pitch wheel. */ + if (!mpu->filter.bender_in) + send = 0; + break; + case 0xf0: /* System message. */ + if (msg[0] == 0xf8) { + send = 0; + if (mpu->clock.active && mpu->state.sync_in) { + send = 0; /* Don't pass to host in this mode? */ + tick = mpu->clock.timebase / 24; + if (mpu->clock.ticks_in != tick) { + if (!mpu->clock.ticks_in || (mpu->clock.ticks_in > (tick * 2))) + mpu->clock.freq_mod *= 2.0; + else { + if (ABS(mpu->clock.ticks_in-tick) == 1) + mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick * 2); + else + mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick); + } + MPU401_ReCalcClock(mpu); + } + mpu->clock.ticks_in = 0; + } + } else if (msg[0] > 0xf8) { /* Realtime. */ + if (!(mpu->filter.rt_in && (msg[0] <= 0xfc) && (msg[0] >= 0xfa))) { + recdata[0] = 0xff; + recdata[1] = msg[0]; + MPU401_RecQueueBuffer(mpu, recdata, 2, 1); + send = 0; + } + } else { /* Common or system. */ + send = 0; + if ((msg[0] == 0xf2) || (msg[0] == 0xf3) || (msg[0] == 0xf6)) { + if (mpu->filter.commonmsgs_in) + send = 1; + if (mpu->filter.commonmsgs_thru) + for (i = 0; i < len; i++) + midi_raw_out_byte(msg[i]); + } + } + if (send) { + recmsg[0] = 0xff; + recmsg[1] = msg[0]; + recmsg[2] = msg[1]; + recmsg[3] = msg[2]; + MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + } + if (mpu->filter.rt_affection) { + switch(msg[0]) { + case 0xf2: case 0xf3: + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xb8); /* Clear play counters. */ + break; + case 0xfa: + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xa); /* Start, play. */ + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(msg[0]); + break; + case 0xfb: + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xb); /* Continue, play. */ + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(msg[0]); + break; + case 0xfc: + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xd) ;/* Stop: Play, rec, midi */ + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(msg[0]); + break; + } + return; + } + } + } + if (send_thru && mpu->midi_thru) { + if (retrigger_thru) { + midi_raw_out_byte(0x80 | (msg[0] & 0xf)); + midi_raw_out_byte(msg[1]); + midi_raw_out_byte(msg[2]); + } + for (i = 0; i < len; i++) + midi_raw_out_byte(msg[i]); + } + if (send) { + if (mpu->state.rec == M_RECON) { + recmsg[0] = mpu->clock.rec_counter; + recmsg[1] = msg[0]; + recmsg[2] = msg[1]; + recmsg[3] = msg[2]; + MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + mpu->clock.rec_counter = 0; + } + else if (mpu->filter.data_in_stop) { + if (mpu->filter.timing_in_stop) { + recmsg[0] = 0; + recmsg[1] = msg[0]; + recmsg[2] = msg[1]; + recmsg[3] = msg[2]; + MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + } else { + recmsg[0] = msg[0]; + recmsg[1] = msg[1]; + recmsg[2] = msg[2]; + recmsg[3] = 0; + MPU401_RecQueueBuffer(mpu, recmsg, len, 1); + } + } + } + return; + } + + /* UART mode input. */ + for (i = 0; i < len; i++) { + MPU401_QueueByte(mpu, msg[i]); + picint(1 << mpu->irq); } } @@ -839,33 +1553,27 @@ next_event: void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) { -#if 0 - if (mode != M_INTELLIGENT) { - mpu401_uart_init(mpu, addr); - return; - } -#endif - mpu->status = STATUS_INPUT_NOT_READY; mpu->irq = irq; mpu->queue_used = 0; mpu->queue_pos = 0; mpu->mode = M_UART; + /* Expalantion: + MPU-401 starting in intelligent mode = Full MPU-401 intelligent mode capability; + MPU-401 starting in UART mode = Reduced MPU-401 intelligent mode capability seen on the Sound Blaster 16/AWE32, + only supporting commands 3F (set UART mode) and FF (reset). */ mpu->intelligent = (mode == M_INTELLIGENT) ? 1 : 0; mpu401_log("Starting as %s (mode is %s)\n", mpu->intelligent ? "INTELLIGENT" : "UART", (mode == M_INTELLIGENT) ? "INTELLIGENT" : "UART"); - mpu401_event_callback = 0LL; - mpu401_eoi_callback = 0LL; - mpu401_reset_callback = 0LL; - - io_sethandler(addr, 2, - mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + if (addr) + io_sethandler(addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); io_sethandler(0x2A20, 16, NULL, NULL, NULL, imf_write, NULL, NULL, mpu); - timer_add(MPU401_Event, &mpu401_event_callback, &mpu401_event_callback, mpu); - timer_add(MPU401_EOIHandler, &mpu401_eoi_callback, &mpu401_eoi_callback, mpu); - timer_add(MPU401_ResetDone, &mpu401_reset_callback, &mpu401_reset_callback, mpu); + timer_add(&mpu->mpu401_event_callback, MPU401_Event, mpu, 0); + timer_add(&mpu->mpu401_eoi_callback, MPU401_EOIHandler, mpu, 0); + timer_add(&mpu->mpu401_reset_callback, MPU401_ResetDone, mpu, 0); MPU401_Reset(mpu); } @@ -874,16 +1582,56 @@ mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) void mpu401_device_add(void) { - char *n; + if (!mpu401_standalone_enable) + return; - if (!mpu401_standalone_enable) return; + if (machines[machine].flags & MACHINE_MCA) + device_add(&mpu401_mca_device); + else + device_add(&mpu401_device); +} - n = sound_card_get_internal_name(sound_card_current); - if (n != NULL) { - if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) return; + +static uint8_t +mpu401_mca_read(int port, void *p) +{ + mpu_t *mpu = (mpu_t *)p; + + return mpu->pos_regs[port & 7]; +} + + +static void +mpu401_mca_write(int port, uint8_t val, void *p) +{ + mpu_t *mpu = (mpu_t *)p; + uint16_t addr; + + if (port < 0x102) + return; + + addr = (mpu->pos_regs[2] & 2) ? 0x0330 : 0x1330; + + port &= 7; + + mpu->pos_regs[port] = val; + + if (port == 2) { + io_removehandler(addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + + addr = (mpu->pos_regs[2] & 2) ? 0x1330 : 0x0330; + + io_sethandler(addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); } +} - device_add(&mpu401_device); + +static uint8_t +mpu401_mca_feedb(void *p) +{ + return 1; } @@ -891,14 +1639,32 @@ static void * mpu401_standalone_init(const device_t *info) { mpu_t *mpu; + int irq; + uint16_t base; mpu = malloc(sizeof(mpu_t)); memset(mpu, 0, sizeof(mpu_t)); mpu401_log("mpu_init\n"); - mpu401_init(mpu, device_get_config_hex16("base"), device_get_config_int("irq"), device_get_config_int("mode")); - return(mpu); + if (info->flags & DEVICE_MCA) { + mca_add(mpu401_mca_read, mpu401_mca_write, mpu401_mca_feedb, mpu); + mpu->pos_regs[0] = 0x0F; + mpu->pos_regs[1] = 0x6C; + base = 0; /* Tell mpu401_init() that this is the MCA variant. */ + irq = 2; /* According to @6c0f.adf, the IRQ is fixed to 2. */ + } else { + base = device_get_config_hex16("base"); + irq = device_get_config_int("irq"); + } + + input_msg = MPU401_InputMsg; + input_sysex = MPU401_InputSysex; + midi_in_p = mpu; + + mpu401_init(mpu, base, irq, M_INTELLIGENT); + + return(mpu); } @@ -953,20 +1719,6 @@ static const device_config_t mpu401_standalone_config[] = } } }, - { - "mode", "Mode", CONFIG_SELECTION, "", 1, - { - { - "UART", M_UART - }, - { - "Intelligent", M_INTELLIGENT - }, - { - "" - } - } - }, { "", "", -1 } @@ -974,11 +1726,21 @@ static const device_config_t mpu401_standalone_config[] = const device_t mpu401_device = { - "MPU-401 (Standalone)", - 0, 0, + "Roland MPU-IPC-T", + DEVICE_ISA, 0, mpu401_standalone_init, mpu401_standalone_close, NULL, NULL, NULL, NULL, mpu401_standalone_config }; + +const device_t mpu401_mca_device = { + "Roland MPU-IMC", + DEVICE_MCA, 0, + mpu401_standalone_init, mpu401_standalone_close, NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound/snd_mpu401.h b/src/sound/snd_mpu401.h index 0dda1b25a..ce2ce54bf 100644 --- a/src/sound/snd_mpu401.h +++ b/src/sound/snd_mpu401.h @@ -8,7 +8,7 @@ * * Roland MPU-401 emulation. * - * Version: @(#)sound_mpu401.h 1.0.1 2018/03/18 + * Version: @(#)sound_mpu401.h 1.0.4 2018/09/31 * * Author: Sarah Walker, * DOSBox Team, @@ -22,12 +22,39 @@ #define MPU401_VERSION 0x15 #define MPU401_REVISION 0x01 -#define MPU401_QUEUE 32 +#define MPU401_QUEUE 64 +#define MPU401_INPUT_QUEUE 1024 #define MPU401_TIMECONSTANT (60000000/1000.0f) #define MPU401_RESETBUSY 27.0f -typedef enum MpuMode { M_UART,M_INTELLIGENT } MpuMode; -typedef enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND} MpuDataType; +/*helpers*/ +#define M_GETKEY key[key/32]&(1<<(key%32)) +#define M_SETKEY key[key/32]|=(1<<(key%32)) +#define M_DELKEY key[key/32]&=~(1<<(key%32)) + +typedef enum MpuMode +{ + M_UART, + M_INTELLIGENT +} MpuMode; + +#define M_MCA 0x10 + +typedef enum MpuDataType +{ + T_OVERFLOW, + T_MARK, + T_MIDI_SYS, + T_MIDI_NORM, + T_COMMAND +} MpuDataType; + +typedef enum RecState +{ + M_RECOFF, + M_RECSTB, + M_RECON +} RecState; /* Messages sent to MPU-401 from host */ #define MSG_EOX 0xf7 @@ -43,52 +70,83 @@ typedef enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND} Mp typedef struct mpu_t { - int uart_mode; - uint8_t rx_data; - int intelligent; - MpuMode mode; - int irq; - uint8_t status; - uint8_t queue[MPU401_QUEUE]; - int queue_pos,queue_used; - struct track - { - int counter; - uint8_t value[8],sys_val; - uint8_t vlength,length; - MpuDataType type; - } playbuf[8],condbuf; + int midi_thru; + int uart_mode, intelligent, + irq, + queue_pos, queue_used; + uint8_t rx_data, is_mca, + status, + queue[MPU401_QUEUE], pos_regs[8]; + MpuMode mode; + uint8_t rec_queue[MPU401_INPUT_QUEUE]; + int rec_queue_pos, rec_queue_used; + uint32_t ch_toref[16]; + struct track + { + int counter; + uint8_t value[3], sys_val, + vlength,length; + MpuDataType type; + } playbuf[8], condbuf; + struct { + int conductor, cond_req, + cond_set, block_ack, + playing, reset, + wsd, wsm, wsd_start, + run_irq, irq_pending, + track_req, + send_now, eoi_scheduled, + data_onoff, clock_to_host, + sync_in, sysex_in_finished, + rec_copy; + RecState rec; + uint8_t tmask, cmask, + amask, + last_rtcmd; + uint16_t midi_mask, req_mask; + uint32_t command_byte, cmd_pending, + track, old_track; + } state; + struct { + uint8_t timebase, old_timebase, + tempo, old_tempo, + tempo_rel, old_tempo_rel, + tempo_grad, cth_rate[4], + cth_mode, midimetro, + metromeas; + uint32_t cth_counter, cth_old, + rec_counter; + int32_t measure_counter, meas_old, + freq; + int ticks_in, active; + float freq_mod; + } clock; struct { - int conductor,cond_req,cond_set, block_ack; - int playing,reset; - int wsd,wsm,wsd_start; - int run_irq,irq_pending; - int send_now; - int eoi_scheduled; - int data_onoff; - uint32_t command_byte,cmd_pending; - uint8_t tmask,cmask,amask; - uint16_t midi_mask; - uint16_t req_mask; - uint8_t channel,old_chan; - } state; + int all_thru, midi_thru, + sysex_thru, commonmsgs_thru, + modemsgs_in, commonmsgs_in, + bender_in, sysex_in, + allnotesoff_out, rt_affection, + rt_out, rt_in, + timing_in_stop, data_in_stop, + rec_measure_end; + uint8_t prchg_buf[16]; + uint16_t prchg_mask; + } filter; struct { - uint8_t timebase,old_timebase; - uint8_t tempo,old_tempo; - uint8_t tempo_rel,old_tempo_rel; - uint8_t tempo_grad; - uint8_t cth_rate,cth_counter; - int clock_to_host,cth_active; - } clock; + int on; + uint8_t chan, trmask; + uint32_t key[4]; + } chanref[5], inputref[16]; + pc_timer_t mpu401_event_callback, mpu401_eoi_callback, + mpu401_reset_callback; } mpu_t; -uint8_t MPU401_ReadData(mpu_t *mpu); +extern int mpu401_standalone_enable; +extern const device_t mpu401_device; +extern const device_t mpu401_mca_device; -void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode); -extern int mpu401_standalone_enable; - -void mpu401_device_add(void); -const device_t mpu401_device; - -void mpu401_uart_init(mpu_t *mpu, uint16_t addr); +extern uint8_t MPU401_ReadData(mpu_t *mpu); +extern void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode); +extern void mpu401_device_add(void); diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index 3daea480b..437ea62b5 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -12,70 +12,93 @@ #include "../timer.h" #include "sound.h" #include "snd_opl.h" -#include "snd_dbopl.h" +#include "snd_opl_backend.h" /*Interfaces between 86Box and the actual OPL emulator*/ -uint8_t opl2_read(uint16_t a, void *priv) +uint8_t +opl2_read(uint16_t a, void *priv) { - opl_t *opl = (opl_t *)priv; + opl_t *opl = (opl_t *)priv; - cycles -= (int)(isa_timing * 8); - opl2_update2(opl); - return opl_read(0, a); -} -void opl2_write(uint16_t a, uint8_t v, void *priv) -{ - opl_t *opl = (opl_t *)priv; + sub_cycles((int) (isa_timing * 8)); + opl2_update2(opl); - opl2_update2(opl); - opl_write(0, a, v); - opl_write(1, a, v); + return opl_read(0, a); } -uint8_t opl2_l_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; - cycles -= (int)(isa_timing * 8); - opl2_update2(opl); - return opl_read(0, a); -} -void opl2_l_write(uint16_t a, uint8_t v, void *priv) +void +opl2_write(uint16_t a, uint8_t v, void *priv) { - opl_t *opl = (opl_t *)priv; + opl_t *opl = (opl_t *)priv; - opl2_update2(opl); - opl_write(0, a, v); + opl2_update2(opl); + opl_write(0, a, v); + opl_write(1, a, v); } -uint8_t opl2_r_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; - cycles -= (int)(isa_timing * 8); - opl2_update2(opl); - return opl_read(1, a); -} -void opl2_r_write(uint16_t a, uint8_t v, void *priv) +uint8_t +opl2_l_read(uint16_t a, void *priv) { - opl_t *opl = (opl_t *)priv; + opl_t *opl = (opl_t *)priv; - opl2_update2(opl); - opl_write(1, a, v); + sub_cycles((int)(isa_timing * 8)); + opl2_update2(opl); + + return opl_read(0, a); } -uint8_t opl3_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; - cycles -= (int)(isa_timing * 8); - opl3_update2(opl); - return opl_read(0, a); +void +opl2_l_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(0, a, v); } -void opl3_write(uint16_t a, uint8_t v, void *priv) + + +uint8_t +opl2_r_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + sub_cycles((int)(isa_timing * 8)); + opl2_update2(opl); + + return opl_read(1, a); +} + + +void +opl2_r_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(1, a, v); +} + + +uint8_t +opl3_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + sub_cycles((int)(isa_timing * 8)); + opl3_update2(opl); + + return opl_read(0, a); +} + + +void +opl3_write(uint16_t a, uint8_t v, void *priv) { opl_t *opl = (opl_t *)priv; @@ -84,102 +107,116 @@ void opl3_write(uint16_t a, uint8_t v, void *priv) } -void opl2_update2(opl_t *opl) +void +opl2_update2(opl_t *opl) { - if (opl->pos < sound_pos_global) - { - opl2_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); - opl2_update(1, &opl->buffer[opl->pos*2 + 1], sound_pos_global - opl->pos); - for (; opl->pos < sound_pos_global; opl->pos++) - { - opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); - opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); - } - } + if (opl->pos < sound_pos_global) { + opl2_update(0, &opl->buffer[opl->pos << 1], sound_pos_global - opl->pos); + opl2_update(1, &opl->buffer2[opl->pos << 1], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) { + opl->buffer[(opl->pos << 1) + 1] = opl->buffer2[(opl->pos << 1) + 1]; + opl->filtbuf[0] = opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2); + opl->filtbuf[1] = opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2); + } + } } -void opl3_update2(opl_t *opl) + +void +opl3_update2(opl_t *opl) { - if (opl->pos < sound_pos_global) - { - opl3_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); - for (; opl->pos < sound_pos_global; opl->pos++) - { - opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); - opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); - } - } + if (opl->pos < sound_pos_global) { + opl3_update(0, &opl->buffer[(opl->pos << 1)], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) { + opl->filtbuf[0] = opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2); + opl->filtbuf[1] = opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2); + } + } } -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 * 20LL; - if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; - opl->timers_enable[0][timer] = period ? 1 : 0; -} -void ym3812_timer_set_1(void *param, int timer, int64_t period) -{ - opl_t *opl = (opl_t *)param; - opl->timers[1][timer] = period * TIMER_USEC * 20LL; - if (!opl->timers[1][timer]) opl->timers[1][timer] = 1; - opl->timers_enable[1][timer] = period ? 1 : 0; +void +ym3812_timer_set_0(void *param, int timer, uint64_t period) +{ + opl_t *opl = (opl_t *)param; + + if (period) + timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[0][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 * 20LL; - if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; - opl->timers_enable[0][timer] = period ? 1 : 0; +void +ym3812_timer_set_1(void *param, int timer, uint64_t period) +{ + opl_t *opl = (opl_t *)param; + + if (period) + timer_set_delay_u64(&opl->timers[1][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[1][timer]); } -static void opl_timer_callback00(void *p) + +void +ymf262_timer_set(void *param, int timer, uint64_t period) { - 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_t *opl = (opl_t *)param; + + if (period) + timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[0][timer]); } -void opl3_init(opl_t *opl) + +static void +opl_timer_callback00(void *p) { - 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_timer_over(0, 0); } + +static void +opl_timer_callback01(void *p) +{ + opl_timer_over(0, 1); +} + + +static void +opl_timer_callback10(void *p) +{ + opl_timer_over(1, 0); +} + + +static void +opl_timer_callback11(void *p) +{ + 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->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) +{ + opl_init(ymf262_timer_set, opl, 0, 1); + + 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/snd_opl.h b/src/sound/snd_opl.h index e99f716f9..aff429e77 100644 --- a/src/sound/snd_opl.h +++ b/src/sound/snd_opl.h @@ -3,31 +3,30 @@ */ typedef struct opl_t { - int chip_nr[2]; - - int64_t timers[2][2]; - int64_t timers_enable[2][2]; + int pos, chip_nr[2]; - int16_t filtbuf[2]; + int32_t filtbuf[2], + buffer[SOUNDBUFLEN * 2], + buffer2[SOUNDBUFLEN * 2]; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; + pc_timer_t timers[2][2]; } opl_t; -uint8_t opl2_read(uint16_t a, void *priv); -void opl2_write(uint16_t a, uint8_t v, void *priv); -uint8_t opl2_l_read(uint16_t a, void *priv); -void opl2_l_write(uint16_t a, uint8_t v, void *priv); -uint8_t opl2_r_read(uint16_t a, void *priv); -void opl2_r_write(uint16_t a, uint8_t v, void *priv); -uint8_t opl3_read(uint16_t a, void *priv); -void opl3_write(uint16_t a, uint8_t v, void *priv); -void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); -void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +extern uint8_t opl2_read(uint16_t a, void *priv); +extern void opl2_write(uint16_t a, uint8_t v, void *priv); +extern uint8_t opl2_l_read(uint16_t a, void *priv); +extern void opl2_l_write(uint16_t a, uint8_t v, void *priv); +extern uint8_t opl2_r_read(uint16_t a, void *priv); +extern void opl2_r_write(uint16_t a, uint8_t v, void *priv); +extern uint8_t opl3_read(uint16_t a, void *priv); +extern void opl3_write(uint16_t a, uint8_t v, void *priv); -void opl2_init(opl_t *opl); -void opl3_init(opl_t *opl); +extern void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +extern void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); -void opl2_update2(opl_t *opl); -void opl3_update2(opl_t *opl); +extern void opl2_init(opl_t *opl); +extern void opl3_init(opl_t *opl); + +extern void opl2_update2(opl_t *opl); +extern void opl3_update2(opl_t *opl); diff --git a/src/sound/snd_opl_backend.c b/src/sound/snd_opl_backend.c new file mode 100644 index 000000000..0a0e08d8e --- /dev/null +++ b/src/sound/snd_opl_backend.c @@ -0,0 +1,147 @@ +/* Copyright holders: Sarah Walker, SA1988 + see COPYING for more details +*/ +#include "nukedopl.h" +#include "sound.h" +#include "snd_opl_backend.h" + + +int opl_type = 0; + + +static struct +{ + struct opl3_chip opl3chip; + int addr; + int timer[2]; + uint8_t timer_ctrl; + uint8_t status_mask; + uint8_t status; + int is_opl3; + + void (*timer_callback)(void *param, int timer, uint64_t period); + void *timer_param; +} opl[2]; + + +enum +{ + STATUS_TIMER_1 = 0x40, + STATUS_TIMER_2 = 0x20, + STATUS_TIMER_ALL = 0x80 +}; + +enum +{ + CTRL_IRQ_RESET = 0x80, + CTRL_TIMER1_MASK = 0x40, + CTRL_TIMER2_MASK = 0x20, + CTRL_TIMER2_CTRL = 0x02, + CTRL_TIMER1_CTRL = 0x01 +}; + + +void +opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3) +{ + opl[nr].timer_callback = timer_callback; + opl[nr].timer_param = timer_param; + opl[nr].is_opl3 = is_opl3; + + opl[nr].opl3chip.newm = 0; + OPL3_Reset(&opl[nr].opl3chip, 48000); +} + + +void +opl_status_update(int nr) +{ + if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask) + opl[nr].status |= STATUS_TIMER_ALL; + else + opl[nr].status &= ~STATUS_TIMER_ALL; +} + + +void +opl_timer_over(int nr, int timer) +{ + if (!timer) { + opl[nr].status |= STATUS_TIMER_1; + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + } else { + opl[nr].status |= STATUS_TIMER_2; + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + } + + opl_status_update(nr); +} + + +void +opl_write(int nr, uint16_t addr, uint8_t val) +{ + if (!(addr & 1)) { + opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; + if (!opl[nr].is_opl3) + opl[nr].addr &= 0xff; + } else { + OPL3_WriteRegBuffered(&opl[nr].opl3chip, (uint16_t) opl[nr].addr, val); + if (opl[nr].addr == 0x105) + opl[nr].opl3chip.newm = opl[nr].addr & 0x01; + + switch (opl[nr].addr) { + case 0x02: /*Timer 1*/ + opl[nr].timer[0] = 256 - val; + break; + case 0x03: /*Timer 2*/ + opl[nr].timer[1] = 256 - val; + break; + case 0x04: /*Timer control*/ + if (val & CTRL_IRQ_RESET) { /*IRQ reset*/ + opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); + opl_status_update(nr); + return; + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL) { + if (val & CTRL_TIMER1_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + else + opl[nr].timer_callback(opl[nr].timer_param, 0, 0); + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL) { + if (val & CTRL_TIMER2_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + else + opl[nr].timer_callback(opl[nr].timer_param, 1, 0); + } + opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; + opl[nr].timer_ctrl = val; + break; + } + } +} + + +uint8_t +opl_read(int nr, uint16_t addr) +{ + if (!(addr & 1)) + return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06); + + return opl[nr].is_opl3 ? 0 : 0xff; +} + + +void +opl2_update(int nr, int32_t *buffer, int samples) +{ + OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); +} + + +void +opl3_update(int nr, int32_t *buffer, int samples) +{ + OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); +} diff --git a/src/sound/snd_dbopl.h b/src/sound/snd_opl_backend.h similarity index 66% rename from src/sound/snd_dbopl.h rename to src/sound/snd_opl_backend.h index ca6299724..24120d036 100644 --- a/src/sound/snd_dbopl.h +++ b/src/sound/snd_opl_backend.h @@ -4,12 +4,12 @@ #ifdef __cplusplus extern "C" { #endif - void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3); + void opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3); void opl_write(int nr, uint16_t addr, uint8_t val); uint8_t opl_read(int nr, uint16_t addr); void opl_timer_over(int nr, int timer); - void opl2_update(int nr, int16_t *buffer, int samples); - void opl3_update(int nr, int16_t *buffer, int samples); + void opl2_update(int nr, int32_t *buffer, int samples); + void opl3_update(int nr, int32_t *buffer, int samples); extern int opl_type; #ifdef __cplusplus diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index e93bdfcb6..e10387df0 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -9,9 +9,9 @@ #include "../cpu/cpu.h" #include "../io.h" #include "../pic.h" +#include "../timer.h" #include "../pit.h" #include "../dma.h" -#include "../timer.h" #include "../device.h" #include "sound.h" #include "filters.h" @@ -128,6 +128,7 @@ typedef struct pas16_t { uint32_t l[3]; int64_t c[3]; + pc_timer_t timer[3]; uint8_t m[3]; uint8_t ctrl, ctrls[2]; int wp, rm[3], wm[3]; @@ -181,13 +182,11 @@ enum #ifdef ENABLE_PAS16_LOG int pas16_do_log = ENABLE_PAS16_LOG; -#endif static void pas16_log(const char *fmt, ...) { -#ifdef ENABLE_PAS16_LOG va_list ap; if (pas16_do_log) { @@ -195,16 +194,16 @@ pas16_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define pas16_log(fmt, ...) +#endif static uint8_t pas16_in(uint16_t port, void *p) { pas16_t *pas16 = (pas16_t *)p; - uint8_t temp; -/* if (CS == 0xCA53 && pc == 0x3AFC) - fatal("here");*/ + uint8_t temp = 0xff; switch ((port - pas16->base) + 0x388) { case 0x388: case 0x389: case 0x38a: case 0x38b: @@ -290,27 +289,15 @@ static uint8_t pas16_in(uint16_t port, void *p) case 0xff8b: /*Master mode read*/ temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/ break; - - default: - temp = 0xff; - break; } -/* if (port != 0x388 && port != 0x389 && port != 0xb8b) */pas16_log("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,cpu_state.pc); -/* if (CS == 0x1FF4 && pc == 0x0585) - { - if (output) - fatal("here"); - output = 3; - }*/ + pas16_log("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,cpu_state.pc); return temp; } static void pas16_out(uint16_t port, uint8_t val, void *p) { pas16_t *pas16 = (pas16_t *)p; -/* if (port != 0x388 && port != 0x389) */pas16_log("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); -/* if (CS == 0x369 && pc == 0x2AC5) - fatal("here\n");*/ + pas16_log("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); switch ((port - pas16->base) + 0x388) { case 0x388: case 0x389: case 0x38a: case 0x38b: @@ -415,8 +402,6 @@ static void pas16_out(uint16_t port, uint8_t val, void *p) fatal("here\n"); output = 3; } -/* if (CS == 0x1FF4 && pc == 0x0431) - output = 3;*/ } static void pas16_pit_out(uint16_t port, uint8_t val, void *p) @@ -430,7 +415,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]; } @@ -440,16 +425,19 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.ctrls[t] = pas16->pit.ctrl = val; if (t == 3) { - pas16_log("PAS16: bad PIT reg select\n"); + printf("Bad PIT reg select\n"); return; } if (!(pas16->pit.ctrl & 0x30)) { - pas16->pit.rl[t] = pas16->pit.c[t]; - if (!t) - pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); - if (pas16->pit.c[t] < 0) - pas16->pit.rl[t] = 0; + 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; @@ -463,9 +451,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; } @@ -481,7 +470,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: @@ -489,7 +478,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: @@ -497,7 +486,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; @@ -513,7 +502,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; } @@ -532,8 +521,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 @@ -585,13 +574,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; } @@ -755,7 +743,7 @@ static void *pas16_init(const device_t *info) 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/snd_pssj.c b/src/sound/snd_pssj.c index 1b6af8caf..8714c540c 100644 --- a/src/sound/snd_pssj.c +++ b/src/sound/snd_pssj.c @@ -25,8 +25,8 @@ typedef struct pssj_t int amplitude; int irq; - int64_t timer_count; - int64_t enable; + pc_timer_t timer_count; + int enable; int wave_pos; int pulse_width; @@ -49,7 +49,11 @@ 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_count, (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_count); sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); if (!(val & 8)) pssj->irq = 0; @@ -168,7 +172,7 @@ static void pssj_callback(void *p) pssj->wave_pos = (pssj->wave_pos + 1) & 31; } - pssj->timer_count += (int64_t)(TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400)); + timer_advance_u64(&pssj->timer_count, (TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400))); } static void pssj_get_buffer(int32_t *buffer, int len, void *p) @@ -192,7 +196,7 @@ void *pssj_init(const device_t *info) 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_count, pssj_callback, pssj, pssj->enable); sound_add_handler(pssj_get_buffer, pssj); return pssj; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index c2831ece9..f86e85cd9 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -8,14 +8,14 @@ * * Sound Blaster emulation. * - * Version: @(#)sound_sb.c 1.0.9 2018/04/29 + * Version: @(#)sound_sb.c 1.0.16 2019/09/27 * * Authors: Sarah Walker, * Miran Grca, * TheCollector1995, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -26,13 +26,14 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mca.h" #include "../mem.h" #include "../rom.h" #include "../device.h" #include "sound.h" +#include "midi.h" #include "filters.h" -#include "snd_dbopl.h" #include "snd_emu8k.h" #include "snd_mpu401.h" #include "snd_opl.h" @@ -134,11 +135,8 @@ typedef struct sb_t sb_ct1345_mixer_t mixer_sbpro; sb_ct1745_mixer_t mixer_sb16; }; - mpu_t mpu; + mpu_t *mpu; emu8k_t emu8k; -#if 0 - sb_ct1745_mixer_t temp_mixer_sb16; -#endif int pos; @@ -173,13 +171,11 @@ const int32_t sb_att_7dbstep_2bits[]= #ifdef ENABLE_SB_LOG int sb_do_log = ENABLE_SB_LOG; -#endif static void sb_log(const char *fmt, ...) { -#ifdef ENABLE_SB_LOG va_list ap; if (sb_do_log) { @@ -187,8 +183,10 @@ sb_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define sb_log(fmt, ...) +#endif /* sb 1, 1.5, 2, 2 mvc do not have a mixer, so signal is hardwired */ @@ -205,7 +203,7 @@ static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) { int32_t out = 0; if (sb->opl_enabled) - out = ((sb->opl.buffer[c] * 51000) >> 16); + out = ((sb->opl.buffer[c] * (sb->opl_emu ? 47000 : 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; @@ -233,7 +231,7 @@ static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) int32_t out = 0; if (sb->opl_enabled) - out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * 51000) >> 15); + out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * (sb->opl_emu ? 47000 : 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; @@ -298,44 +296,6 @@ static void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) sb->dsp.pos = 0; } -// FIXME: See why this causes weird audio glitches in some situations. -#if 0 -static void sb_process_buffer_sb16(int32_t *buffer, int len, void *p) -{ - sb_t *sb = (sb_t *)p; - sb_ct1745_mixer_t *mixer = &sb->temp_mixer_sb16; - - int c; - - for (c = 0; c < len * 2; c += 2) - { - int32_t out_l = 0, out_r = 0; - - out_l = ((int32_t)(low_fir_sb16(0, (float)buffer[c]) * mixer->cd_l) / 3) >> 15; - out_r = ((int32_t)(low_fir_sb16(1, (float)buffer[c + 1]) * mixer->cd_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])); - } - - buffer[c] = (out_l << mixer->output_gain_L); - buffer[c + 1] = (out_r << mixer->output_gain_R); - } -} -#endif - static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; @@ -407,9 +367,6 @@ static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) sb->pos = 0; sb->opl.pos = 0; sb->dsp.pos = 0; -#if 0 - memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); -#endif } #ifdef SB_DSP_RECORD_DEBUG int old_dsp_rec_pos=0; @@ -520,9 +477,6 @@ static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) sb->opl.pos = 0; sb->dsp.pos = 0; sb->emu8k.pos = 0; -#if 0 - memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); -#endif } @@ -629,7 +583,7 @@ void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p) { /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ case 0x02: case 0x06: case 0x08: - mixer->regs[mixer->index+0x20]=((val&0xE) << 4)|(val&0xE) << 4; + mixer->regs[mixer->index+0x20]=((val&0xE) << 4)|(val&0xE); break; case 0x22: case 0x26: case 0x28: @@ -862,6 +816,7 @@ 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; + uint8_t temp; if (!(addr & 1)) return mixer->index; @@ -942,7 +897,10 @@ uint8_t sb_ct1745_mixer_read(uint16_t addr, void *p) 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; + temp = ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | 0x4000; + if (sb->mpu) + temp |= ((sb->mpu->state.irq_pending) ? 4 : 0); + return temp; /* TODO: creative drivers read and write on 0xFE and 0xFF. not sure what they are supposed to be. */ @@ -1006,6 +964,14 @@ void sb_mcv_write(int port, uint8_t val, void *p) } } +uint8_t sb_mcv_feedb(void *p) +{ + sb_t *sb = (sb_t *)p; + + return (sb->pos_regs[2] & 1); +} + + static int sb_pro_mcv_irqs[4] = {7, 5, 3, 3}; uint8_t sb_pro_mcv_read(int port, void *p) @@ -1069,7 +1035,6 @@ void *sb_1_init() 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_dsp_set_mpu(&sb->mpu); /* CMS I/O handler is activated on the dedicated sound_cms module DSP I/O handler is activated in sb_dsp_setaddr */ if (sb->opl_enabled) { @@ -1077,6 +1042,11 @@ void *sb_1_init() io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); } sound_add_handler(sb_get_buffer_sb2, sb); + + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; + return sb; } void *sb_15_init() @@ -1103,6 +1073,11 @@ void *sb_15_init() io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); } sound_add_handler(sb_get_buffer_sb2, sb); + + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; + return sb; } @@ -1121,12 +1096,16 @@ void *sb_mcv_init() 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_dsp_set_mpu(&sb->mpu); sound_add_handler(sb_get_buffer_sb2, sb); /* I/O handlers activated in sb_mcv_write */ - mca_add(sb_mcv_read, sb_mcv_write, sb); + mca_add(sb_mcv_read, sb_mcv_write, sb_mcv_feedb, sb); sb->pos_regs[0] = 0x84; sb->pos_regs[1] = 0x50; + + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; + return sb; } void *sb_2_init() @@ -1155,7 +1134,6 @@ void *sb_2_init() 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_dsp_set_mpu(&sb->mpu); 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 */ @@ -1175,6 +1153,10 @@ void *sb_2_init() else sound_add_handler(sb_get_buffer_sb2, sb); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; + return sb; } @@ -1197,7 +1179,6 @@ void *sb_pro_v1_init() 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_dsp_set_mpu(&sb->mpu); sb_ct1345_mixer_reset(sb); /* DSP I/O handler is activated in sb_dsp_setaddr */ if (sb->opl_enabled) { @@ -1209,6 +1190,10 @@ void *sb_pro_v1_init() 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); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; + return sb; } @@ -1231,7 +1216,6 @@ void *sb_pro_v2_init() 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_dsp_set_mpu(&sb->mpu); sb_ct1345_mixer_reset(sb); /* DSP I/O handler is activated in sb_dsp_setaddr */ if (sb->opl_enabled) { @@ -1242,6 +1226,10 @@ void *sb_pro_v2_init() 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); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; + return sb; } @@ -1263,10 +1251,14 @@ void *sb_pro_mcv_init() sound_add_handler(sb_get_buffer_sbpro, sb); /* I/O handlers activated in sb_pro_mcv_write */ - mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb); + mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb_mcv_feedb, sb); sb->pos_regs[0] = 0x03; sb->pos_regs[1] = 0x51; + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; + return sb; } @@ -1274,6 +1266,7 @@ void *sb_16_init() { sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); + uint16_t mpu_addr = device_get_config_hex16("base401"); memset(sb, 0, sizeof(sb_t)); sb->opl_enabled = device_get_config_int("opl"); @@ -1292,14 +1285,18 @@ void *sb_16_init() } 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); -#if 0 - sound_add_process_handler(sb_process_buffer_sb16, sb); -#endif - mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); - sb_dsp_set_mpu(&sb->mpu); -#if 0 - memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); -#endif + if (mpu_addr) { + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART); + sb_dsp_set_mpu(sb->mpu); + } else + sb->mpu = NULL; + + + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1313,6 +1310,7 @@ void *sb_awe32_init() { sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); + uint16_t mpu_addr = device_get_config_hex16("base401"); uint16_t emu_addr = device_get_config_hex16("emu_base"); int onboard_ram = device_get_config_int("onboard_ram"); memset(sb, 0, sizeof(sb_t)); @@ -1327,7 +1325,6 @@ void *sb_awe32_init() sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); - sb_dsp_set_mpu(&sb->mpu); sb_ct1745_mixer_reset(sb); if (sb->opl_enabled) { io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); @@ -1336,15 +1333,18 @@ void *sb_awe32_init() } 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); -#if 0 - sound_add_process_handler(sb_process_buffer_sb16, sb); -#endif - mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); - sb_dsp_set_mpu(&sb->mpu); + if (mpu_addr) { + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART); + sb_dsp_set_mpu(sb->mpu); + } else + sb->mpu = NULL; emu8k_init(&sb->emu8k, emu_addr, onboard_ram); -#if 0 - memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); -#endif + + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1567,6 +1567,9 @@ static const device_config_t sb_16_config[] = { "base401", "MPU-401 Address", CONFIG_HEX16, "", 0x330, { + { + "Disabled", 0 + }, { "0x300", 0x300 }, @@ -1598,32 +1601,6 @@ static const device_config_t sb_16_config[] = } } }, - { - "irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, - { - { - "IRQ 9", 9 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "" - } - } - }, { "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, { @@ -1658,20 +1635,6 @@ static const device_config_t sb_16_config[] = } } }, - { - "mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1, - { - { - "UART", M_UART - }, - { - "Intelligent", M_INTELLIGENT - }, - { - "" - } - } - }, { "opl", "Enable OPL", CONFIG_BINARY, "", 1 }, @@ -1725,6 +1688,9 @@ static const device_config_t sb_awe32_config[] = { "base401", "MPU-401 Address", CONFIG_HEX16, "", 0x330, { + { + "Disabled", 0 + }, { "0x300", 0x300 }, @@ -1756,32 +1722,6 @@ static const device_config_t sb_awe32_config[] = } } }, - { - "irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, - { - { - "IRQ 9", 9 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "" - } - } - }, { "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, { @@ -1816,20 +1756,6 @@ static const device_config_t sb_awe32_config[] = } } }, - { - "mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1, - { - { - "UART", M_UART - }, - { - "Intelligent", M_INTELLIGENT - }, - { - "" - } - } - }, { "onboard_ram", "Onboard RAM", CONFIG_SELECTION, "", 512, { diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index d4dbf15e1..dc40de587 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -25,6 +25,11 @@ #include "snd_sb.h" #include "snd_sb_dsp.h" + +#define ADPCM_4 1 +#define ADPCM_26 2 +#define ADPCM_2 3 + /*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 @@ -60,66 +65,69 @@ static int sb_commands[256]= -1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0 }; + char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x40d}; + /*These tables were 'borrowed' from DOSBox*/ - int8_t scaleMap4[64] = { - 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, - 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, - 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, - 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 - }; - uint8_t adjustMap4[64] = { - 0, 0, 0, 0, 0, 16, 16, 16, - 0, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 16, 16, 16, - 240, 0, 0, 0, 0, 0, 0, 0, - 240, 0, 0, 0, 0, 0, 0, 0 - }; +int8_t scaleMap4[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, + 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, + 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, + 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 +}; - int8_t scaleMap26[40] = { - 0, 1, 2, 3, 0, -1, -2, -3, - 1, 3, 5, 7, -1, -3, -5, -7, - 2, 6, 10, 14, -2, -6, -10, -14, - 4, 12, 20, 28, -4, -12, -20, -28, - 5, 15, 25, 35, -5, -15, -25, -35 - }; - uint8_t adjustMap26[40] = { - 0, 0, 0, 8, 0, 0, 0, 8, - 248, 0, 0, 8, 248, 0, 0, 8, - 248, 0, 0, 8, 248, 0, 0, 8, - 248, 0, 0, 8, 248, 0, 0, 8, - 248, 0, 0, 0, 248, 0, 0, 0 - }; +uint8_t adjustMap4[64] = { + 0, 0, 0, 0, 0, 16, 16, 16, + 0, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 0 +}; - int8_t scaleMap2[24] = { - 0, 1, 0, -1, 1, 3, -1, -3, - 2, 6, -2, -6, 4, 12, -4, -12, - 8, 24, -8, -24, 6, 48, -16, -48 - }; - uint8_t adjustMap2[24] = { - 0, 4, 0, 4, - 252, 4, 252, 4, 252, 4, 252, 4, - 252, 4, 252, 4, 252, 4, 252, 4, - 252, 0, 252, 0 - }; +int8_t scaleMap26[40] = { + 0, 1, 2, 3, 0, -1, -2, -3, + 1, 3, 5, 7, -1, -3, -5, -7, + 2, 6, 10, 14, -2, -6, -10, -14, + 4, 12, 20, 28, -4, -12, -20, -28, + 5, 15, 25, 35, -5, -15, -25, -35 +}; + +uint8_t adjustMap26[40] = { + 0, 0, 0, 8, 0, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 0, 248, 0, 0, 0 +}; + +int8_t scaleMap2[24] = { + 0, 1, 0, -1, 1, 3, -1, -3, + 2, 6, -2, -6, 4, 12, -4, -12, + 8, 24, -8, -24, 6, 48, -16, -48 +}; + +uint8_t adjustMap2[24] = { + 0, 4, 0, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 0, 252, 0 +}; float low_fir_sb16_coef[SB16_NCoef]; #ifdef ENABLE_SB_DSP_LOG int sb_dsp_do_log = ENABLE_SB_DSP_LOG; -#endif static void sb_dsp_log(const char *fmt, ...) { -#ifdef ENABLE_SB_DSP_LOG va_list ap; if (sb_dsp_do_log) { @@ -127,1018 +135,1174 @@ sb_dsp_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define sb_dsp_log(fmt, ...) #endif + + +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; + double w, h; + + for (n = 0; n < SB16_NCoef; n++) { + /* Blackman window */ + 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 */ + 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; } -static inline double sinc(double x) +void +sb_irq(sb_dsp_t *dsp, int irq8) { - return sin(M_PI * x) / (M_PI * x); -} + sb_dsp_log("IRQ %i %02X\n", irq8, pic.mask); + if (irq8) + dsp->sb_irq8 = 1; + else + dsp->sb_irq16 = 1; -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; + picint(1 << dsp->sb_irqnum); } -void sb_irq(sb_dsp_t *dsp, int irq8) +void +sb_irqc(sb_dsp_t *dsp, int irq8) { - sb_dsp_log("IRQ %i %02X\n",irq8,pic.mask); - if (irq8) dsp->sb_irq8 = 1; - else dsp->sb_irq16 = 1; - picint(1 << dsp->sb_irqnum); -} -void sb_irqc(sb_dsp_t *dsp, int irq8) -{ - if (irq8) dsp->sb_irq8 = 0; - else dsp->sb_irq16 = 0; - picintc(1 << dsp->sb_irqnum); + if (irq8) + dsp->sb_irq8 = 0; + else + dsp->sb_irq16 = 0; + + picintc(1 << dsp->sb_irqnum); } -void sb_dsp_reset(sb_dsp_t *dsp) + +void +sb_dsp_reset(sb_dsp_t *dsp) { - dsp->sbenable = dsp->sb_enable_i = 0; - dsp->sb_command = 0; - - dsp->sb_8_length = 0xffff; - dsp->sb_8_autolen = 0xffff; - - sb_irqc(dsp, 0); - sb_irqc(dsp, 1); - dsp->sb_16_pause = 0; - dsp->sb_read_wp = dsp->sb_read_rp = 0; - dsp->sb_data_stat = -1; - dsp->sb_speaker = 0; - dsp->sb_pausetime = -1LL; - dsp->sbe2 = 0xAA; - dsp->sbe2count = 0; + midi_clear_buffer(); + + timer_disable(&dsp->output_timer); + timer_disable(&dsp->input_timer); - dsp->sbreset = 0; - dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0; + dsp->sb_command = 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; + dsp->sb_8_length = 0xffff; + dsp->sb_8_autolen = 0xffff; + + sb_irqc(dsp, 0); + sb_irqc(dsp, 1); + dsp->sb_16_pause = 0; + dsp->sb_read_wp = dsp->sb_read_rp = 0; + dsp->sb_data_stat = -1; + dsp->sb_speaker = 0; + dsp->sb_pausetime = -1LL; + dsp->sbe2 = 0xAA; + dsp->sbe2count = 0; + + dsp->sbreset = 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; } -void sb_doreset(sb_dsp_t *dsp) + +void +sb_doreset(sb_dsp_t *dsp) { - int c; - - sb_dsp_reset(dsp); - - if (dsp->sb_type==SB16) sb_commands[8] = 1; - else sb_commands[8] = -1; - - for (c = 0; c < 256; c++) - dsp->sb_asp_regs[c] = 0; - dsp->sb_asp_regs[5] = 0x01; - dsp->sb_asp_regs[9] = 0xf8; + int c; + + sb_dsp_reset(dsp); + + if (dsp->sb_type==SB16) + sb_commands[8] = 1; + else + sb_commands[8] = -1; + + for (c = 0; c < 256; c++) + dsp->sb_asp_regs[c] = 0; + + dsp->sb_asp_regs[5] = 0x01; + dsp->sb_asp_regs[9] = 0xf8; } -void sb_dsp_speed_changed(sb_dsp_t *dsp) -{ - if (dsp->sb_timeo < 256LL) - dsp->sblatcho = TIMER_USEC * (256LL - dsp->sb_timeo); - else - dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256LL))); - if (dsp->sb_timei < 256LL) - dsp->sblatchi = TIMER_USEC * (256LL - dsp->sb_timei); - else - dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256LL))); +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 = (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 = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256))); } -void sb_add_data(sb_dsp_t *dsp, uint8_t v) + +void +sb_add_data(sb_dsp_t *dsp, uint8_t v) { - dsp->sb_read_data[dsp->sb_read_wp++] = v; - dsp->sb_read_wp &= 0xff; + dsp->sb_read_data[dsp->sb_read_wp++] = v; + dsp->sb_read_wp &= 0xff; } -#define ADPCM_4 1 -#define ADPCM_26 2 -#define ADPCM_2 3 -void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) +void +sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) { - dsp->sb_pausetime = -1LL; - if (dma8) - { - dsp->sb_8_length = len; - dsp->sb_8_format = format; - dsp->sb_8_autoinit = autoinit; - dsp->sb_8_pause = 0; - dsp->sb_8_enable = 1; - if (dsp->sb_16_enable && dsp->sb_16_output) dsp->sb_16_enable = 0; - dsp->sb_8_output = 1; - timer_process(); - dsp->sbenable = dsp->sb_8_enable; - timer_update_outstanding(); - dsp->sbleftright = 0; - dsp->sbdacpos = 0; - } - else - { - dsp->sb_16_length = len; - dsp->sb_16_format = format; - dsp->sb_16_autoinit = autoinit; - dsp->sb_16_pause = 0; - dsp->sb_16_enable = 1; - if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0; - dsp->sb_16_output = 1; - timer_process(); - dsp->sbenable = dsp->sb_16_enable; - timer_update_outstanding(); - } + dsp->sb_pausetime = -1; + + if (dma8) { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + + if (dsp->sb_16_enable && dsp->sb_16_output) + dsp->sb_16_enable = 0; + dsp->sb_8_output = 1; + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); + dsp->sbleftright = 0; + dsp->sbdacpos = 0; + } else { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0; + dsp->sb_16_output = 1; + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); + } } -void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) + +void +sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) { - if (dma8) - { - dsp->sb_8_length = len; - dsp->sb_8_format = format; - dsp->sb_8_autoinit = autoinit; - dsp->sb_8_pause = 0; - dsp->sb_8_enable = 1; - if (dsp->sb_16_enable && !dsp->sb_16_output) dsp->sb_16_enable = 0; - dsp->sb_8_output = 0; - timer_process(); - dsp->sb_enable_i = dsp->sb_8_enable; - timer_update_outstanding(); - } - else - { - dsp->sb_16_length = len; - dsp->sb_16_format = format; - dsp->sb_16_autoinit = autoinit; - dsp->sb_16_pause = 0; - dsp->sb_16_enable = 1; - if (dsp->sb_8_enable && !dsp->sb_8_output) dsp->sb_8_enable = 0; - dsp->sb_16_output = 0; - timer_process(); - dsp->sb_enable_i = dsp->sb_16_enable; - timer_update_outstanding(); - } - memset(dsp->record_buffer,0,sizeof(dsp->record_buffer)); + if (dma8) { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && !dsp->sb_16_output) + dsp->sb_16_enable = 0; + dsp->sb_8_output = 0; + if (!timer_is_enabled(&dsp->input_timer)) + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); + } else { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && !dsp->sb_8_output) + dsp->sb_8_enable = 0; + dsp->sb_16_output = 0; + if (!timer_is_enabled(&dsp->input_timer)) + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); + } + + memset(dsp->record_buffer,0,sizeof(dsp->record_buffer)); } -int sb_8_read_dma(sb_dsp_t *dsp) + +int +sb_8_read_dma(sb_dsp_t *dsp) { - return dma_channel_read(dsp->sb_8_dmanum); -} -void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) -{ - dma_channel_write(dsp->sb_8_dmanum, val); -} -int sb_16_read_dma(sb_dsp_t *dsp) -{ - return dma_channel_read(dsp->sb_16_dmanum); -} -int sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) -{ - int ret = dma_channel_write(dsp->sb_16_dmanum, val); - return (ret == DMA_NODATA); + return dma_channel_read(dsp->sb_8_dmanum); } -void sb_dsp_setirq(sb_dsp_t *dsp, int irq) + +void +sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) { - dsp->sb_irqnum = irq; + dma_channel_write(dsp->sb_8_dmanum, val); } -void sb_dsp_setdma8(sb_dsp_t *dsp, int dma) + +int +sb_16_read_dma(sb_dsp_t *dsp) { - dsp->sb_8_dmanum = dma; + return dma_channel_read(dsp->sb_16_dmanum); } -void sb_dsp_setdma16(sb_dsp_t *dsp, int dma) + +int +sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) { - dsp->sb_16_dmanum = dma; + int ret = dma_channel_write(dsp->sb_16_dmanum, val); + + return (ret == DMA_NODATA); } -void sb_exec_command(sb_dsp_t *dsp) + + +void +sb_dsp_setirq(sb_dsp_t *dsp, int irq) { - int temp,c; - sb_dsp_log("sb_exec_command : SB command %02X\n", dsp->sb_command); - switch (dsp->sb_command) - { - case 0x01: /*???*/ - if (dsp->sb_type < SB16) break; - dsp->asp_data_len = dsp->sb_data[0] + (dsp->sb_data[1] << 8) + 1; - break; - case 0x03: /*ASP status*/ - sb_add_data(dsp, 0); - break; - case 0x10: /*8-bit direct mode*/ - sb_dsp_update(dsp); - dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8; - break; - case 0x14: /*8-bit single cycle DMA output*/ - sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - break; - case 0x17: /*2-bit ADPCM output with reference*/ - dsp->sbref = sb_8_read_dma(dsp); - dsp->sbstep = 0; - case 0x16: /*2-bit ADPCM output*/ - sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - if (dsp->sb_command == 0x17) - dsp->sb_8_length--; - break; - case 0x1C: /*8-bit autoinit DMA output*/ - if (dsp->sb_type < SB15) break; - sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); - break; - case 0x1F: /*2-bit ADPCM autoinit output*/ - if (dsp->sb_type < SB15) break; - sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - break; - case 0x20: /*8-bit direct input*/ - sb_add_data(dsp, (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 (dsp->sb_enable_i==0) - { - dsp->sb_timei = 256LL - 22LL; - dsp->sblatchi = TIMER_USEC * 22LL; - temp = 1000000 / 22; - dsp->sb_freq = temp; - timer_process(); - dsp->sb_enable_i = 1; - timer_update_outstanding(); - } - break; - case 0x24: /*8-bit single cycle DMA input*/ - sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - break; - case 0x2C: /*8-bit autoinit DMA input*/ - if (dsp->sb_type < SB15) break; - sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - break; - case 0x30: - case 0x31: + dsp->sb_irqnum = irq; +} + + +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; + + sb_dsp_log("sb_exec_command : SB command %02X\n", dsp->sb_command); + + switch (dsp->sb_command) { + case 0x01: /* ???? */ + if (dsp->sb_type >= SB16) + dsp->asp_data_len = dsp->sb_data[0] + (dsp->sb_data[1] << 8) + 1; break; - case 0x34: + case 0x03: /* ASP status */ + sb_add_data(dsp, 0); + break; + case 0x10: /* 8-bit direct mode */ + sb_dsp_update(dsp); + dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8; + break; + case 0x14: /* 8-bit single cycle DMA output */ + sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x17: /* 2-bit ADPCM output with reference */ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; + /* Fall through */ + case 0x16: /* 2-bit ADPCM output */ + sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + if (dsp->sb_command == 0x17) + dsp->sb_8_length--; + break; + case 0x1C: /* 8-bit autoinit DMA output */ + if (dsp->sb_type >= SB15) + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x1F: /* 2-bit ADPCM autoinit output */ + if (dsp->sb_type >= SB15) { + sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + break; + case 0x20: /* 8-bit direct input */ + sb_add_data(dsp, (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)); + break; + case 0x2C: /* 8-bit autoinit DMA input */ + if (dsp->sb_type >= SB15) + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x30: /* MIDI Polling mode input */ + sb_dsp_log("MIDI polling mode input\n"); + dsp->midi_in_poll = 1; + dsp->uart_irq = 0; + break; + case 0x31: /* MIDI Interrupt mode input */ + sb_dsp_log("MIDI interrupt mode input\n"); + dsp->midi_in_poll = 0; + dsp->uart_irq = 1; + break; + case 0x34: /* MIDI In poll */ + if (dsp->sb_type < SB2) + break; + sb_dsp_log("MIDI poll in\n"); + dsp->midi_in_poll = 1; dsp->uart_midi = 1; dsp->uart_irq = 0; break; - case 0x35: + case 0x35: /* MIDI In irq */ + if (dsp->sb_type < SB2) + break; + sb_dsp_log("MIDI irq in\n"); + dsp->midi_in_poll = 0; dsp->uart_midi = 1; dsp->uart_irq = 1; break; - case 0x36: - case 0x37: + case 0x36: case 0x37: /* MIDI timestamps */ break; - case 0x38: + case 0x38: /* Write to SB MIDI Output (Raw) */ dsp->onebyte_midi = 1; break; - case 0x40: /*Set time constant*/ - dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0]; - dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); - temp = 256 - dsp->sb_data[0]; - temp = 1000000 / temp; - sb_dsp_log("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)))); - sb_dsp_log("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 = 256LL + 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); - break; - case 0x75: /*4-bit ADPCM output with reference*/ - dsp->sbref = sb_8_read_dma(dsp); - dsp->sbstep = 0; - case 0x74: /*4-bit ADPCM output*/ - sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - 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); - dsp->sbstep = 0; - case 0x76: /*2.6-bit ADPCM output*/ - sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - if (dsp->sb_command == 0x77) - dsp->sb_8_length--; - break; - case 0x7D: /*4-bit ADPCM autoinit output*/ - if (dsp->sb_type < SB15) break; - sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - break; - case 0x7F: /*2.6-bit ADPCM autoinit output*/ - if (dsp->sb_type < SB15) break; - sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - break; - case 0x80: /*Pause DAC*/ - dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); - timer_process(); - dsp->sbenable = 1; - timer_update_outstanding(); - break; - case 0x90: /*High speed 8-bit autoinit DMA output*/ - if (dsp->sb_type < SB2) break; - sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); - break; - case 0x91: /*High speed 8-bit single cycle DMA output*/ - if (dsp->sb_type < SB2) break; - sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen); - break; - case 0x98: /*High speed 8-bit autoinit DMA input*/ - if (dsp->sb_type < SB2) break; - sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen); - break; - case 0x99: /*High speed 8-bit single cycle DMA input*/ - if (dsp->sb_type < SB2) break; - sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); - break; - case 0xA0: /*Set input mode to mono*/ - case 0xA8: /*Set input mode to stereo*/ - 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*/ - if (dsp->sb_type < SB16) break; - sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); - dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); - break; - case 0xB8: case 0xB9: case 0xBA: case 0xBB: - case 0xBC: case 0xBD: case 0xBE: case 0xBF: /*16-bit DMA input*/ - if (dsp->sb_type < SB16) break; - sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); - dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); - break; - case 0xC0: case 0xC1: case 0xC2: case 0xC3: - case 0xC4: case 0xC5: case 0xC6: case 0xC7: /*8-bit DMA output*/ - if (dsp->sb_type < SB16) break; - sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); - dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); - break; - case 0xC8: case 0xC9: case 0xCA: case 0xCB: - case 0xCC: case 0xCD: case 0xCE: case 0xCF: /*8-bit DMA input*/ - if (dsp->sb_type < SB16) break; - sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); - dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); - break; - case 0xD0: /*Pause 8-bit DMA*/ - dsp->sb_8_pause = 1; - break; - case 0xD1: /*Speaker on*/ - 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*/ - dsp->sb_8_pause = 0; - break; - case 0xD5: /*Pause 16-bit DMA*/ - if (dsp->sb_type < SB16) break; - dsp->sb_16_pause = 1; - break; - case 0xD6: /*Continue 16-bit DMA*/ - if (dsp->sb_type < SB16) break; - dsp->sb_16_pause = 0; - break; - case 0xD8: /*Get speaker status*/ - sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0); - break; - case 0xD9: /*Exit 16-bit auto-init mode*/ - if (dsp->sb_type < SB16) break; - dsp->sb_16_autoinit = 0; - break; - case 0xDA: /*Exit 8-bit auto-init mode*/ - dsp->sb_8_autoinit = 0; - break; - case 0xE0: /*DSP identification*/ - sb_add_data(dsp, ~dsp->sb_data[0]); - break; - case 0xE1: /*Get DSP version*/ - sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); - sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); - break; - case 0xE2: /*Stupid ID/protection*/ - for (c = 0; c < 8; c++) - if (dsp->sb_data[0] & (1 << c)) dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c]; - dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8]; - dsp->sbe2count++; - sb_8_write_dma(dsp, dsp->sbe2); - break; - case 0xE3: /*DSP copyright*/ - if (dsp->sb_type < SB16) break; - c = 0; - while (sb16_copyright[c]) - sb_add_data(dsp, sb16_copyright[c++]); - sb_add_data(dsp, 0); - break; - case 0xE4: /*Write test register*/ - dsp->sb_test = dsp->sb_data[0]; - break; - case 0xE8: /*Read test register*/ - sb_add_data(dsp, dsp->sb_test); - break; - case 0xF2: /*Trigger 8-bit IRQ*/ - sb_dsp_log("Trigger IRQ\n"); - sb_irq(dsp, 1); - break; - case 0xF3: /*Trigger 16-bit IRQ*/ - sb_dsp_log("Trigger IRQ\n"); - sb_irq(dsp, 0); - break; - case 0xE7: /*???*/ - case 0xFA: /*???*/ - break; - case 0x07: /*No, that's not how you program auto-init DMA*/ - case 0xFF: - break; - case 0x08: /*ASP get version*/ - if (dsp->sb_type < SB16) break; - sb_add_data(dsp, 0x18); - break; - case 0x0E: /*ASP set register*/ - if (dsp->sb_type < SB16) break; - dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; - break; - case 0x0F: /*ASP get register*/ - if (dsp->sb_type < SB16) break; - sb_add_data(dsp, dsp->sb_asp_regs[dsp->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; - if (dsp->sb_data[0] == 0x0e) sb_add_data(dsp, 0xff); - else if (dsp->sb_data[0] == 0x0f) sb_add_data(dsp, 0x07); - else if (dsp->sb_data[0] == 0x37) sb_add_data(dsp, 0x38); - else sb_add_data(dsp, 0x00); - case 0x04: - case 0x05: - break; - - /*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 - */ - - } -} - -void sb_write(uint16_t a, uint8_t v, void *priv) -{ - sb_dsp_t *dsp = (sb_dsp_t *)priv; - switch (a&0xF) - { - case 6: /*Reset*/ - if (!(v & 1) && (dsp->sbreset & 1)) - { - sb_dsp_reset(dsp); - sb_add_data(dsp, 0xAA); - } - dsp->sbreset = v; - return; - case 0xC: /*Command/data write*/ - if (dsp->uart_midi || dsp->onebyte_midi) - { - midi_write(v); - dsp->onebyte_midi = 0; - return; - } - timer_process(); - dsp->wb_time = TIMER_USEC * 1LL; - dsp->wb_full = 1LL; - timer_update_outstanding(); - if (dsp->asp_data_len) - { - sb_dsp_log("ASP data %i\n", dsp->asp_data_len); - dsp->asp_data_len--; - if (!dsp->asp_data_len) - sb_add_data(dsp, 0); - return; - } - if (dsp->sb_data_stat == -1) - { - dsp->sb_command = v; - if (v == 0x01) - sb_add_data(dsp, 0); - dsp->sb_data_stat++; - } - else - dsp->sb_data[dsp->sb_data_stat++] = v; - if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) - { - sb_exec_command(dsp); - dsp->sb_data_stat = -1; - } - break; - } -} - -uint8_t sb_read(uint16_t a, void *priv) -{ - sb_dsp_t *dsp = (sb_dsp_t *)priv; - switch (a & 0xf) - { - case 0xA: /*Read data*/ - if (dsp->uart_midi) - { - return MPU401_ReadData(mpu); + case 0x40: /* Set time constant */ + dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0]; + dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); + temp = 256 - dsp->sb_data[0]; + temp = 1000000 / temp; + sb_dsp_log("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) { + dsp->sblatcho = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); + sb_dsp_log("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 = 256LL + 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); } - dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; - if (dsp->sb_read_rp != dsp->sb_read_wp) - { - dsp->sb_read_rp++; - dsp->sb_read_rp &= 0xFF; - } - return dsp->sbreaddat; - case 0xC: /*Write data ready*/ - 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; - } - return 0x7f; - case 0xE: /*Read data ready*/ - picintc(1 << dsp->sb_irqnum); - dsp->sb_irq8 = dsp->sb_irq16 = 0; - return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; - case 0xF: /*16-bit ack*/ - dsp->sb_irq16 = 0; - if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum); - return 0xff; + break; + case 0x48: /* Set DSP block transfer size */ + dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8); + break; + case 0x75: /* 4-bit ADPCM output with reference */ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; + /* Fall through */ + case 0x74: /* 4-bit ADPCM output */ + sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + 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); + dsp->sbstep = 0; + /* Fall through */ + case 0x76: /* 2.6-bit ADPCM output */ + sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + if (dsp->sb_command == 0x77) + dsp->sb_8_length--; + break; + case 0x7D: /* 4-bit ADPCM autoinit output */ + if (dsp->sb_type >= SB15) { + sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + break; + case 0x7F: /* 2.6-bit ADPCM autoinit output */ + if (dsp->sb_type >= SB15) { + sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + break; + case 0x80: /* Pause DAC */ + dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); + 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) + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x91: /* High speed 8-bit single cycle DMA output */ + if (dsp->sb_type >= SB2) + sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0x98: /* High speed 8-bit autoinit DMA input */ + if (dsp->sb_type >= SB2) + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x99: /* High speed 8-bit single cycle DMA input */ + if (dsp->sb_type >= SB2) + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0xA0: /* Set input mode to mono */ + case 0xA8: /* Set input mode to stereo */ + 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 */ + if (dsp->sb_type >= SB16) { + sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + } + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: + case 0xBC: case 0xBD: case 0xBE: case 0xBF: /* 16-bit DMA input */ + if (dsp->sb_type >= SB16) { + sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + } + break; + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC4: case 0xC5: case 0xC6: case 0xC7: /* 8-bit DMA output */ + if (dsp->sb_type >= SB16) { + sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + } + break; + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + case 0xCC: case 0xCD: case 0xCE: case 0xCF: /* 8-bit DMA input */ + if (dsp->sb_type >= SB16) { + sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + } + break; + case 0xD0: /* Pause 8-bit DMA */ + dsp->sb_8_pause = 1; + break; + case 0xD1: /* Speaker on */ + 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 */ + dsp->sb_8_pause = 0; + break; + case 0xD5: /* Pause 16-bit DMA */ + if (dsp->sb_type >= SB16) + dsp->sb_16_pause = 1; + break; + case 0xD6: /* Continue 16-bit DMA */ + if (dsp->sb_type >= SB16) + dsp->sb_16_pause = 0; + break; + case 0xD8: /* Get speaker status */ + sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0); + break; + case 0xD9: /* Exit 16-bit auto-init mode */ + if (dsp->sb_type >= SB16) + dsp->sb_16_autoinit = 0; + break; + case 0xDA: /* Exit 8-bit auto-init mode */ + dsp->sb_8_autoinit = 0; + break; + case 0xE0: /* DSP identification */ + sb_add_data(dsp, ~dsp->sb_data[0]); + break; + case 0xE1: /* Get DSP version */ + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); + break; + case 0xE2: /* Stupid ID/protection */ + for (c = 0; c < 8; c++) { + if (dsp->sb_data[0] & (1 << c)) + dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c]; + } + dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8]; + dsp->sbe2count++; + sb_8_write_dma(dsp, dsp->sbe2); + break; + case 0xE3: /* DSP copyright */ + if (dsp->sb_type >= SB16) { + c = 0; + while (sb16_copyright[c]) + sb_add_data(dsp, sb16_copyright[c++]); + sb_add_data(dsp, 0); + } + break; + case 0xE4: /* Write test register */ + dsp->sb_test = dsp->sb_data[0]; + break; + case 0xE8: /* Read test register */ + sb_add_data(dsp, dsp->sb_test); + break; + case 0xF2: /* Trigger 8-bit IRQ */ + sb_dsp_log("Trigger IRQ\n"); + sb_irq(dsp, 1); + break; + case 0xF3: /* Trigger 16-bit IRQ */ + sb_dsp_log("Trigger IRQ\n"); + sb_irq(dsp, 0); + break; + case 0xE7: case 0xFA: /* ???? */ + break; + case 0x07: case 0xFF: /* No, that's not how you program auto-init DMA */ + break; + case 0x08: /* ASP get version */ + if (dsp->sb_type >= SB16) + sb_add_data(dsp, 0x18); + break; + case 0x0E: /* ASP set register */ + if (dsp->sb_type >= SB16) + dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; + break; + case 0x0F: /* ASP get register */ + if (dsp->sb_type >= SB16) + sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]); + break; + case 0xF8: + if (dsp->sb_type < SB16) + sb_add_data(dsp, 0); + break; + case 0xF9: + if (dsp->sb_type >= SB16) { + if (dsp->sb_data[0] == 0x0e) + sb_add_data(dsp, 0xff); + else if (dsp->sb_data[0] == 0x0f) + sb_add_data(dsp, 0x07); + else if (dsp->sb_data[0] == 0x37) + sb_add_data(dsp, 0x38); + else + sb_add_data(dsp, 0x00); + } + case 0x04: case 0x05: + break; + + /* 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 + */ + } +} + + +void +sb_write(uint16_t a, uint8_t v, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *) priv; + + switch (a & 0xF) { + case 6: /* Reset */ + if (!dsp->uart_midi) { + if (!(v & 1) && (dsp->sbreset & 1)) { + sb_dsp_reset(dsp); + sb_add_data(dsp, 0xAA); + } + dsp->sbreset = v; + } + dsp->uart_midi = 0; + dsp->uart_irq = 0; + dsp->onebyte_midi = 0; + return; + case 0xC: /* Command/data write */ + if (dsp->uart_midi || dsp->onebyte_midi ) { + midi_raw_out_byte(v); + dsp->onebyte_midi = 0; + return; + } + timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1); + if (dsp->asp_data_len) { + sb_dsp_log("ASP data %i\n", dsp->asp_data_len); + dsp->asp_data_len--; + if (!dsp->asp_data_len) + sb_add_data(dsp, 0); + return; + } + if (dsp->sb_data_stat == -1) { + dsp->sb_command = v; + if (v == 0x01) + sb_add_data(dsp, 0); + dsp->sb_data_stat++; + } else + dsp->sb_data[dsp->sb_data_stat++] = v; + if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) { + sb_exec_command(dsp); + dsp->sb_data_stat = -1; + } + break; + } +} + + +uint8_t +sb_read(uint16_t a, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *) priv; + uint8_t ret = 0x00; + + switch (a & 0xf) { + case 0xA: /* Read data */ + if (mpu && dsp->uart_midi) { + ret = MPU401_ReadData(mpu); + } else { + dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; + if (dsp->sb_read_rp != dsp->sb_read_wp) { + dsp->sb_read_rp++; + dsp->sb_read_rp &= 0xff; + } + return dsp->sbreaddat; + } + break; + case 0xC: /* Write data ready */ + 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 = timer_is_enabled(&dsp->wb_timer); + return 0xff; + } + ret = 0x7f; + break; + case 0xE: /* Read data ready */ + picintc(1 << dsp->sb_irqnum); + dsp->sb_irq8 = dsp->sb_irq16 = 0; + ret = (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; + break; + case 0xF: /* 16-bit ack */ + dsp->sb_irq16 = 0; + if (!dsp->sb_irq8) + picintc(1 << dsp->sb_irqnum); + ret = 0xff; + break; } - return 0; + + return ret; } -static void sb_wb_clear(void *p) + +/* This should not even be needed. */ +void +sb_dsp_set_mpu(mpu_t *src_mpu) { - sb_dsp_t *dsp = (sb_dsp_t *)p; - - dsp->wb_time = 0LL; + mpu = src_mpu; } -void sb_dsp_set_mpu(mpu_t *src_mpu) +void +sb_dsp_input_msg(void *p, uint8_t *msg) { - mpu = src_mpu; -} - -void sb_dsp_init(sb_dsp_t *dsp, int type) -{ - dsp->sb_type = type; - - // 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); - - /*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) -{ - sb_dsp_log("sb_dsp_setaddr : %04X\n", addr); - if (dsp->sb_addr != 0) { - io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); - io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + sb_dsp_t *dsp = (sb_dsp_t *) p; + + sb_dsp_log("MIDI in sysex = %d, uart irq = %d, msg = %d\n", dsp->midi_in_sysex, dsp->uart_irq, msg[3]); + + if (dsp->midi_in_sysex) { + return; + } + + uint8_t len = msg[3]; + uint8_t i = 0; + if (dsp->uart_irq) { + for (i=0;isb_irq8); + if (!dsp->sb_irq8) + picint(1 << dsp->sb_irqnum); + } else if (dsp->midi_in_poll) { + for (i=0;isb_addr = addr; - if (dsp->sb_addr != 0) { - io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); - io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); - } } -void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo) +int +sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) { - dsp->stereo = stereo; + sb_dsp_t *dsp = (sb_dsp_t *) p; + + uint32_t i; + + if (abort) { + dsp->midi_in_sysex = 0; + return 0; + } + dsp->midi_in_sysex = 1; + for (i=0;isb_read_rp == dsp->sb_read_wp) { + sb_dsp_log("Length sysex SB = %d\n", len-i); + return (len-i); + } + sb_add_data(dsp, buffer[i]); + } + dsp->midi_in_sysex = 0; + return 0; } -void pollsb(void *p) +void +sb_dsp_init(sb_dsp_t *dsp, int type) { - sb_dsp_t *dsp = (sb_dsp_t *)p; - int tempi,ref; - - dsp->sbcount += dsp->sblatcho; - if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) - { - int data[2]; - - sb_dsp_update(dsp); - switch (dsp->sb_8_format) - { - case 0x00: /*Mono unsigned*/ - data[0] = sb_8_read_dma(dsp); - /*Needed to prevent clicking in Worms, which programs the DSP to - auto-init DMA but programs the DMA controller to single cycle*/ - if (data[0] == DMA_NODATA) - break; - dsp->sbdat = (data[0] ^ 0x80) << 8; - if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) - { - if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; - else dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } - else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - dsp->sb_8_length--; - break; - case 0x10: /*Mono signed*/ - data[0] = sb_8_read_dma(dsp); - if (data[0] == DMA_NODATA) - break; - dsp->sbdat = data[0] << 8; - if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) - { - if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; - else dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } - else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - dsp->sb_8_length--; - break; - case 0x20: /*Stereo unsigned*/ - data[0] = sb_8_read_dma(dsp); - data[1] = sb_8_read_dma(dsp); - if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) - break; - dsp->sbdatl = (data[0] ^ 0x80) << 8; - dsp->sbdatr = (data[1] ^ 0x80) << 8; - dsp->sb_8_length -= 2; - break; - case 0x30: /*Stereo signed*/ - data[0] = sb_8_read_dma(dsp); - data[1] = sb_8_read_dma(dsp); - if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) - break; - dsp->sbdatl = data[0] << 8; - dsp->sbdatr = data[1] << 8; - dsp->sb_8_length -= 2; - break; + dsp->sb_type = type; - case ADPCM_4: - if (dsp->sbdacpos) tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep; - else tempi = (dsp->sbdat2 >> 4) + dsp->sbstep; - if (tempi < 0) tempi = 0; - if (tempi > 63) tempi = 63; + /* Default values. Use sb_dsp_setxxx() methods to change. */ + dsp->sb_irqnum = 7; + dsp->sb_8_dmanum = 1; + dsp->sb_16_dmanum = 5; + mpu = NULL; - ref = dsp->sbref + scaleMap4[tempi]; - if (ref > 0xff) dsp->sbref = 0xff; - else if (ref < 0x00) dsp->sbref = 0x00; - else dsp->sbref = ref; + sb_doreset(dsp); - dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff; + timer_add(&dsp->output_timer, pollsb, dsp, 0); + timer_add(&dsp->input_timer, sb_poll_i, dsp, 0); + timer_add(&dsp->wb_timer, NULL, dsp, 0); - dsp->sbdat = (dsp->sbref ^ 0x80) << 8; - - dsp->sbdacpos++; - if (dsp->sbdacpos >= 2) - { - dsp->sbdacpos = 0; - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - } - - if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) - { - if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; - else dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } - else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - break; - - case ADPCM_26: - if (!dsp->sbdacpos) tempi = (dsp->sbdat2 >> 5) + dsp->sbstep; - else if (dsp->sbdacpos == 1) tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep; - else tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep; - - if (tempi < 0) tempi = 0; - if (tempi > 39) tempi = 39; - - ref = dsp->sbref + scaleMap26[tempi]; - if (ref > 0xff) dsp->sbref = 0xff; - else if (ref < 0x00) dsp->sbref = 0x00; - else dsp->sbref = ref; - dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff; - - dsp->sbdat = (dsp->sbref ^ 0x80) << 8; - - dsp->sbdacpos++; - if (dsp->sbdacpos>=3) - { - dsp->sbdacpos = 0; - dsp->sbdat2 = sb_8_read_dma(dsp); - dsp->sb_8_length--; - } - - if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) - { - if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; - else dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } - else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - break; - - case ADPCM_2: - tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep; - if (tempi < 0) tempi = 0; - if (tempi > 23) tempi = 23; - - ref = dsp->sbref + scaleMap2[tempi]; - if (ref > 0xff) dsp->sbref = 0xff; - else if (ref < 0x00) dsp->sbref = 0x00; - else dsp->sbref = ref; - dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff; - - dsp->sbdat = (dsp->sbref ^ 0x80) << 8; - - dsp->sbdacpos++; - if (dsp->sbdacpos >= 4) - { - dsp->sbdacpos = 0; - dsp->sbdat2 = sb_8_read_dma(dsp); - } - - if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) - { - if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; - else dsp->sbdatr = dsp->sbdat; - dsp->sbleftright = !dsp->sbleftright; - } - else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - break; - -// default: - //fatal("Unrecognised SB 8-bit format %02X\n",sb_8_format); - } - - if (dsp->sb_8_length < 0) - { - if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; - else dsp->sb_8_enable = dsp->sbenable=0; - sb_irq(dsp, 1); - } - } - if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0LL && dsp->sb_16_output) - { - int data[2]; - - sb_dsp_update(dsp); - - switch (dsp->sb_16_format) - { - case 0x00: /*Mono unsigned*/ - 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*/ - 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*/ - 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*/ - 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; - } - - if (dsp->sb_16_length < 0) - { - sb_dsp_log("16DMA over %i\n",dsp->sb_16_autoinit); - if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; - else dsp->sb_16_enable = dsp->sbenable = 0; - sb_irq(dsp, 0); - } - } - if (dsp->sb_pausetime > -1LL) - { - dsp->sb_pausetime--; - if (dsp->sb_pausetime < 0LL) - { - sb_irq(dsp, 1); - dsp->sbenable = dsp->sb_8_enable; - sb_dsp_log("SB pause over\n"); - } - } + /* 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_poll_i(void *p) + +void +sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) { - sb_dsp_t *dsp = (sb_dsp_t *)p; - int processed=0; - dsp->sb_count_i += dsp->sblatchi; - 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 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, (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, (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; - } - - 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->sb_enable_i = 0; - sb_irq(dsp, 1); - } - processed=1; - } - if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0LL && !dsp->sb_16_output) - { - switch (dsp->sb_16_format) - { - 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*/ - 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; - } - - if (dsp->sb_16_length < 0) - { - if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; - else dsp->sb_16_enable = dsp->sb_enable_i = 0; - sb_irq(dsp, 0); - } - processed=1; - } - /* Assume this is direct mode */ - if (!processed) - { - dsp->record_pos_read+=2; - dsp->record_pos_read&=0xFFFF; - } + sb_dsp_log("sb_dsp_setaddr : %04X\n", addr); + if (dsp->sb_addr != 0) { + io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + } + dsp->sb_addr = addr; + if (dsp->sb_addr != 0) { + io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + } } + +void +sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo) +{ + dsp->stereo = stereo; +} + + +void +pollsb(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *) p; + int tempi, ref; + int data[2]; + + timer_advance_u64(&dsp->output_timer, dsp->sblatcho); + if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) { + sb_dsp_update(dsp); + + switch (dsp->sb_8_format) { + case 0x00: /* Mono unsigned */ + data[0] = sb_8_read_dma(dsp); + /* Needed to prevent clicking in Worms, which programs the DSP to + auto-init DMA but programs the DMA controller to single cycle */ + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = (data[0] ^ 0x80) << 8; + if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { + sb_dsp_log("pollsb: Mono unsigned, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x10: /* Mono signed */ + data[0] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = data[0] << 8; + if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { + sb_dsp_log("pollsb: Mono signed, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", data[0], dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x20: /* Stereo unsigned */ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) + break; + dsp->sbdatl = (data[0] ^ 0x80) << 8; + dsp->sbdatr = (data[1] ^ 0x80) << 8; + dsp->sb_8_length -= 2; + break; + case 0x30: /* Stereo signed */ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) + break; + dsp->sbdatl = data[0] << 8; + dsp->sbdatr = data[1] << 8; + dsp->sb_8_length -= 2; + break; + + case ADPCM_4: + if (dsp->sbdacpos) + tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep; + else + tempi = (dsp->sbdat2 >> 4) + dsp->sbstep; + if (tempi < 0) + tempi = 0; + if (tempi > 63) + tempi = 63; + + ref = dsp->sbref + scaleMap4[tempi]; + if (ref > 0xff) + dsp->sbref = 0xff; + else if (ref < 0x00) + dsp->sbref = 0x00; + else + dsp->sbref = ref; + + dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff; + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + + if (dsp->sbdacpos >= 2) { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { + sb_dsp_log("pollsb: ADPCM 4, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_26: + if (!dsp->sbdacpos) + tempi = (dsp->sbdat2 >> 5) + dsp->sbstep; + else if (dsp->sbdacpos == 1) + tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep; + else + tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep; + + if (tempi < 0) + tempi = 0; + if (tempi > 39) + tempi = 39; + + ref = dsp->sbref + scaleMap26[tempi]; + if (ref > 0xff) + dsp->sbref = 0xff; + else if (ref < 0x00) + dsp->sbref = 0x00; + else + dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 3) { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { + sb_dsp_log("pollsb: ADPCM 26, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_2: + tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep; + if (tempi < 0) + tempi = 0; + if (tempi > 23) + tempi = 23; + + ref = dsp->sbref + scaleMap2[tempi]; + if (ref > 0xff) + dsp->sbref = 0xff; + else if (ref < 0x00) + dsp->sbref = 0x00; + else + dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 4) { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + } + + if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { + sb_dsp_log("pollsb: ADPCM 2, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + } + + if (dsp->sb_8_length < 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 < 0LL) && dsp->sb_16_output) { + sb_dsp_update(dsp); + + switch (dsp->sb_16_format) { + case 0x00: /* Mono unsigned */ + 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 */ + 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 */ + 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 */ + 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; + } + + if (dsp->sb_16_length < 0) { + sb_dsp_log("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 = 0; + timer_disable(&dsp->output_timer); + } + sb_irq(dsp, 0); + } + } + if (dsp->sb_pausetime > -1) { + dsp->sb_pausetime--; + if (dsp->sb_pausetime < 0) { + sb_irq(dsp, 1); + if (!dsp->sb_8_enable) + timer_disable(&dsp->output_timer); + sb_dsp_log("SB pause over\n"); + } + } +} + + +void +sb_poll_i(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *) p; + int processed = 0; + + timer_advance_u64(&dsp->input_timer, dsp->sblatchi); + + 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 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, (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, (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; + } + + if (dsp->sb_8_length < 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 < 0LL) && !dsp->sb_16_output) { + switch (dsp->sb_16_format) { + 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 */ + 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; + } + + if (dsp->sb_16_length < 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; - } + 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) + +void +sb_dsp_close(sb_dsp_t *dsp) { } diff --git a/src/sound/snd_sb_dsp.h b/src/sound/snd_sb_dsp.h index e4587c529..9e60dfaac 100644 --- a/src/sound/snd_sb_dsp.h +++ b/src/sound/snd_sb_dsp.h @@ -6,17 +6,21 @@ typedef struct sb_dsp_t 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; - int64_t sb_pausetime; + int sb_pausetime; uint8_t sb_read_data[256]; - int sb_read_wp, sb_read_rp; + int sb_read_wp, sb_read_rp; int sb_speaker; int muted; int sb_data_stat; - int uart_midi; - int uart_irq; - int onebyte_midi; + + int midi_in_sysex; + int midi_in_poll; + int uart_midi; + int uart_irq; + int onebyte_midi; + int midi_in_timestamp; int sb_irqnum; @@ -42,17 +46,17 @@ typedef struct sb_dsp_t uint8_t sbreaddat; uint8_t sb_command; uint8_t sb_test; - int64_t sb_timei, sb_timeo; + int sb_timei, sb_timeo; int sb_irq8, sb_irq16; uint8_t sb_asp_regs[256]; - int64_t sbenable, sb_enable_i; + int sbenable, sb_enable_i; - int64_t sbcount, sb_count_i; + pc_timer_t output_timer, input_timer; - int64_t sblatcho, sblatchi; + uint64_t sblatcho, sblatchi; uint16_t sb_addr; @@ -60,7 +64,8 @@ typedef struct sb_dsp_t int asp_data_len; - int64_t wb_time, wb_full; + pc_timer_t wb_timer; + int wb_full; int busy_count; @@ -71,6 +76,11 @@ typedef struct sb_dsp_t int pos; } sb_dsp_t; + +void sb_dsp_input_msg(void *p, uint8_t *msg); + +int sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort); + void sb_dsp_set_mpu(mpu_t *src_mpu); void sb_dsp_init(sb_dsp_t *dsp, int type); diff --git a/src/sound/snd_speaker.c b/src/sound/snd_speaker.c index 5defaa2c1..c6b9b1a8a 100644 --- a/src/sound/snd_speaker.c +++ b/src/sound/snd_speaker.c @@ -1,68 +1,111 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the PC speaker. + * + * Version: @(#)snd_speaker.c 1.0.1 2019/11/15 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ #include #include #include #include #include "../86box.h" +#include "../timer.h" #include "../pit.h" #include "sound.h" #include "snd_speaker.h" -int speaker_mute = 0; -int speaker_gated = 0; +int speaker_mute = 0, speaker_gated = 0; int speaker_enable = 0, was_speaker_enable = 0; - -int gated,speakval,speakon; +int gated, speakval, speakon; -static int16_t speaker_buffer[SOUNDBUFLEN]; +static int32_t speaker_buffer[SOUNDBUFLEN]; static int speaker_pos = 0; +static uint8_t speaker_mode = 0; +static double speaker_count = 65535.0; -void speaker_update(void) + +void +speaker_set_count(uint8_t new_m, int new_count) { - int16_t val; - - for (; speaker_pos < sound_pos_global; speaker_pos++) - { - if (speaker_gated && was_speaker_enable) - { - if (!pit.m[2] || pit.m[2]==4) - val = speakval; - else if (pit.l[2] < 0x40) - val = 0xa00; - else - val = speakon ? 0x1400 : 0; - } - else - val = was_speaker_enable ? 0x1400 : 0; - - if (!speaker_enable) - was_speaker_enable = 0; - - speaker_buffer[speaker_pos] = val; - } -} - -static void speaker_get_buffer(int32_t *buffer, int len, void *p) -{ - int c; - - speaker_update(); - - if (!speaker_mute) - { - for (c = 0; c < len * 2; c++) - buffer[c] += speaker_buffer[c >> 1]; - } - - speaker_pos = 0; + speaker_mode = new_m; + speaker_count = (double) new_count; } -void speaker_init(void) +void +speaker_update(void) { - sound_add_handler(speaker_get_buffer, NULL); - speaker_mute = 0; + int32_t val; + double amplitude; + + amplitude = ((speaker_count / 64.0) * 10240.0) - 5120.0; + + if (amplitude > 5120.0) + amplitude = 5120.0; + + if (speaker_pos < sound_pos_global) { + for (; speaker_pos < sound_pos_global; speaker_pos++) { + if (speaker_gated && was_speaker_enable) { + if ((speaker_mode == 0) || (speaker_mode == 4)) + val = (int32_t) amplitude; + else if (speaker_count < 64.0) + val = 0xa00; + else + val = speakon ? 0x1400 : 0; + } else { + if (speaker_mode == 1) + val = was_speaker_enable ? (int32_t) amplitude : 0; + else + val = was_speaker_enable ? 0x1400 : 0; + } + + if (!speaker_enable) + was_speaker_enable = 0; + + speaker_buffer[speaker_pos] = val; + } + } +} + + +void +speaker_get_buffer(int32_t *buffer, int len, void *p) +{ + int32_t c, val; + + speaker_update(); + + if (!speaker_mute) { + for (c = 0; c < len * 2; c += 2) { + val = speaker_buffer[c >> 1]; + buffer[c] += val; + buffer[c + 1] += val; + } + } + + speaker_pos = 0; +} + + +void +speaker_init(void) +{ + sound_add_handler(speaker_get_buffer, NULL); + speaker_mute = 0; } diff --git a/src/sound/snd_speaker.h b/src/sound/snd_speaker.h index 409a7c4e6..c27869f64 100644 --- a/src/sound/snd_speaker.h +++ b/src/sound/snd_speaker.h @@ -1,8 +1,28 @@ -void speaker_init(); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header of the emulation of the PC speaker. + * + * Version: @(#)snd_speaker.h 1.0.0 2019/11/15 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +extern int speaker_mute; -extern int speaker_mute; +extern int speaker_gated; +extern int speaker_enable, was_speaker_enable; -extern int speaker_gated; -extern int speaker_enable, was_speaker_enable; -void speaker_update(); +extern void speaker_init(); + +extern void speaker_set_count(uint8_t new_m, int new_count); +extern void speaker_update(void); diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 14725b5af..838547997 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -1,7 +1,21 @@ -/*PCem v0.8 by Tom Walker - - Windows Sound System emulation*/ - +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Windows Sound System emulation. + * + * Version: @(#)snd_wss.c 1.0.0 2018/08/11 + * + * Authors: Sarah Walker, + * TheCollector1995, + * + * Copyright 2012-2018 Sarah Walker. + * Copyright 2018 TheCollector1995. + */ #include #include #include @@ -10,6 +24,8 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" +#include "../mca.h" #include "../pic.h" #include "../dma.h" #include "../device.h" @@ -40,6 +56,9 @@ typedef struct wss_t ad1848_t ad1848; opl_t opl; + + int opl_enabled; + uint8_t pos_regs[8]; } wss_t; uint8_t wss_read(uint16_t addr, void *p) @@ -98,6 +117,73 @@ void *wss_init(const device_t *info) return wss; } +static uint8_t ncr_audio_mca_read(int port, void *p) +{ + wss_t *wss = (wss_t *)p; + + return wss->pos_regs[port & 7]; +} + +static void ncr_audio_mca_write(int port, uint8_t val, void *p) +{ + wss_t *wss = (wss_t *)p; + uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604}; + uint16_t addr; + + if (port < 0x102) + return; + + wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0; + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + + io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + //pclog("WSS MCA: opl=%d, addr=%03x\n", wss->opl_enabled, addr); + + wss->pos_regs[port & 7] = val; + + if (wss->pos_regs[2] & 1) + { + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + + if (wss->opl_enabled) + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + + io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + } +} + +static uint8_t ncr_audio_mca_feedb(void *p) +{ + wss_t *wss = (wss_t *)p; + + return (wss->pos_regs[2] & 1); +} + +void *ncr_audio_init(const device_t *info) +{ + wss_t *wss = malloc(sizeof(wss_t)); + + memset(wss, 0, sizeof(wss_t)); + + opl3_init(&wss->opl); + ad1848_init(&wss->ad1848); + + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); + + mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, wss); + wss->pos_regs[0] = 0x16; + wss->pos_regs[1] = 0x51; + + sound_add_handler(wss_get_buffer, wss); + + return wss; +} + void wss_close(void *p) { wss_t *wss = (wss_t *)p; @@ -122,3 +208,14 @@ const device_t wss_device = NULL, NULL }; + +const device_t ncr_business_audio_device = +{ + "NCR Business Audio", + DEVICE_MCA, 0, + ncr_audio_init, wss_close, NULL, + NULL, + wss_speed_changed, + NULL, + NULL +}; diff --git a/src/sound/snd_wss.h b/src/sound/snd_wss.h index 0836e5808..77fc9f08c 100644 --- a/src/sound/snd_wss.h +++ b/src/sound/snd_wss.h @@ -1 +1,25 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Windows Sound System emulation. + * + * Version: @(#)snd_wss.c 1.0.0 2018/08/11 + * + * Authors: Sarah Walker, + * TheCollector1995, + * + * Copyright 2012-2018 Sarah Walker. + * Copyright 2018 TheCollector1995. + */ +#ifndef SND_WSS_H +# define SND_WSS_H + extern const device_t wss_device; +extern const device_t ncr_business_audio_device; + +#endif /*SND_WSS_H*/ diff --git a/src/sound/sound.c b/src/sound/sound.c index 75145468e..d3de46351 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.c 1.0.17 2018/04/29 + * Version: @(#)sound.c 1.0.27 2019/02/06 * * Authors: Sarah Walker, * Miran Grca, @@ -26,8 +26,8 @@ #include "../86box.h" #include "../device.h" #include "../timer.h" -#include "../scsi/scsi.h" #include "../cdrom/cdrom.h" +#include "../disk/hdc_ide.h" #include "../plat.h" #include "sound.h" #include "midi.h" @@ -62,61 +62,62 @@ typedef struct { int sound_card_current = 0; int sound_pos_global = 0; -volatile int soundon = 1; int sound_gain = 0; -static int sound_card_last = 0; static sound_handler_t sound_handlers[8]; -static sound_handler_t sound_process_handlers[8]; -static int sound_handlers_num; -static int sound_process_handlers_num; -static int64_t sound_poll_time = 0LL, sound_poll_latch; -static int16_t cd_buffer[CDROM_NUM][CD_BUFLEN * 2]; -static float cd_out_buffer[CD_BUFLEN * 2]; -static int16_t cd_out_buffer_int16[CD_BUFLEN * 2]; + static thread_t *sound_cd_thread_h; static event_t *sound_cd_event; static event_t *sound_cd_start_event; +static int32_t *outbuffer; +static float *outbuffer_ex; +static int16_t *outbuffer_ex_int16; +static int sound_handlers_num; +static pc_timer_t sound_poll_timer; +static uint64_t sound_poll_latch; + +static int16_t cd_buffer[CDROM_NUM][CD_BUFLEN * 2]; +static float cd_out_buffer[CD_BUFLEN * 2]; +static int16_t cd_out_buffer_int16[CD_BUFLEN * 2]; static unsigned int cd_vol_l, cd_vol_r; static int cd_buf_update = CD_BUFLEN / SOUNDBUFLEN; static volatile int cdaudioon = 0; +static int cd_thread_enable = 0; static const SOUND_CARD sound_cards[] = { - { "None", "none", NULL }, - { "[ISA] Adlib", "adlib", &adlib_device }, - { "[ISA] Adlib Gold", "adlibgold",&adgold_device }, - { "[ISA] Sound Blaster 1.0", "sb", &sb_1_device }, - { "[ISA] Sound Blaster 1.5", "sb1.5", &sb_15_device }, - { "[ISA] Sound Blaster 2.0", "sb2.0", &sb_2_device }, - { "[ISA] Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device }, - { "[ISA] Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device }, - { "[ISA] Sound Blaster 16", "sb16", &sb_16_device }, - { "[ISA] Sound Blaster AWE32", "sbawe32", &sb_awe32_device }, + { "None", "none", NULL }, + { "[ISA] Adlib", "adlib", &adlib_device }, + { "[ISA] Adlib Gold", "adlibgold", &adgold_device }, + { "[ISA] Sound Blaster 1.0", "sb", &sb_1_device }, + { "[ISA] Sound Blaster 1.5", "sb1.5", &sb_15_device }, + { "[ISA] Sound Blaster 2.0", "sb2.0", &sb_2_device }, + { "[ISA] Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device }, + { "[ISA] Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device }, + { "[ISA] Sound Blaster 16", "sb16", &sb_16_device }, + { "[ISA] Sound Blaster AWE32", "sbawe32", &sb_awe32_device }, #if defined(DEV_BRANCH) && defined(USE_PAS16) - { "[ISA] Pro Audio Spectrum 16","pas16", &pas16_device }, + { "[ISA] Pro Audio Spectrum 16", "pas16", &pas16_device }, #endif - { "[ISA] Windows Sound System", "wss", &wss_device }, - { "[MCA] Adlib", "adlib_mca", &adlib_mca_device }, - { "[MCA] Sound Blaster MCV", "sbmcv", &sb_mcv_device }, - { "[MCA] Sound Blaster Pro MCV","sbpromcv", &sb_pro_mcv_device }, - { "[PCI] Ensoniq AudioPCI (ES1371)","es1371", &es1371_device}, - { "[PCI] Sound Blaster PCI 128", "sbpci128", &es1371_device}, - { "", "", NULL } + { "[ISA] Windows Sound System", "wss", &wss_device }, + { "[MCA] Adlib", "adlib_mca", &adlib_mca_device }, + { "[MCA] NCR Business Audio", "ncraudio", &ncr_business_audio_device }, + { "[MCA] Sound Blaster MCV", "sbmcv", &sb_mcv_device }, + { "[MCA] Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device }, + { "[PCI] Ensoniq AudioPCI (ES1371)", "es1371", &es1371_device }, + { "", "", NULL } }; #ifdef ENABLE_SOUND_LOG int sound_do_log = ENABLE_SOUND_LOG; -#endif static void sound_log(const char *fmt, ...) { -#ifdef ENABLE_SOUND_LOG va_list ap; if (sound_do_log) { @@ -124,380 +125,335 @@ sound_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define sound_log(fmt, ...) #endif + + +int +sound_card_available(int card) +{ + if (sound_cards[card].device) + return device_available(sound_cards[card].device); + + return 1; } -int sound_card_available(int card) +char * +sound_card_getname(int card) { - if (sound_cards[card].device) - return device_available(sound_cards[card].device); - - return 1; + return (char *) sound_cards[card].name; } -char *sound_card_getname(int card) + +const device_t * +sound_card_getdevice(int card) { - return (char *) sound_cards[card].name; + return sound_cards[card].device; } -const device_t *sound_card_getdevice(int card) -{ - return sound_cards[card].device; -} -int sound_card_has_config(int card) +int +sound_card_has_config(int card) { - if (!sound_cards[card].device) - return 0; - return sound_cards[card].device->config ? 1 : 0; -} - -char *sound_card_get_internal_name(int card) -{ - return (char *) sound_cards[card].internal_name; -} - -int sound_card_get_from_internal_name(char *s) -{ - int c = 0; - - while (strlen((char *) sound_cards[c].internal_name)) - { - if (!strcmp((char *) sound_cards[c].internal_name, s)) - return c; - c++; - } - + if (!sound_cards[card].device) return 0; + return sound_cards[card].device->config ? 1 : 0; } -void sound_card_init(void) + +char * +sound_card_get_internal_name(int card) { - if (sound_cards[sound_card_current].device) - device_add(sound_cards[sound_card_current].device); - sound_card_last = sound_card_current; + return (char *) sound_cards[card].internal_name; } -void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) + +int +sound_card_get_from_internal_name(char *s) { - cd_vol_l = vol_l; - cd_vol_r = vol_r; + int c = 0; + + while (strlen((char *) sound_cards[c].internal_name)) { + if (!strcmp((char *) sound_cards[c].internal_name, s)) + return c; + c++; + } + + return 0; } -static void sound_cd_thread(void *param) + +void +sound_card_init(void) { - int i = 0; + if (sound_cards[sound_card_current].device) + device_add(sound_cards[sound_card_current].device); +} - float cd_buffer_temp[2] = {0.0, 0.0}; - float cd_buffer_temp2[2] = {0.0, 0.0}; - int32_t cd_buffer_temp4[2] = {0, 0}; +void +sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) +{ + cd_vol_l = vol_l; + cd_vol_r = vol_r; +} - int c, has_audio; - int d, r; - thread_set_event(sound_cd_start_event); +static void +sound_cd_clean_buffers(void) +{ + if (sound_is_float) + memset(cd_out_buffer, 0, (CD_BUFLEN * 2) * sizeof(float)); + else + memset(cd_out_buffer_int16, 0, (CD_BUFLEN * 2) * sizeof(int16_t)); +} - while (cdaudioon) - { - thread_wait_event(sound_cd_event, -1); - thread_reset_event(sound_cd_event); - if (!soundon || !cdaudioon) - return; - for (c = 0; c < CD_BUFLEN*2; c += 2) - { - if (sound_is_float) - { - cd_out_buffer[c] = 0.0; - cd_out_buffer[c+1] = 0.0; + +static void +sound_cd_thread(void *param) +{ + int c, r, i, channel_select[2]; + float audio_vol_l, audio_vol_r; + float cd_buffer_temp[2] = {0.0, 0.0}; + + thread_set_event(sound_cd_start_event); + + while (cdaudioon) { + thread_wait_event(sound_cd_event, -1); + thread_reset_event(sound_cd_event); + + if (!cdaudioon) + return; + + sound_cd_clean_buffers(); + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom[i].bus_type == CDROM_BUS_DISABLED) || + (cdrom[i].cd_status == CD_STATUS_EMPTY)) + continue; + r = cdrom_audio_callback(&(cdrom[i]), cd_buffer[i], CD_BUFLEN * 2); + if (!cdrom[i].bus_type || !cdrom[i].sound_on || !r) + continue; + + if (cdrom[i].get_volume) { + audio_vol_l = (float) (cdrom[i].get_volume(cdrom[i].priv, 0)); + audio_vol_r = (float) (cdrom[i].get_volume(cdrom[i].priv, 1)); + } else { + audio_vol_l = 255.0; + audio_vol_r = 255.0; + } + + audio_vol_l /= 511.0; + audio_vol_r /= 511.0; + + if (cdrom[i].get_channel) { + channel_select[0] = cdrom[i].get_channel(cdrom[i].priv, 0); + channel_select[1] = cdrom[i].get_channel(cdrom[i].priv, 1); + } else { + channel_select[0] = 1; + channel_select[1] = 2; + } + + for (c = 0; c < CD_BUFLEN*2; c += 2) { + /*Apply ATAPI channel select*/ + cd_buffer_temp[0] = cd_buffer_temp[1] = 0.0; + +#if 0 + if (channel_select[0] & 1) + cd_buffer_temp[0] += ((float) cd_buffer[i][c]) * audio_vol_l; + if (channel_select[0] & 2) + cd_buffer_temp[1] += ((float) cd_buffer[i][c]) * audio_vol_l; + if (channel_select[1] & 1) + cd_buffer_temp[0] += ((float) cd_buffer[i][c + 1]) * audio_vol_r; + if (channel_select[1] & 2) + cd_buffer_temp[1] += ((float) cd_buffer[i][c + 1]) * audio_vol_r; +#else + if ((audio_vol_l != 0.0) && (channel_select[0] != 0)) { + if (channel_select[0] & 1) + cd_buffer_temp[0] += ((float) cd_buffer[i][c]); /* Channel 0 => Port 0 */ + if (channel_select[0] & 2) + cd_buffer_temp[0] += ((float) cd_buffer[i][c + 1]); /* Channel 1 => Port 0 */ + + cd_buffer_temp[0] *= audio_vol_l; /* Multiply Port 0 by Port 0 volume */ } - else - { - cd_out_buffer_int16[c] = 0; - cd_out_buffer_int16[c+1] = 0; + + if ((audio_vol_r != 0.0) && (channel_select[1] != 0)) { + if (channel_select[1] & 1) + cd_buffer_temp[1] += ((float) cd_buffer[i][c]); /* Channel 0 => Port 1 */ + if (channel_select[1] & 2) + cd_buffer_temp[1] += ((float) cd_buffer[i][c + 1]); /* Channel 1 => Port 1 */ + + cd_buffer_temp[1] *= audio_vol_r; /* Multiply Port 1 by Port 1 volume */ + } +#endif + + /*Apply sound card CD volume*/ + cd_buffer_temp[0] *= ((float) cd_vol_l) / 65535.0; + cd_buffer_temp[1] *= ((float) cd_vol_r) / 65535.0; + + if (sound_is_float) { + cd_out_buffer[c] += (cd_buffer_temp[0] / 32768.0); + cd_out_buffer[c+1] += (cd_buffer_temp[1] / 32768.0); + } else { + if (cd_buffer_temp[0] > 32767) + cd_buffer_temp[0] = 32767; + if (cd_buffer_temp[0] < -32768) + cd_buffer_temp[0] = -32768; + if (cd_buffer_temp[1] > 32767) + cd_buffer_temp[1] = 32767; + if (cd_buffer_temp[1] < -32768) + cd_buffer_temp[1] = -32768; + + cd_out_buffer_int16[c] += cd_buffer_temp[0]; + cd_out_buffer_int16[c+1] += cd_buffer_temp[1]; } } - for (i = 0; i < CDROM_NUM; i++) - { - has_audio = 0; - if ((cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) || !cdrom[i] || !cdrom[i]->handler) - continue; - if (cdrom[i]->handler->audio_callback) - { - r = cdrom[i]->handler->audio_callback(i, cd_buffer[i], CD_BUFLEN*2); - has_audio = (cdrom_drives[i].bus_type && cdrom_drives[i].sound_on/* && r*/); - } else - continue; - if (soundon && has_audio) - { - int32_t audio_vol_l = cdrom_mode_sense_get_volume(cdrom[i], 0); - int32_t audio_vol_r = cdrom_mode_sense_get_volume(cdrom[i], 1); - int channel_select[2]; - - channel_select[0] = cdrom_mode_sense_get_channel(cdrom[i], 0); - channel_select[1] = cdrom_mode_sense_get_channel(cdrom[i], 1); - - if (!r) - { - for (c = 0; c < CD_BUFLEN*2; c += 2) - { - if (sound_is_float) - { - cd_out_buffer[c] += 0.0; - cd_out_buffer[c+1] += 0.0; - } - else - { - cd_out_buffer_int16[c] += 0; - cd_out_buffer_int16[c+1] += 0; - } - } - continue; - } - - for (c = 0; c < CD_BUFLEN*2; c += 2) - { - /* First, transfer the CD audio data to the temporary buffer. */ - cd_buffer_temp[0] = (float) cd_buffer[i][c]; - cd_buffer_temp[1] = (float) cd_buffer[i][c+1]; - - /* Then, adjust input from drive according to ATAPI/SCSI volume. */ - cd_buffer_temp[0] *= (float) audio_vol_l; - cd_buffer_temp[0] /= 511.0; - cd_buffer_temp[1] *= (float) audio_vol_r; - cd_buffer_temp[1] /= 511.0; - - /*Apply ATAPI channel select*/ - cd_buffer_temp2[0] = cd_buffer_temp2[1] = 0.0; - if (channel_select[0] & 1) - { - cd_buffer_temp2[0] += cd_buffer_temp[0]; - } - if (channel_select[0] & 2) - { - cd_buffer_temp2[1] += cd_buffer_temp[0]; - } - if (channel_select[1] & 1) - { - cd_buffer_temp2[0] += cd_buffer_temp[1]; - } - if (channel_select[1] & 2) - { - cd_buffer_temp2[1] += cd_buffer_temp[1]; - } - - if (sound_process_handlers_num) - { - cd_buffer_temp4[0] = (int32_t) cd_buffer_temp2[0]; - cd_buffer_temp4[1] = (int32_t) cd_buffer_temp2[1]; - - for (d = 0; d < sound_process_handlers_num; d++) - sound_process_handlers[d].get_buffer(cd_buffer_temp4, 1, sound_process_handlers[d].priv); - - cd_buffer_temp2[0] = (float) cd_buffer_temp4[0]; - cd_buffer_temp2[1] = (float) cd_buffer_temp4[1]; - } - else - { - /*Apply sound card CD volume*/ - cd_buffer_temp2[0] *= (float) cd_vol_l; - cd_buffer_temp2[0] /= 65535.0; - - cd_buffer_temp2[1] *= (float) cd_vol_r; - cd_buffer_temp2[1] /= 65535.0; - } - - if (sound_is_float) - { - cd_out_buffer[c] += (cd_buffer_temp2[0] / 32768.0); - cd_out_buffer[c+1] += (cd_buffer_temp2[1] / 32768.0); - } - else - { - if (cd_buffer_temp2[0] > 32767) - cd_buffer_temp2[0] = 32767; - if (cd_buffer_temp2[0] < -32768) - cd_buffer_temp2[0] = -32768; - if (cd_buffer_temp2[1] > 32767) - cd_buffer_temp2[1] = 32767; - if (cd_buffer_temp2[1] < -32768) - cd_buffer_temp2[1] = -32768; - - cd_out_buffer_int16[c] += cd_buffer_temp2[0]; - cd_out_buffer_int16[c+1] += cd_buffer_temp2[1]; - } - } - } - } - if (sound_is_float) - givealbuffer_cd(cd_out_buffer); - else - givealbuffer_cd(cd_out_buffer_int16); - } -} - -static int32_t *outbuffer; -static float *outbuffer_ex; -static int16_t *outbuffer_ex_int16; - -static int cd_thread_enable = 0; - -static void sound_realloc_buffers(void) -{ - if (outbuffer_ex != NULL) - { - free(outbuffer_ex); - } - - if (outbuffer_ex_int16 != NULL) - { - free(outbuffer_ex_int16); } if (sound_is_float) - { - outbuffer_ex = malloc(SOUNDBUFLEN * 2 * sizeof(float)); - } + givealbuffer_cd(cd_out_buffer); else - { - outbuffer_ex_int16 = malloc(SOUNDBUFLEN * 2 * sizeof(int16_t)); - } + givealbuffer_cd(cd_out_buffer_int16); + } } -void sound_init(void) + +static void +sound_realloc_buffers(void) { - int i = 0; - int available_cdrom_drives = 0; + if (outbuffer_ex != NULL) + free(outbuffer_ex); - outbuffer_ex = NULL; - outbuffer_ex_int16 = NULL; + if (outbuffer_ex_int16 != NULL) + free(outbuffer_ex_int16); - outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); + if (sound_is_float) + outbuffer_ex = malloc(SOUNDBUFLEN * 2 * sizeof(float)); + else + outbuffer_ex_int16 = malloc(SOUNDBUFLEN * 2 * sizeof(int16_t)); +} - for (i = 0; i < CDROM_NUM; i++) - { - if (cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) - { - available_cdrom_drives++; + +void +sound_init(void) +{ + int i = 0; + int available_cdrom_drives = 0; + + outbuffer_ex = NULL; + outbuffer_ex_int16 = NULL; + + outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); + + for (i = 0; i < CDROM_NUM; i++) { + if (cdrom[i].bus_type != CDROM_BUS_DISABLED) + available_cdrom_drives++; + } + + if (available_cdrom_drives) { + cdaudioon = 1; + + sound_cd_start_event = thread_create_event(); + + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); + + sound_log("Waiting for CD start event...\n"); + thread_wait_event(sound_cd_start_event, -1); + thread_reset_event(sound_cd_start_event); + sound_log("Done!\n"); + } else + cdaudioon = 0; + + cd_thread_enable = available_cdrom_drives ? 1 : 0; +} + + +void +sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) +{ + sound_handlers[sound_handlers_num].get_buffer = get_buffer; + sound_handlers[sound_handlers_num].priv = p; + sound_handlers_num++; +} + + +void +sound_poll(void *priv) +{ + timer_advance_u64(&sound_poll_timer, sound_poll_latch); + + midi_poll(); + + sound_pos_global++; + if (sound_pos_global == SOUNDBUFLEN) { + int c; + + memset(outbuffer, 0, SOUNDBUFLEN * 2 * sizeof(int32_t)); + + for (c = 0; c < sound_handlers_num; c++) + sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv); + + for (c = 0; c < SOUNDBUFLEN * 2; c++) { + if (sound_is_float) + outbuffer_ex[c] = ((float) outbuffer[c]) / 32768.0; + else { + if (outbuffer[c] > 32767) + outbuffer[c] = 32767; + if (outbuffer[c] < -32768) + outbuffer[c] = -32768; + + outbuffer_ex_int16[c] = outbuffer[c]; } - } - - if (available_cdrom_drives) - { - cdaudioon = 1; - - sound_cd_start_event = thread_create_event(); - - sound_cd_event = thread_create_event(); - sound_cd_thread_h = thread_create(sound_cd_thread, NULL); - - sound_log("Waiting for CD start event...\n"); - thread_wait_event(sound_cd_start_event, -1); - thread_reset_event(sound_cd_start_event); - sound_log("Done!\n"); } + + if (sound_is_float) + givealbuffer(outbuffer_ex); else - cdaudioon = 0; + givealbuffer(outbuffer_ex_int16); - cd_thread_enable = available_cdrom_drives ? 1 : 0; + if (cd_thread_enable) { + 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; + } } -void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) + +void +sound_speed_changed(void) { - sound_handlers[sound_handlers_num].get_buffer = get_buffer; - sound_handlers[sound_handlers_num].priv = p; - sound_handlers_num++; + sound_poll_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); } -void sound_add_process_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) + +void +sound_reset(void) { - sound_process_handlers[sound_process_handlers_num].get_buffer = get_buffer; - sound_process_handlers[sound_process_handlers_num].priv = p; - sound_process_handlers_num++; + sound_realloc_buffers(); + + midi_device_init(); + midi_in_device_init(); + inital(); + + timer_add(&sound_poll_timer, sound_poll, NULL, 1); + + sound_handlers_num = 0; + + sound_set_cd_volume(65535, 65535); } -void sound_poll(void *priv) -{ - sound_poll_time += sound_poll_latch; - midi_poll(); - - sound_pos_global++; - if (sound_pos_global == SOUNDBUFLEN) - { - int c; - - memset(outbuffer, 0, SOUNDBUFLEN * 2 * sizeof(int32_t)); - - for (c = 0; c < sound_handlers_num; c++) - sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv); - - - for (c = 0; c < SOUNDBUFLEN * 2; c++) - { - if (sound_is_float) - { - outbuffer_ex[c] = ((float) outbuffer[c]) / 32768.0; - } - else - { - if (outbuffer[c] > 32767) - outbuffer[c] = 32767; - if (outbuffer[c] < -32768) - outbuffer[c] = -32768; - - outbuffer_ex_int16[c] = outbuffer[c]; - } - } - - if (soundon) - { - if (sound_is_float) - { - givealbuffer(outbuffer_ex); - } - else - { - givealbuffer(outbuffer_ex_int16); - } - } - - if (cd_thread_enable) - { - 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; - } -} - -void sound_speed_changed(void) -{ - sound_poll_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); -} - -void sound_reset(void) -{ - sound_realloc_buffers(); - - midi_device_init(); - inital(); - - timer_add(sound_poll, &sound_poll_time, TIMER_ALWAYS_ENABLED, NULL); - - sound_handlers_num = 0; - sound_process_handlers_num = 0; - - sound_set_cd_volume(65535, 65535); -} - -void sound_card_reset(void) +void +sound_card_reset(void) { sound_card_init(); if (mpu401_standalone_enable) @@ -510,64 +466,58 @@ void sound_card_reset(void) device_add(&ssi2001_device); } -void sound_cd_thread_end(void) + +void +sound_cd_thread_end(void) { - if (cdaudioon) { - cdaudioon = 0; + if (cdaudioon) { + cdaudioon = 0; - sound_log("Waiting for CD Audio thread to terminate...\n"); - thread_set_event(sound_cd_event); - thread_wait(sound_cd_thread_h, -1); - sound_log("CD Audio thread terminated...\n"); + sound_log("Waiting for CD Audio thread to terminate...\n"); + thread_set_event(sound_cd_event); + thread_wait(sound_cd_thread_h, -1); + sound_log("CD Audio thread terminated...\n"); - if (sound_cd_event) { - thread_destroy_event(sound_cd_event); - sound_cd_event = NULL; - } - - sound_cd_thread_h = NULL; - - if (sound_cd_start_event) { - thread_destroy_event(sound_cd_start_event); - sound_cd_event = NULL; - } + if (sound_cd_event) { + thread_destroy_event(sound_cd_event); + sound_cd_event = NULL; } + + sound_cd_thread_h = NULL; + + if (sound_cd_start_event) { + thread_destroy_event(sound_cd_start_event); + sound_cd_event = NULL; + } + } } -void sound_cd_thread_reset(void) + +void +sound_cd_thread_reset(void) { - int i = 0; - int available_cdrom_drives = 0; + int i = 0; + int available_cdrom_drives = 0; - for (i = 0; i < CDROM_NUM; i++) - { - if (cdrom[i] && cdrom[i]->handler && cdrom[i]->handler->audio_stop) - { - cdrom[i]->handler->audio_stop(i); - } + for (i = 0; i < CDROM_NUM; i++) { + cdrom_stop(&(cdrom[i])); - if ((cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) && cdrom[i]) - { - available_cdrom_drives++; - } - } + if (cdrom[i].bus_type != CDROM_BUS_DISABLED) + available_cdrom_drives++; + } - if (available_cdrom_drives && !cd_thread_enable) - { - cdaudioon = 1; + if (available_cdrom_drives && !cd_thread_enable) { + cdaudioon = 1; - sound_cd_start_event = thread_create_event(); + sound_cd_start_event = thread_create_event(); - sound_cd_event = thread_create_event(); - sound_cd_thread_h = thread_create(sound_cd_thread, NULL); + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); - thread_wait_event(sound_cd_start_event, -1); - thread_reset_event(sound_cd_start_event); - } - else if (!available_cdrom_drives && cd_thread_enable) - { - sound_cd_thread_end(); - } + thread_wait_event(sound_cd_start_event, -1); + thread_reset_event(sound_cd_start_event); + } else if (!available_cdrom_drives && cd_thread_enable) + sound_cd_thread_end(); - cd_thread_enable = available_cdrom_drives ? 1 : 0; + cd_thread_enable = available_cdrom_drives ? 1 : 0; } diff --git a/src/sound/sound.h b/src/sound/sound.h index cf49dbf1c..5410a5602 100644 --- a/src/sound/sound.h +++ b/src/sound/sound.h @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.h 1.0.7 2018/04/23 + * Version: @(#)sound.h 1.0.8 2018/10/26 * * Authors: Sarah Walker, * Miran Grca, @@ -39,8 +39,6 @@ extern int sound_card_current; extern void sound_add_handler(void (*get_buffer)(int32_t *buffer, \ int len, void *p), void *p); -extern void sound_add_process_handler(void (*get_buffer)(int32_t *buffer, \ - int len, void *p), void *p); extern int sound_card_available(int card); extern char *sound_card_getname(int card); diff --git a/src/timer.c b/src/timer.c index 02d5a1bd2..600b28c06 100644 --- a/src/timer.c +++ b/src/timer.c @@ -6,132 +6,242 @@ #include "timer.h" -#define TIMERS_MAX 64 +uint64_t TIMER_USEC; +uint32_t timer_target; + +/*Enabled timers are stored in a linked list, with the first timer to expire at + the head.*/ +static pc_timer_t *timer_head = NULL; + +/* Are we initialized? */ +static int timer_inited = 0; -static struct +void +timer_enable(pc_timer_t *timer) { - int64_t present; - void (*callback)(void *priv); - void *priv; - int64_t *enable; - int64_t *count; -} timers[TIMERS_MAX]; + pc_timer_t *timer_node = timer_head; + if (!timer_inited || (timer == NULL)) + return; -int64_t TIMER_USEC; -int64_t timers_present = 0; -int64_t timer_one = 1; - -int64_t timer_count = 0, timer_latch = 0; -int64_t timer_start = 0; + if (timer->flags & TIMER_ENABLED) + timer_disable(timer); + if (timer->next || timer->prev) + fatal("timer_enable - timer->next\n"); -void timer_process(void) -{ - int64_t c; - int64_t process = 0; - /*Get actual elapsed time*/ - int64_t diff = timer_latch - timer_count; - int64_t enable[TIMERS_MAX]; + timer->flags |= TIMER_ENABLED; - timer_latch = 0; + /*List currently empty - add to head*/ + if (!timer_head) { + timer_head = timer; + timer->next = timer->prev = NULL; +#if 0 + timer_target = timer_head->ts_integer; +#else + timer_target = timer_head->ts.ts32.integer; +#endif + return; + } - for (c = 0; c < timers_present; c++) - { - /* This is needed to avoid timer crashes on hard reset. */ - if ((timers[c].enable == NULL) || (timers[c].count == NULL)) - { - continue; + 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; +#if 0 + timer_target = timer_head->ts_integer; +#else + timer_target = timer_head->ts.ts32.integer; +#endif } - 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) - { - int64_t 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(void) -{ - int64_t c; - timer_latch = 0x7fffffffffffffff; - for (c = 0; c < timers_present; c++) - { - if (*timers[c].enable && *timers[c].count < timer_latch) - timer_latch = *timers[c].count; + return; } - timer_count = timer_latch = (timer_latch + ((1 << TIMER_SHIFT) - 1)); -} - -void timer_reset(void) -{ - timers_present = 0; - timer_latch = timer_count = 0; -} - - -int64_t timer_add(void (*callback)(void *priv), int64_t *count, int64_t *enable, void *priv) -{ - int64_t i = 0; - - if (timers_present < TIMERS_MAX) - { - if (timers_present != 0) - { - /* This is the sanity check - it goes through all present timers and makes sure we're not adding a timer that already exists. */ - for (i = 0; i < timers_present; i++) - { - if (timers[i].present && (timers[i].callback == callback) && (timers[i].priv == priv) && (timers[i].count == count) && (timers[i].enable == enable)) - { - return 0; - } - } - } - - 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; + /*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; } - return -1; + + timer_node = timer_node->next; + } } -void timer_set_callback(int64_t timer, void (*callback)(void *priv)) +void +timer_disable(pc_timer_t *timer) { - timers[timer].callback = callback; + if (!timer_inited || (timer == NULL) || !(timer->flags & TIMER_ENABLED)) + return; + + if (!timer->next && !timer->prev && timer != timer_head) + fatal("timer_disable - !timer->next\n"); + + timer->flags &= ~TIMER_ENABLED; + + 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(void) +{ + pc_timer_t *timer; + + if (!timer_inited) + return; + + if (timer_head) { + timer = timer_head; + timer_head = timer->next; + if (timer_head) + timer_head->prev = NULL; + timer->next = timer->prev = NULL; + timer->flags &= ~TIMER_ENABLED; + } +} + + +void +timer_process(void) +{ + pc_timer_t *timer; + + if (!timer_inited || !timer_head) + return; + + while(1) { + timer = timer_head; + + if (!TIMER_LESS_THAN_VAL(timer, (uint32_t)tsc)) + break; + + timer_remove_head(); + + if (timer->flags & TIMER_SPLIT) + timer_advance_ex(timer, 0); /* We're splitting a > 1 s period into multiple <= 1 s periods. */ + else if (timer->callback != NULL) /* Make sure it's no NULL, so that we can have a NULL callback when no operation is needed. */ + timer->callback(timer->p); + } + +#if 0 + timer_target = timer_head->ts_integer; +#else + timer_target = timer_head->ts.ts32.integer; +#endif +} + + +void +timer_close(void) +{ + timer_head = NULL; + + timer_inited = 0; +} + + +void +timer_init(void) +{ + timer_target = 0ULL; + tsc = 0; + + timer_inited = 1; +} + + +void +timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int start_timer) +{ + memset(timer, 0, sizeof(pc_timer_t)); + + timer->callback = callback; + timer->p = p; + timer->flags = 0; + timer->prev = timer->next = NULL; + if (start_timer) + timer_set_delay_u64(timer, 0); +} + + +/* The API for big timer periods starts here. */ +void +timer_stop(pc_timer_t *timer) +{ + if (!timer_inited || (timer == NULL)) + return; + + timer->period = 0.0; + timer_disable(timer); + timer->flags &= ~TIMER_SPLIT; +} + + +static void +timer_do_period(pc_timer_t *timer, uint64_t period, int start) +{ + if (!timer_inited || (timer == NULL)) + return; + + if (start) + timer_set_delay_u64(timer, period); + else + timer_advance_u64(timer, period); +} + + +void +timer_advance_ex(pc_timer_t *timer, int start) +{ + if (!timer_inited || (timer == NULL)) + return; + + if (timer->period > MAX_USEC) { + timer_do_period(timer, MAX_USEC64 * TIMER_USEC, start); + timer->period -= MAX_USEC; + timer->flags |= TIMER_SPLIT; + } else { + if (timer->period > 0.0) + timer_do_period(timer, (uint64_t) (timer->period * ((double) TIMER_USEC)), start); + timer->period = 0.0; + timer->flags &= ~TIMER_SPLIT; + } +} + + +void +timer_on(pc_timer_t *timer, double period, int start) +{ + if (!timer_inited || (timer == NULL)) + return; + + timer->period = period; + timer_advance_ex(timer, start); +} + + +void +timer_on_auto(pc_timer_t *timer, double period) +{ + if (!timer_inited || (timer == NULL)) + return; + + timer_on(timer, period, (timer->period == 0.0)); } diff --git a/src/timer.h b/src/timer.h index 5806a4b6b..9941c3fdd 100644 --- a/src/timer.h +++ b/src/timer.h @@ -1,57 +1,228 @@ #ifndef _TIMER_H_ #define _TIMER_H_ +#include "cpu/cpu.h" -extern int64_t timer_start; +/* Maximum period, currently 1 second. */ +#define MAX_USEC64 1000000ULL +#define MAX_USEC 1000000.0 -#define timer_start_period(cycles) \ - timer_start = cycles; +#define TIMER_SPLIT 2 +#define TIMER_ENABLED 1 -#define timer_end_period(cycles) \ - do \ - { \ - int64_t diff = timer_start - (cycles); \ - timer_count -= diff; \ - timer_start = cycles; \ - if (timer_count <= 0) \ - { \ - timer_process(); \ - timer_update_outstanding(); \ - } \ - } while (0) -#define timer_clock() \ - do \ - { \ - int64_t 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) +#pragma pack(push,1) +typedef struct +{ + uint32_t frac; + uint32_t integer; +} ts_struct_t; +#pragma pack(pop) -extern void timer_process(void); -extern void timer_update_outstanding(void); -extern void timer_reset(void); -extern int64_t timer_add(void (*callback)(void *priv), int64_t *count, int64_t *enable, void *priv); -extern void timer_set_callback(int64_t timer, void (*callback)(void *priv)); +typedef union +{ + uint64_t ts64; + ts_struct_t ts32; +} ts_t; -#define TIMER_ALWAYS_ENABLED &timer_one -extern int64_t timer_count; -extern int64_t timer_one; +/*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_SHIFT 6 + 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 +{ +#ifdef USE_PCEM_TIMER + uint32_t ts_integer; + uint32_t ts_frac; +#else + ts_t ts; +#endif + int flags, pad; /* The flags are defined above. */ + double period; /* This is used for large period timers to count + the microseconds and split the period. */ -extern int64_t TIMER_USEC; + void (*callback)(void *p); + void *p; + + 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*/ +extern void timer_enable(pc_timer_t *timer); +/*Disable timer*/ +extern void timer_disable(pc_timer_t *timer); + +/*Process any pending timers*/ +extern void timer_process(void); + +/*Reset timer system*/ +extern void timer_close(void); +extern void timer_init(void); + +/*Add new timer. If start_timer is set, timer will be enabled with a zero + timestamp - this is useful for permanently enabled timers*/ +extern void timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int start_timer); + +/*1us in 32:32 format*/ +extern uint64_t TIMER_USEC; + +/*True if timer a expires before timer b*/ +#if 0 +#define TIMER_LESS_THAN(a, b) ((int32_t)((a)->ts_integer - (b)->ts_integer) <= 0) +#else +#define TIMER_LESS_THAN(a, b) ((int64_t)((a)->ts.ts64 - (b)->ts.ts64) <= 0) +#endif +/*True if timer a expires before 32 bit integer timestamp b*/ +#if 0 +#define TIMER_LESS_THAN_VAL(a, b) ((int32_t)((a)->ts_integer - (b)) <= 0) +#else +#define TIMER_LESS_THAN_VAL(a, b) ((int32_t)((a)->ts.ts32.integer - (b)) <= 0) +#endif +/*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) + + +/*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) +{ +#if 0 + 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; +#else + timer->ts.ts64 += delay; +#endif + + 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) +{ +#if 0 + 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; +#else + timer->ts.ts64 = 0ULL; + timer->ts.ts32.integer = tsc; + timer->ts.ts64 += delay; +#endif + + timer_enable(timer); +} + + +/*True if timer currently enabled*/ +static __inline int +timer_is_enabled(pc_timer_t *timer) +{ + return !!(timer->flags & TIMER_ENABLED); +} + + +/*Return integer timestamp of timer*/ +static __inline uint32_t +timer_get_ts_int(pc_timer_t *timer) +{ +#if 0 + return timer->ts_integer; +#else + return timer->ts.ts32.integer; +#endif +} + + +/*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) +{ + int64_t remaining; + + if (timer->flags & TIMER_ENABLED) { +#if 0 + remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32); +#else + remaining = (int64_t) (timer->ts.ts64 - (uint64_t)(tsc << 32)); +#endif + + 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) +{ + int64_t remaining; + + if (timer->flags & TIMER_ENABLED) { +#if 0 + remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32); +#else + remaining = (int64_t) (timer->ts.ts64 - (uint64_t)(tsc << 32)); +#endif + + 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; +} + + +/* The API for big timer periods starts here. */ +extern void timer_stop(pc_timer_t *timer); +extern void timer_advance_ex(pc_timer_t *timer, int start); +extern void timer_on(pc_timer_t *timer, double period, int start); +extern void timer_on_auto(pc_timer_t *timer, double period); #endif /*_TIMER_H_*/ diff --git a/src/ui.h b/src/ui.h index 1e9077cdf..4c66d218b 100644 --- a/src/ui.h +++ b/src/ui.h @@ -8,13 +8,13 @@ * * Define the various UI functions. * - * Version: @(#)ui.h 1.0.14 2018/04/24 + * Version: @(#)ui.h 1.0.16 2019/09/22 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_UI_H # define EMU_UI_H @@ -33,6 +33,7 @@ extern "C" { #define MBX_INFO 1 #define MBX_ERROR 2 #define MBX_QUESTION 3 +#define MBX_QUESTION_YN 4 #define MBX_FATAL 0x20 #define MBX_ANSI 0x80 @@ -53,10 +54,12 @@ extern void ui_check_menu_item(int id, int checked); extern wchar_t *ui_window_title(wchar_t *s); extern void ui_status_update(void); extern int ui_sb_find_part(int tag); +extern void ui_sb_set_ready(int ready); extern void ui_sb_update_panes(void); extern void ui_sb_update_tip(int meaning); extern void ui_sb_check_menu_item(int tag, int id, int chk); extern void ui_sb_enable_menu_item(int tag, int id, int val); +extern void ui_sb_timer_callback(int pane); extern void ui_sb_update_icon(int tag, int val); extern void ui_sb_update_icon_state(int tag, int active); extern void ui_sb_set_text_w(wchar_t *wstr); diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 01614c299..648772c77 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -8,7 +8,7 @@ * * ATI 18800 emulation (VGA Edge-16) * - * Version: @(#)vid_ati18800.c 1.0.12 2018/04/29 + * Version: @(#)vid_ati18800.c 1.0.14 2018/10/02 * * Authors: Sarah Walker, * Miran Grca, @@ -22,11 +22,11 @@ #include #include #include "../86box.h" -#include "../cpu/cpu.h" #include "../io.h" #include "../mem.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_ati18800.h" #include "vid_ati_eeprom.h" @@ -63,6 +63,8 @@ typedef struct ati18800_t int index; } ati18800_t; +static video_timings_t timing_ati18800 = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + static void ati18800_out(uint16_t addr, uint8_t val, void *p) { @@ -176,7 +178,7 @@ static void ati18800_recalctimings(svga_t *svga) svga->vblankstart <<= 1; } - if (!svga->scrblank && (ati18800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + if (!svga->scrblank && ((ati18800->regs[0xb0] & 0x02) || (ati18800->regs[0xb0] & 0x04))) /*Extended 256 colour modes*/ { svga->render = svga_render_8bpp_highres; svga->bpp = 8; @@ -190,6 +192,8 @@ static void *ati18800_init(const device_t *info) ati18800_t *ati18800 = malloc(sizeof(ati18800_t)); memset(ati18800, 0, sizeof(ati18800_t)); + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ati18800); + switch (info->local) { #if defined(DEV_BRANCH) && defined(USE_VGAWONDER) case ATI18800_WONDER: @@ -207,7 +211,7 @@ static void *ati18800_init(const device_t *info) break; }; - svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ + svga_init(&ati18800->svga, ati18800, 1 << 20, /*512kb*/ ati18800_recalctimings, ati18800_in, ati18800_out, NULL, diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index e8fda8302..a0c883c33 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -8,7 +8,7 @@ * * ATI 28800 emulation (VGA Charger and Korean VGA) * - * Version: @(#)vid_ati28800.c 1.0.19 2018/05/20 + * Version: @(#)vid_ati28800.c 1.0.27 2019/05/17 * * Authors: Sarah Walker, * Miran Grca, @@ -26,9 +26,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../cpu/cpu.h" #include "../io.h" -#include "../pit.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -38,8 +36,14 @@ #include "vid_ati_eeprom.h" #include "vid_svga.h" #include "vid_svga_render.h" +#include "vid_sc1502x_ramdac.h" +#define VGAWONDERXL 1 +#if defined(DEV_BRANCH) && defined(USE_XL24) +#define VGAWONDERXL24 2 +#endif + #define BIOS_ATIKOR_PATH L"roms/video/ati28800/atikorvga.bin" #define FONT_ATIKOR_PATH L"roms/video/ati28800/ati_ksc5601.rom" @@ -56,35 +60,38 @@ typedef struct ati28800_t { - svga_t svga; - ati_eeprom_t eeprom; - - rom_t bios_rom; - - uint8_t regs[256]; - int index; - - uint32_t memory; + svga_t svga; + ati_eeprom_t eeprom; - 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; + rom_t bios_rom; + + uint8_t regs[256]; + int index; + uint16_t vtotal; + + uint32_t memory; + uint8_t id; + + 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; +static video_timings_t timing_ati28800 = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; + + #ifdef ENABLE_ATI28800_LOG int ati28800_do_log = ENABLE_ATI28800_LOG; -#endif static void ati28800_log(const char *fmt, ...) { -#ifdef ENABLE_ATI28800_LOG va_list ap; if (ati28800_do_log) { @@ -92,354 +99,427 @@ ati28800_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define ati28800_log(fmt, ...) #endif -} -static void ati28800_out(uint16_t addr, uint8_t val, void *p) +static void ati28800_recalctimings(svga_t *svga); + + +static void +ati28800_out(uint16_t addr, uint8_t val, void *p) { - ati28800_t *ati28800 = (ati28800_t *)p; - svga_t *svga = &ati28800->svga; - uint8_t old; - - ati28800_log("ati28800_out : %04X %02X %04X:%04X\n", addr, val, CS, cpu_state.pc); + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t old; - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) - addr ^= 0x60; + ati28800_log("ati28800_out : %04X %02X\n", addr, val); - switch (addr) - { - case 0x1ce: - ati28800->index = val; - break; - case 0x1cf: - old=ati28800->regs[ati28800->index]; - ati28800->regs[ati28800->index] = val; - switch (ati28800->index) - { - case 0xb2: - case 0xbe: - if (ati28800->regs[0xbe] & 8) /*Read/write bank mode*/ - { - svga->read_bank = ((ati28800->regs[0xb2] >> 5) & 7) * 0x10000; - svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; - } - else /*Single bank mode*/ - svga->read_bank = svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; - break; - case 0xb3: - ati_eeprom_write(&ati28800->eeprom, val & 8, val & 2, val & 1); - break; - 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; - - 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); -} + if (((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; -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; - svga_recalctimings(svga); - - } - ati28800_out(oldaddr, val, p); - break; - case 0x3DD: - 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: - ati28800->in_get_korean_font_kind_set = 0; - if(ati28800->get_korean_font_enabled && (ati28800->regs[0xBF] & 0x20)) - { - 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].chr[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; - } - break; - } - default: - ati28800_out(oldaddr, val, p); - break; - } -} - -static uint8_t ati28800_in(uint16_t addr, void *p) -{ - ati28800_t *ati28800 = (ati28800_t *)p; - svga_t *svga = &ati28800->svga; - uint8_t temp; - - if (addr != 0x3da) ati28800_log("ati28800_in : %04X ", addr); - - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; - - switch (addr) - { - case 0x1ce: - temp = ati28800->index; - break; - case 0x1cf: - switch (ati28800->index) - { + switch (addr) { + case 0x1ce: + ati28800->index = val; + break; + case 0x1cf: + old = ati28800->regs[ati28800->index]; + ati28800->regs[ati28800->index] = val; + ati28800_log("ATI 28800 write reg=0x%02X, val=0x%02X\n", ati28800->index, val); + switch (ati28800->index) { + case 0xa3: + ati28800->regs[0xa3] = val & 0x1f; + svga_recalctimings(svga); + break; + case 0xa6: + ati28800->regs[0xa6] = val & 0xc9; + break; + case 0xab: + ati28800->regs[0xab] = val & 0xdf; + break; case 0xb0: - if (ati28800->memory == 256) - return 0x08; - else if (ati28800->memory == 512) - return 0x10; - else - return 0x18; - break; + ati28800->regs[0xb0] = val & 0x7d; + svga_recalctimings(svga); + break; + case 0xb1: + ati28800->regs[0xb0] = val & 0x7f; + break; + case 0xb2: + if (ati28800->regs[0xbe] & 0x08) { /* Read/write bank mode */ + svga->read_bank = (((val & 0x01) << 3) | ((val & 0xe0) >> 5)) * 0x10000; + svga->write_bank = ((val & 0x1e) >> 1) * 0x10000; + } else { /* Single bank mode */ + svga->read_bank = ((val & 0x1e) >> 1) * 0x10000; + svga->write_bank = ((val & 0x1e) >> 1) * 0x10000; + } + break; + case 0xb3: + ati28800->regs[0xb3] = val & 0xef; + 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; - case 0xb7: - temp = ati28800->regs[ati28800->index] & ~8; - if (ati_eeprom_read(&ati28800->eeprom)) - temp |= 8; - break; - - default: - temp = ati28800->regs[ati28800->index]; - break; - } - break; + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + sc1502x_ramdac_out(addr, val, svga->ramdac, svga); + return; - case 0x3c2: - if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) - temp = 0; - else - temp = 0x10; - break; - case 0x3D4: - temp = svga->crtcreg; - break; - case 0x3D5: - temp = svga->crtc[svga->crtcreg]; - break; - default: - temp = svga_in(addr, svga); - break; - } - if (addr != 0x3da) ati28800_log("%02X %04X:%04X\n", temp, CS,cpu_state.pc); - return temp; + 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 ((ati28800->regs[0xb4] & 0x10) && ((svga->crtcreg == 0x0a) || (svga->crtcreg == 0x0b))) + return; + if ((ati28800->regs[0xb4] & 0x20) && ((svga->crtc[0x08] & 0x7f) && (svga->crtc[0x14] & 0x1f))) + return; + if ((ati28800->regs[0xb4] & 0x40) && (((svga->crtcreg >= 0x00) && (svga->crtcreg <= 0x06)) && + (svga->crtc[0x07] & 0x10) != 0x10)) + return; + + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); } -uint8_t ati28800k_in(uint16_t addr, void *p) + +static 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; - uint8_t temp = 0xFF; + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint16_t oldaddr = addr; - if (addr != 0x3da) ati28800_log("ati28800k_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 && (ati28800->regs[0xBF] & 0x20)) - { - switch(ati28800->get_korean_font_kind >> 8) - { - case 4: /* ROM font */ - temp = fontdatksc5601[ati28800->get_korean_font_base].chr[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].chr[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) ati28800_log("%02X %04X:%04X\n", temp, CS,cpu_state.pc); - return temp; -} + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; -static void ati28800_recalctimings(svga_t *svga) + switch (addr) { + case 0x1CF: + if (ati28800->index == 0xBF && ((ati28800->regs[0xBF] ^ val) & 0x20)) { + ati28800->ksc5601_mode_enabled = val & 0x20; + svga_recalctimings(svga); + } + ati28800_out(oldaddr, val, p); + break; + case 0x3DD: + 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: + 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].chr[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; + } + break; + } + default: + ati28800_out(oldaddr, val, p); + break; + } +} + + +static uint8_t +ati28800_in(uint16_t addr, void *p) { - ati28800_t *ati28800 = (ati28800_t *)svga->p; + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t temp; - switch(((ati28800->regs[0xbe] & 0x10) >> 1) | ((ati28800->regs[0xb9] & 2) << 1) | ((svga->miscout & 0x0C) >> 2)) - { - case 0x00: svga->clock = cpuclock / 42954000.0; break; - case 0x01: svga->clock = cpuclock / 48771000.0; break; - case 0x03: svga->clock = cpuclock / 36000000.0; break; - case 0x04: svga->clock = cpuclock / 50350000.0; break; - case 0x05: svga->clock = cpuclock / 56640000.0; break; - case 0x07: svga->clock = cpuclock / 44900000.0; break; - case 0x08: svga->clock = cpuclock / 30240000.0; break; - case 0x09: svga->clock = cpuclock / 32000000.0; break; - case 0x0A: svga->clock = cpuclock / 37500000.0; break; - case 0x0B: svga->clock = cpuclock / 39000000.0; break; - case 0x0C: svga->clock = cpuclock / 40000000.0; break; - case 0x0D: svga->clock = cpuclock / 56644000.0; break; - case 0x0E: svga->clock = cpuclock / 75000000.0; break; - case 0x0F: svga->clock = cpuclock / 65000000.0; break; - default: break; - } + if (addr != 0x3da) + ati28800_log("ati28800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; - if(ati28800->regs[0xb8] & 0x40) svga->clock *= 2; + switch (addr) { + case 0x1ce: + temp = ati28800->index; + break; + case 0x1cf: + switch (ati28800->index) { + case 0xa0: + temp = 0x10; + break; + case 0xaa: + temp = ati28800->id; + break; + case 0xb0: + if (ati28800->memory == 1024) + temp = 0x08; + else if (ati28800->memory == 512) + temp = 0x10; + else + temp = 0x00; + break; + case 0xb7: + temp = ati28800->regs[ati28800->index] & ~8; + if (ati_eeprom_read(&ati28800->eeprom)) + temp |= 8; + break; + + default: + temp = ati28800->regs[ati28800->index]; + break; + } + break; + + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return sc1502x_ramdac_in(addr, svga->ramdac, svga); + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } + if (addr != 0x3da) + ati28800_log("%02X\n", temp); + return temp; +} - if (ati28800->regs[0xb6] & 0x10) - { - svga->hdisp <<= 1; - svga->htotal <<= 1; - svga->rowoffset <<= 1; +static 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) + ati28800_log("ati28800k_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].chr[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].chr[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) + ati28800_log("%02X\n", temp); + return temp; +} + + +static void +ati28800_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *)svga->p; + + 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 0x02: ati28800_log ("clock 2\n"); 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 0x06: ati28800_log ("clock 2\n"); 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)) / 40000000.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[0xa3] & 0x10) + svga->ma |= 0x10000; + + if (ati28800->regs[0xb0] & 0x40) + svga->ma |= 0x20000; + + if (ati28800->regs[0xb6] & 0x10) { + svga->hdisp <<= 1; + svga->htotal <<= 1; + svga->rowoffset <<= 1; + } + + if (svga->crtc[0x17] & 4) { + svga->vtotal <<= 1; + svga->dispend <<= 1; + svga->vsyncstart <<= 1; + svga->split <<= 1; + svga->vblankstart <<= 1; + } + + if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) { /* Extended 256 colour modes */ + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; + svga->rowoffset <<= 1; + svga->ma <<= 1; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp >>= 1; + svga->rowoffset <<= 1; + svga->ma <<= 1; + break; } - - if(svga->crtc[0x17] & 4) - { - svga->vtotal <<= 1; - svga->dispend <<= 1; - svga->vsyncstart <<= 1; - svga->split <<= 1; - svga->vblankstart <<= 1; - } - - if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ - { - svga->render = svga_render_8bpp_highres; - svga->bpp = 8; - svga->rowoffset <<= 1; - svga->ma <<= 1; - } + } } -void ati28800k_recalctimings(svga_t *svga) + +static void +ati28800k_recalctimings(svga_t *svga) { - ati28800_t *ati28800 = (ati28800_t *) svga->p; + ati28800_t *ati28800 = (ati28800_t *) svga->p; - ati28800_recalctimings(svga); + ati28800_recalctimings(svga); - if (svga->render == svga_render_text_80 && ati28800->ksc5601_mode_enabled) - { - svga->render = svga_render_text_80_ksc5601; - } + if (svga->render == svga_render_text_80 && ati28800->ksc5601_mode_enabled) + svga->render = svga_render_text_80_ksc5601; } + void * ati28800k_init(const device_t *info) { - ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); - memset(ati28800, 0, sizeof(ati28800_t)); + ati28800_t *ati28800 = (ati28800_t *) malloc(sizeof(ati28800_t)); + memset(ati28800, 0, sizeof(ati28800_t)); - ati28800->memory = device_get_config_int("memory"); - - 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, BIOS_ATIKOR_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - loadfont(FONT_ATIKOR_PATH, 6); - - svga_init(&ati28800->svga, ati28800, ati28800->memory << 10, /*Memory size, default 512KB*/ - ati28800k_recalctimings, - ati28800k_in, ati28800k_out, - NULL, - NULL); + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ati28800); - 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->memory = device_get_config_int("memory"); - ati28800->svga.miscout = 1; + 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; - ati_eeprom_load(&ati28800->eeprom, L"atikorvga.nvr", 0); + rom_init(&ati28800->bios_rom, BIOS_ATIKOR_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont(FONT_ATIKOR_PATH, 6); - return ati28800; + svga_init(&ati28800->svga, ati28800, ati28800->memory << 10, /*Memory size, default 512KB*/ + ati28800k_recalctimings, + ati28800k_in, ati28800k_out, + NULL, + NULL); + + ati28800->svga.ramdac = device_add(&sc1502x_ramdac_device); + + 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; + + ati_eeprom_load(&ati28800->eeprom, L"atikorvga.nvr", 0); + + return ati28800; } + static void * ati28800_init(const device_t *info) { - ati28800_t *ati; - ati = malloc(sizeof(ati28800_t)); - memset(ati, 0x00, sizeof(ati28800_t)); + ati28800_t *ati28800; + ati28800 = malloc(sizeof(ati28800_t)); + memset(ati28800, 0x00, sizeof(ati28800_t)); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ati28800); + + ati28800->memory = device_get_config_int("memory"); - ati->memory = device_get_config_int("memory"); - switch(info->local) { - case GFX_VGAWONDERXL: - rom_init_interleaved(&ati->bios_rom, + case VGAWONDERXL: + ati28800->id = 6; + rom_init_interleaved(&ati28800->bios_rom, BIOS_VGAXL_EVEN_PATH, BIOS_VGAXL_ODD_PATH, 0xc0000, 0x10000, 0xffff, @@ -447,8 +527,9 @@ ati28800_init(const device_t *info) break; #if defined(DEV_BRANCH) && defined(USE_XL24) - case GFX_VGAWONDERXL24: - rom_init_interleaved(&ati->bios_rom, + case VGAWONDERXL24: + ati28800->id = 6; + rom_init_interleaved(&ati28800->bios_rom, BIOS_XL24_EVEN_PATH, BIOS_XL24_ODD_PATH, 0xc0000, 0x10000, 0xffff, @@ -457,31 +538,48 @@ ati28800_init(const device_t *info) #endif default: - rom_init(&ati->bios_rom, + ati28800->id = 5; + rom_init(&ati28800->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); break; } - svga_init(&ati->svga, ati, ati->memory << 10, /*default: 512kb*/ + svga_init(&ati28800->svga, ati28800, ati28800->memory << 10, /*default: 512kb*/ ati28800_recalctimings, ati28800_in, ati28800_out, NULL, NULL); + ati28800->svga.ramdac = device_add(&sc1502x_ramdac_device); + io_sethandler(0x01ce, 2, ati28800_in, NULL, NULL, - ati28800_out, NULL, NULL, ati); + ati28800_out, NULL, NULL, ati28800); io_sethandler(0x03c0, 32, ati28800_in, NULL, NULL, - ati28800_out, NULL, NULL, ati); + ati28800_out, NULL, NULL, ati28800); - ati->svga.miscout = 1; + ati28800->svga.miscout = 1; - ati_eeprom_load(&ati->eeprom, L"ati28800.nvr", 0); + switch (info->local) { + case VGAWONDERXL: + ati_eeprom_load(&ati28800->eeprom, L"ati28800xl.nvr", 0); + break; - return(ati); +#if defined(DEV_BRANCH) && defined(USE_XL24) + case VGAWONDERXL24: + ati_eeprom_load(&ati28800->eeprom, L"ati28800xl24.nvr", 0); + break; +#endif + + default: + ati_eeprom_load(&ati28800->eeprom, L"ati28800.nvr", 0); + break; + } + + return(ati28800); } @@ -518,11 +616,11 @@ ati28800_wonderxl24_available(void) static void ati28800_close(void *priv) { - ati28800_t *ati = (ati28800_t *)priv; + ati28800_t *ati28800 = (ati28800_t *)priv; - svga_close(&ati->svga); + svga_close(&ati28800->svga); - free(ati); + free(ati28800); } @@ -538,9 +636,9 @@ ati28800_speed_changed(void *p) static void ati28800_force_redraw(void *priv) { - ati28800_t *ati = (ati28800_t *)priv; + ati28800_t *ati28800 = (ati28800_t *)priv; - ati->svga.fullchange = changeframecount; + ati28800->svga.fullchange = changeframecount; } @@ -556,7 +654,7 @@ static const device_config_t ati28800_config[] = "512 kB", 512 }, { - "1024 kB", 1024 + "1 MB", 1024 }, { "" @@ -622,7 +720,7 @@ const device_t compaq_ati28800_device = { "Compaq ATI-28800", DEVICE_ISA, - GFX_VGAWONDERXL, + VGAWONDERXL, ati28800_init, ati28800_close, NULL, compaq_ati28800_available, ati28800_speed_changed, @@ -635,7 +733,7 @@ const device_t ati28800_wonderxl24_device = { "ATI-28800 (VGA Wonder XL24)", DEVICE_ISA, - GFX_VGAWONDERXL24, + VGAWONDERXL24, ati28800_init, ati28800_close, NULL, ati28800_wonderxl24_available, ati28800_speed_changed, diff --git a/src/video/vid_ati68860_ramdac.c b/src/video/vid_ati68860_ramdac.c index 89a9827d3..c814352b2 100644 --- a/src/video/vid_ati68860_ramdac.c +++ b/src/video/vid_ati68860_ramdac.c @@ -28,170 +28,203 @@ * 7 If set can remove "snow" in some cases * (A860_Delay_L ?) ?? * - * Version: @(#)vid_ati68860.c 1.0.3 2017/11/04 + * Version: @(#)vid_ati68860.c 1.0.5 2018/10/04 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "../86box.h" +#include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_ati68860_ramdac.h" #include "vid_svga_render.h" -void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) +void +ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) { - switch (addr) - { - case 0: - svga_out(0x3c8, val, svga); - break; - case 1: - svga_out(0x3c9, val, svga); - break; - case 2: - svga_out(0x3c6, val, svga); - break; - case 3: - svga_out(0x3c7, val, svga); - break; - default: - ramdac->regs[addr & 0xf] = val; - switch (addr & 0xf) - { - case 0x4: - ramdac->dac_write = val; - ramdac->dac_pos = 0; - break; - case 0x5: - switch (ramdac->dac_pos) - { - case 0: - ramdac->dac_r = val; - ramdac->dac_pos++; - break; - case 1: - ramdac->dac_g = val; - ramdac->dac_pos++; - break; - case 2: - if (ramdac->dac_write > 1) - break; - ramdac->pal[ramdac->dac_write].r = ramdac->dac_r; - ramdac->pal[ramdac->dac_write].g = ramdac->dac_g; - ramdac->pal[ramdac->dac_write].b = val; - if (ramdac->ramdac_type == RAMDAC_8BIT) - ramdac->pallook[ramdac->dac_write] = makecol32(ramdac->pal[ramdac->dac_write].r, ramdac->pal[ramdac->dac_write].g, ramdac->pal[ramdac->dac_write].b); - else - ramdac->pallook[ramdac->dac_write] = makecol32((ramdac->pal[ramdac->dac_write].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].b & 0x3f) * 4); - ramdac->dac_pos = 0; - ramdac->dac_write = (ramdac->dac_write + 1) & 255; - break; - } - break; - - case 0xb: - switch (val) - { - case 0x82: - ramdac->render = svga_render_4bpp_highres; - break; - case 0x83: - ramdac->render = svga_render_8bpp_highres; - break; - case 0xa0: case 0xb0: - ramdac->render = svga_render_15bpp_highres; - break; - case 0xa1: case 0xb1: - ramdac->render = svga_render_16bpp_highres; - break; - case 0xc0: case 0xd0: - ramdac->render = svga_render_24bpp_highres; - break; - case 0xe2: case 0xf7: - ramdac->render = svga_render_32bpp_highres; - break; - case 0xe3: - ramdac->render = svga_render_ABGR8888_highres; - break; - case 0xf2: - ramdac->render = svga_render_RGBA8888_highres; - break; - default: - ramdac->render = svga_render_8bpp_highres; - break; - } - break; - case 0xc: - svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT); - break; - } - break; - } + switch (addr) { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + default: + ramdac->regs[addr & 0xf] = val; + switch (addr & 0xf) { + case 0x4: + ramdac->dac_addr = val; + ramdac->dac_pos = 0; + break; + case 0x5: + switch (ramdac->dac_pos) { + case 0: + ramdac->dac_r = val; + ramdac->dac_pos++; + break; + case 1: + ramdac->dac_g = val; + ramdac->dac_pos++; + break; + case 2: + if (ramdac->dac_addr > 1) + break; + ramdac->pal[ramdac->dac_addr].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_addr].g = ramdac->dac_g; + ramdac->pal[ramdac->dac_addr].b = val; + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[ramdac->dac_addr] = makecol32(ramdac->pal[ramdac->dac_addr].r, + ramdac->pal[ramdac->dac_addr].g, + ramdac->pal[ramdac->dac_addr].b); + else + ramdac->pallook[ramdac->dac_addr] = makecol32(video_6to8[ramdac->pal[ramdac->dac_addr].r & 0x3f], + video_6to8[ramdac->pal[ramdac->dac_addr].g & 0x3f], + video_6to8[ramdac->pal[ramdac->dac_addr].b & 0x3f]); + ramdac->dac_pos = 0; + ramdac->dac_addr = (ramdac->dac_addr + 1) & 255; + break; + } + break; + case 0xb: + switch (val) { + case 0x82: + ramdac->render = svga_render_4bpp_highres; + break; + case 0x83: + ramdac->render = svga_render_8bpp_highres; + break; + case 0xa0: case 0xb0: + ramdac->render = svga_render_15bpp_highres; + break; + case 0xa1: case 0xb1: + ramdac->render = svga_render_16bpp_highres; + break; + case 0xc0: case 0xd0: + ramdac->render = svga_render_24bpp_highres; + break; + case 0xe2: case 0xf7: + ramdac->render = svga_render_32bpp_highres; + break; + case 0xe3: + ramdac->render = svga_render_ABGR8888_highres; + break; + case 0xf2: + ramdac->render = svga_render_RGBA8888_highres; + break; + default: + ramdac->render = svga_render_8bpp_highres; + break; + } + break; + case 0xc: + svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT); + break; + } + break; + } } -uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga) +uint8_t +ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga) { - uint8_t ret = 0; - switch (addr) - { - case 0: - ret = svga_in(0x3c8, svga); - break; - case 1: - ret = svga_in(0x3c9, svga); - break; - case 2: - ret = svga_in(0x3c6, svga); - break; - case 3: - ret = svga_in(0x3c7, svga); - break; - case 4: case 8: - ret = 2; - break; - case 6: case 0xa: - ret = 0x1d; - break; - case 0xf: - ret = 0xd0; - break; - - default: - ret = ramdac->regs[addr & 0xf]; - break; - } - return ret; + uint8_t temp = 0; + + switch (addr) { + case 0: + temp = svga_in(0x3c8, svga); + break; + case 1: + temp = svga_in(0x3c9, svga); + break; + case 2: + temp = svga_in(0x3c6, svga); + break; + case 3: + temp = svga_in(0x3c7, svga); + break; + case 4: case 8: + temp = 2; + break; + case 6: case 0xa: + temp = 0x1d; + break; + case 0xf: + temp = 0xd0; + break; + + default: + temp = ramdac->regs[addr & 0xf]; + break; + } + + return temp; } -void ati68860_ramdac_init(ati68860_ramdac_t *ramdac) + +void +ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type) { - ramdac->render = svga_render_8bpp_highres; + int c; + + if (ramdac->ramdac_type != type) { + ramdac->ramdac_type = type; + + for (c = 0; c < 2; c++) { + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g, + ramdac->pal[c].b); + else + ramdac->pallook[c] = makecol32(video_6to8[ramdac->pal[c].r & 0x3f], video_6to8[ramdac->pal[c].g & 0x3f], + video_6to8[ramdac->pal[c].b & 0x3f]); + } + } } -void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type) + +static void * +ati68860_ramdac_init(const device_t *info) { - int c; - - if (ramdac->ramdac_type != type) - { - ramdac->ramdac_type = type; - - for (c = 0; c < 2; c++) - { - if (ramdac->ramdac_type == RAMDAC_8BIT) - ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g, ramdac->pal[c].b); - else - ramdac->pallook[c] = makecol32((ramdac->pal[c].r & 0x3f) * 4, (ramdac->pal[c].g & 0x3f) * 4, (ramdac->pal[c].b & 0x3f) * 4); - } - } + ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) malloc(sizeof(ati68860_ramdac_t)); + memset(ramdac, 0, sizeof(ati68860_ramdac_t)); + + ramdac->render = svga_render_8bpp_highres; + + return ramdac; } + + +static void +ati68860_ramdac_close(void *priv) +{ + ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + + +const device_t ati68860_ramdac_device = +{ + "ATI-68860 RAMDAC", + 0, 0, + ati68860_ramdac_init, ati68860_ramdac_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_ati68860_ramdac.h b/src/video/vid_ati68860_ramdac.h index c71376b42..33e59ebc3 100644 --- a/src/video/vid_ati68860_ramdac.h +++ b/src/video/vid_ati68860_ramdac.h @@ -1,20 +1,36 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * ATI 68860 RAMDAC emulation header (for Mach64) + * + * Version: @(#)vid_ati68860.h 1.0.0 2018/10/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ typedef struct ati68860_ramdac_t { - uint8_t regs[16]; - void (*render)(struct svga_t *svga); - - int dac_write, dac_pos; - int dac_r, dac_g; - PALETTE pal; - uint32_t pallook[2]; - - int ramdac_type; + uint8_t regs[16]; + void (*render)(struct svga_t *svga); + + int dac_addr, dac_pos; + int dac_r, dac_g; + PALETTE pal; + uint32_t pallook[2]; + + int ramdac_type; } ati68860_ramdac_t; -void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga); -uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga); -void ati68860_ramdac_init(ati68860_ramdac_t *ramdac); -void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type); +extern void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga); +extern uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga); +extern void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type); + +extern const device_t ati68860_ramdac_device; diff --git a/src/video/vid_ati_eeprom.c b/src/video/vid_ati_eeprom.c index 4bcd9d702..3a01bfedd 100644 --- a/src/video/vid_ati_eeprom.c +++ b/src/video/vid_ati_eeprom.c @@ -23,6 +23,7 @@ #include "../86box.h" #include "../device.h" #include "../mem.h" +#include "../timer.h" #include "../nvr.h" #include "vid_ati_eeprom.h" diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index cac55a2e8..03f7309f3 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -8,13 +8,13 @@ * * ATi Mach64 graphics card emulation. * - * Version: @(#)vid_ati_mach64.c 1.0.22 2018/07/16 + * Version: @(#)vid_ati_mach64.c 1.0.27 2019/09/28 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -24,11 +24,10 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../cpu/cpu.h" -#include "../machine/machine.h" #include "../device.h" #include "../io.h" #include "../mem.h" +#include "../timer.h" #include "../pci.h" #include "../rom.h" #include "../plat.h" @@ -87,9 +86,7 @@ typedef struct mach64_t mem_mapping_t mmio_linear_mapping; mem_mapping_t mmio_linear_mapping_2; - ati68860_ramdac_t ramdac; ati_eeprom_t eeprom; - ics2595_t ics2595; svga_t svga; rom_t bios_rom; @@ -256,6 +253,9 @@ typedef struct mach64_t int overlay_v_acc; } mach64_t; +static video_timings_t timing_mach64_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; +static video_timings_t timing_mach64_vlb_pci = {VIDEO_BUS, 2, 2, 1, 20, 20, 21}; + enum { SRC_BG = 0, @@ -345,13 +345,11 @@ void mach64_ext_writel(uint32_t addr, uint32_t val, void *priv); #ifdef ENABLE_MACH64_LOG int mach64_do_log = ENABLE_MACH64_LOG; -#endif static void mach64_log(const char *fmt, ...) { -#ifdef ENABLE_MACH64_LOG va_list ap; if (mach64_do_log) { @@ -359,8 +357,10 @@ mach64_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define mach64_log(fmt, ...) +#endif void mach64_out(uint16_t addr, uint8_t val, void *p) @@ -385,7 +385,7 @@ void mach64_out(uint16_t addr, uint8_t val, void *p) case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: if (mach64->type == MACH64_GX) - ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, svga); + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, mach64->svga.ramdac, svga); else svga_out(addr, val, svga); return; @@ -444,7 +444,7 @@ uint8_t mach64_in(uint16_t addr, void *p) case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: if (mach64->type == MACH64_GX) - return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, svga); + return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), mach64->svga.ramdac, svga); return svga_in(addr, svga); case 0x3D4: @@ -460,7 +460,9 @@ uint8_t mach64_in(uint16_t addr, void *p) void mach64_recalctimings(svga_t *svga) { mach64_t *mach64 = (mach64_t *)svga->p; - + ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) svga->ramdac; + ics2595_t *clock_gen = (ics2595_t *) svga->clock_gen; + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) { svga->vtotal = (mach64->crtc_v_total_disp & 2047) + 1; @@ -469,7 +471,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 * (double)(1ull << 32)) / clock_gen->output_clock; svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; svga->linedbl = svga->rowcount = 0; svga->split = 0xffffff; @@ -477,7 +479,7 @@ void mach64_recalctimings(svga_t *svga) svga->rowcount = mach64->crtc_gen_cntl & 1; svga->rowoffset <<= 1; if (mach64->type == MACH64_GX) - svga->render = mach64->ramdac.render; + svga->render = ramdac->render; switch ((mach64->crtc_gen_cntl >> 8) & 7) { case 1: @@ -1712,10 +1714,12 @@ static void mach64_vblank_start(svga_t *svga) uint8_t mach64_ext_readb(uint32_t addr, void *p) { mach64_t *mach64 = (mach64_t *)p; + ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) mach64->svga.ramdac; + uint8_t ret; if (!(addr & 0x400)) { - mach64_log("nmach64_ext_readb: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); + mach64_log("nmach64_ext_readb: addr=%04x\n", addr); switch (addr & 0x3ff) { case 0x00: case 0x01: case 0x02: case 0x03: @@ -1836,9 +1840,9 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) case 0xc0: case 0xc1: case 0xc2: case 0xc3: if (mach64->type == MACH64_GX) - ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), ramdac, &mach64->svga); else - ret = ati68860_ramdac_in(addr & 3, &mach64->ramdac, &mach64->svga); + ret = ati68860_ramdac_in(addr & 3, ramdac, &mach64->svga); break; case 0xc4: case 0xc5: case 0xc6: case 0xc7: if (mach64->type == MACH64_VT2) @@ -2082,7 +2086,7 @@ uint16_t mach64_ext_readw(uint32_t addr, void *p) uint16_t ret; if (!(addr & 0x400)) { - mach64_log("nmach64_ext_readw: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); + mach64_log("nmach64_ext_readw: addr=%04x\n", addr); ret = 0xffff; } else switch (addr & 0x3ff) @@ -2101,7 +2105,7 @@ uint32_t mach64_ext_readl(uint32_t addr, void *p) uint32_t ret; if (!(addr & 0x400)) { - mach64_log("nmach64_ext_readl: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); + mach64_log("nmach64_ext_readl: addr=%04x\n", addr); ret = 0xffffffff; } else switch (addr & 0x3ff) @@ -2132,8 +2136,10 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) { mach64_t *mach64 = (mach64_t *)p; svga_t *svga = &mach64->svga; + ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) svga->ramdac; + ics2595_t *clock_gen = (ics2595_t *) svga->clock_gen; - mach64_log("mach64_ext_writeb : addr %08X val %02X %04x(%08x):%08x\n", addr, val, CS,cs,cpu_state.pc); + mach64_log("mach64_ext_writeb : addr %08X val %02X\n", addr, val); if (!(addr & 0x400)) { @@ -2248,12 +2254,12 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) case 0x60: case 0x61: case 0x62: case 0x63: WRITE8(addr, mach64->cur_clr0, val); if (mach64->type == MACH64_VT2) - mach64->ramdac.pallook[0] = makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff); + ramdac->pallook[0] = makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff); break; case 0x64: case 0x65: case 0x66: case 0x67: WRITE8(addr, mach64->cur_clr1, val); if (mach64->type == MACH64_VT2) - mach64->ramdac.pallook[1] = makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff); + ramdac->pallook[1] = makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff); break; case 0x68: case 0x69: case 0x6a: case 0x6b: WRITE8(addr, mach64->cur_offset, val); @@ -2283,11 +2289,11 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) case 0x90: case 0x91: case 0x92: case 0x93: WRITE8(addr, mach64->clock_cntl, val); if (mach64->type == MACH64_GX) - ics2595_write(&mach64->ics2595, val & 0x40, val & 0xf); + ics2595_write(clock_gen, val & 0x40, val & 0xf); else { pll_write(mach64, addr, val); - mach64->ics2595.output_clock = mach64->pll_freq[mach64->clock_cntl & 3]; + clock_gen->output_clock = mach64->pll_freq[mach64->clock_cntl & 3]; } svga_recalctimings(&mach64->svga); break; @@ -2315,14 +2321,14 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) case 0xc0: case 0xc1: case 0xc2: case 0xc3: if (mach64->type == MACH64_GX) - ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, ramdac, &mach64->svga); else - ati68860_ramdac_out(addr & 3, val, &mach64->ramdac, &mach64->svga); + ati68860_ramdac_out(addr & 3, val, ramdac, &mach64->svga); break; case 0xc4: case 0xc5: case 0xc6: case 0xc7: WRITE8(addr, mach64->dac_cntl, val); svga_set_ramdac_type(svga, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); - ati68860_set_ramdac_type(&mach64->ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + ati68860_set_ramdac_type(ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: @@ -2350,7 +2356,7 @@ void mach64_ext_writew(uint32_t addr, uint16_t val, void *p) mach64_log("mach64_ext_writew : addr %08X val %04X\n", addr, val); if (!(addr & 0x400)) { - mach64_log("nmach64_ext_writew: addr=%04x val=%04x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc); + mach64_log("nmach64_ext_writew: addr=%04x val=%04x\n", addr, val); mach64_ext_writeb(addr, val, p); mach64_ext_writeb(addr + 1, val >> 8, p); @@ -2374,7 +2380,7 @@ void mach64_ext_writel(uint32_t addr, uint32_t val, void *p) mach64_log("mach64_ext_writel : addr %08X val %08X\n", addr, val); if (!(addr & 0x400)) { - mach64_log("nmach64_ext_writel: addr=%04x val=%08x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc); + mach64_log("nmach64_ext_writel: addr=%04x val=%08x\n", addr, val); mach64_ext_writew(addr, val, p); mach64_ext_writew(addr + 2, val >> 16, p); @@ -2395,7 +2401,9 @@ void mach64_ext_writel(uint32_t addr, uint32_t val, void *p) uint8_t mach64_ext_inb(uint16_t port, void *p) { mach64_t *mach64 = (mach64_t *)p; + ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) mach64->svga.ramdac; uint8_t ret; + switch (port) { case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: @@ -2480,9 +2488,9 @@ uint8_t mach64_ext_inb(uint16_t port, void *p) case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: if (mach64->type == MACH64_GX) - ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), ramdac, &mach64->svga); else - ret = ati68860_ramdac_in(port & 3, &mach64->ramdac, &mach64->svga); + ret = ati68860_ramdac_in(port & 3, ramdac, &mach64->svga); break; case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: @@ -2510,7 +2518,7 @@ uint8_t mach64_ext_inb(uint16_t port, void *p) ret = 0; break; } - mach64_log("mach64_ext_inb : port %04X ret %02X %04X:%04X\n", port, ret, CS,cpu_state.pc); + mach64_log("mach64_ext_inb : port %04X ret %02X\n", port, ret); return ret; } uint16_t mach64_ext_inw(uint16_t port, void *p) @@ -2550,7 +2558,9 @@ uint32_t mach64_ext_inl(uint16_t port, void *p) void mach64_ext_outb(uint16_t port, uint8_t val, void *p) { mach64_t *mach64 = (mach64_t *)p; - mach64_log("mach64_ext_outb : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); + ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) mach64->svga.ramdac; + + mach64_log("mach64_ext_outb : port %04X val %02X\n", port, val); switch (port) { case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: @@ -2631,9 +2641,9 @@ void mach64_ext_outb(uint16_t port, uint8_t val, void *p) case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: if (mach64->type == MACH64_GX) - ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, ramdac, &mach64->svga); else - ati68860_ramdac_out(port & 3, val, &mach64->ramdac, &mach64->svga); + ati68860_ramdac_out(port & 3, val, ramdac, &mach64->svga); break; case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: @@ -2679,7 +2689,7 @@ static uint8_t mach64_block_inb(uint16_t port, void *p) uint8_t ret; ret = mach64_ext_readb(0x400 | (port & 0x3ff), mach64); - mach64_log("mach64_block_inb : port %04X ret %02X %04x:%04x\n", port, ret, CS,cpu_state.pc); + mach64_log("mach64_block_inb : port %04X ret %02X\n", port, ret); return ret; } static uint16_t mach64_block_inw(uint16_t port, void *p) @@ -2775,31 +2785,27 @@ uint32_t mach64_readl(uint32_t addr, void *p) void mach64_hwcursor_draw(svga_t *svga, int displine) { - mach64_t *mach64 = (mach64_t *)svga->p; + ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) svga->ramdac; int x, offset; uint8_t dat; - uint32_t col0 = mach64->ramdac.pallook[0]; - uint32_t col1 = mach64->ramdac.pallook[1]; - int y_add, x_add; + uint32_t col0 = ramdac->pallook[0]; + uint32_t col1 = ramdac->pallook[1]; - y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; - x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; - offset = svga->hwcursor_latch.xoff; for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) { dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + x + svga->x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + x + svga->x_add] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + x + svga->x_add + 1] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + x + svga->x_add + 1] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + x + svga->x_add + 2] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + x + svga->x_add + 2] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + x + svga->x_add + 3] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + x + svga->x_add + 3] ^= 0xFFFFFF; dat >>= 2; offset += 4; } @@ -2958,7 +2964,7 @@ void mach64_overlay_draw(svga_t *svga, int displine) int graphics_key_fn = (mach64->overlay_key_cntl >> 4) & 5; int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; - p = &((uint32_t *)buffer32->line[displine])[32 + mach64->svga.overlay_latch.x]; + p = &buffer32->line[displine][svga->x_add + mach64->svga.overlay_latch.x]; if (mach64->scaler_update) { @@ -3300,10 +3306,10 @@ static void *mach64_common_init(const device_t *info) if (info->flags & DEVICE_PCI) mem_mapping_disable(&mach64->bios_rom.mapping); - mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &mach64->svga); - mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); - mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); - mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &mach64->svga); + mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); + mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); + mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); mem_mapping_disable(&mach64->mmio_mapping); mach64_io_set(mach64); @@ -3317,9 +3323,10 @@ static void *mach64_common_init(const device_t *info) mach64->pci_regs[0x30] = 0x00; mach64->pci_regs[0x32] = 0x0c; mach64->pci_regs[0x33] = 0x00; - - ati68860_ramdac_init(&mach64->ramdac); - + + mach64->svga.ramdac = device_add(&ati68860_ramdac_device); + mach64->svga.clock_gen = device_add(&ics2595_device); + mach64->dst_cntl = 3; mach64->wake_fifo_thread = thread_create_event(); @@ -3333,6 +3340,11 @@ static void *mach64gx_init(const device_t *info) { mach64_t *mach64 = mach64_common_init(info); + if (info->flags & DEVICE_ISA) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_isa); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_vlb_pci); + mach64->type = MACH64_GX; mach64->pci = !!(info->flags & DEVICE_PCI); mach64->pci_id = (int)'X' | ((int)'G' << 8); @@ -3360,13 +3372,15 @@ static void *mach64vt2_init(const device_t *info) mach64_t *mach64 = mach64_common_init(info); svga_t *svga = &mach64->svga; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_vlb_pci); + mach64->type = MACH64_VT2; mach64->pci = 1; mach64->pci_id = 0x5654; 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; + mach64->use_block_decoded_io = 4; ati_eeprom_load(&mach64->eeprom, L"mach64vt.nvr", 1); diff --git a/src/video/vid_att20c49x_ramdac.c b/src/video/vid_att20c49x_ramdac.c new file mode 100644 index 000000000..1077c7e54 --- /dev/null +++ b/src/video/vid_att20c49x_ramdac.c @@ -0,0 +1,157 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of a AT&T 20c490/491 and 492/493 RAMDAC. + * + * Version: @(#)vid_att20c49x_ramdac.c 1.0.1 2019/01/12 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../mem.h" +#include "../timer.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_att20c49x_ramdac.h" + +enum +{ + ATT_490_1 = 0, + ATT_492_3 +}; + +void +att49x_ramdac_out(uint16_t addr, uint8_t val, att49x_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) { + case 0x3C6: + if (ramdac->state == 4) { + ramdac->state = 0; + ramdac->ctrl = val; + if (ramdac->type == ATT_490_1) + svga_set_ramdac_type(svga, (val & 2) ? RAMDAC_8BIT : RAMDAC_6BIT); + switch (val) + { + case 0: + svga->bpp = 8; + break; + + case 0x20: + svga->bpp = 15; + break; + + case 0x40: + svga->bpp = 24; + break; + + case 0x60: + svga->bpp = 16; + break; + + case 0x80: + case 0xa0: + svga->bpp = 15; + break; + + case 0xc0: + svga->bpp = 16; + break; + + case 0xe0: + svga->bpp = 24; + break; + } + svga_recalctimings(svga); + return; + } + ramdac->state = 0; + break; + case 0x3C7: + case 0x3C8: + case 0x3C9: + ramdac->state = 0; + break; + } + + svga_out(addr, val, svga); +} + + +uint8_t +att49x_ramdac_in(uint16_t addr, att49x_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; + temp = svga_in(addr, svga); + + switch (addr) { + case 0x3C6: + if (ramdac->state == 4) { + ramdac->state = 0; + temp = ramdac->ctrl; + break; + } + ramdac->state++; + break; + case 0x3C7: + case 0x3C8: + case 0x3C9: + ramdac->state = 0; + break; + } + + return temp; +} + + +static void * +att49x_ramdac_init(const device_t *info) +{ + att49x_ramdac_t *ramdac = (att49x_ramdac_t *) malloc(sizeof(att49x_ramdac_t)); + memset(ramdac, 0, sizeof(att49x_ramdac_t)); + + ramdac->type = info->local; + + return ramdac; +} + + +static void +att49x_ramdac_close(void *priv) +{ + att49x_ramdac_t *ramdac = (att49x_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + + +const device_t att490_ramdac_device = +{ + "AT&T 20c490/20c491 RAMDAC", + 0, ATT_490_1, + att49x_ramdac_init, att49x_ramdac_close, + NULL, NULL, NULL, NULL +}; + +const device_t att492_ramdac_device = +{ + "AT&T 20c492/20c493 RAMDAC", + 0, ATT_492_3, + att49x_ramdac_init, att49x_ramdac_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_att20c49x_ramdac.h b/src/video/vid_att20c49x_ramdac.h new file mode 100644 index 000000000..2a191afcf --- /dev/null +++ b/src/video/vid_att20c49x_ramdac.h @@ -0,0 +1,32 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header of the emulation of a Sierra SC1502X RAMDAC. + * + * Used by the TLIVESA1 driver for ET4000. + * + * Version: @(#)vid_sc1502x_ramdac.h 1.0.0 2018/10/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +typedef struct +{ + int type; + int state; + uint8_t ctrl; +} att49x_ramdac_t; + +extern void att49x_ramdac_out(uint16_t addr, uint8_t val, att49x_ramdac_t *ramdac, svga_t *svga); +extern uint8_t att49x_ramdac_in(uint16_t addr, att49x_ramdac_t *ramdac, svga_t *svga); + +extern const device_t att490_ramdac_device; +extern const device_t att492_ramdac_device; diff --git a/src/video/vid_av9194.c b/src/video/vid_av9194.c new file mode 100644 index 000000000..ad3f706a1 --- /dev/null +++ b/src/video/vid_av9194.c @@ -0,0 +1,102 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * AV9194 clock generator emulation. + * + * Used by the S3 86c801 (V7-Mirage) card. + * + * Version: @(#)vid_av9194.c 1.0.1 2019/01/12 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "vid_av9194.h" + + +float +av9194_getclock(int clock, void *p) +{ + float ret = 0.0; + + switch (clock & 0x0f) + { + case 0: + ret = 25175000.0; + break; + case 1: + ret = 28322000.0; + break; + case 2: + ret = 40000000.0; + break; + case 4: + ret = 50000000.0; + break; + case 5: + ret = 77000000.0; + break; + case 6: + ret = 36000000.0; + break; + case 7: + ret = 44900000.0; + break; + case 8: + ret = 130000000.0; + break; + case 9: + ret = 120000000.0; + break; + case 0xa: + ret = 80000000.0; + break; + case 0xb: + ret = 31500000.0; + break; + case 0xc: + ret = 110000000.0; + break; + case 0xd: + ret = 65000000.0; + break; + case 0xe: + ret = 75000000.0; + break; + case 0xf: + ret = 94500000.0; + break; + } + + return ret; +} + + +static void * +av9194_init(const device_t *info) +{ + /* Return something non-NULL. */ + return (void *) &av9194_device; +} + + +const device_t av9194_device = +{ + "AV9194 Clock Generator", + 0, 0, + av9194_init, NULL, + NULL, NULL, NULL, NULL +}; + diff --git a/src/video/vid_av9194.h b/src/video/vid_av9194.h new file mode 100644 index 000000000..11760fe53 --- /dev/null +++ b/src/video/vid_av9194.h @@ -0,0 +1,21 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * AV9194 clock generator emulation. + * + * Used by the S3 86c801 (V7-Mirage) card. + * + * Version: @(#)vid_av9194.c 1.0.1 2019/01/12 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +float av9194_getclock(int clock, void *p); + +extern const device_t av9194_device; diff --git a/src/video/vid_bt485_ramdac.c b/src/video/vid_bt485_ramdac.c deleted file mode 100644 index 80087044d..000000000 --- a/src/video/vid_bt485_ramdac.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Brooktree BT485 true colour RAMDAC emulation. - * - * Currently only a dummy stub for logging and passing output - * to the generic SVGA handler. - * - * Version: @(#)vid_bt485_ramdac.c 1.0.2 2017/11/04 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. - */ -#include -#include -#include -#include -#include "../86box.h" -#include "../mem.h" -#include "video.h" -#include "vid_svga.h" -#include "vid_bt485_ramdac.h" - - -int bt485_get_clock_divider(bt485_ramdac_t *ramdac) -{ - return 1; /* Will be implemented later. */ -} - -void bt485_set_rs2(uint8_t rs2, bt485_ramdac_t *ramdac) -{ - ramdac->rs2 = rs2 ? 1 : 0; -} - -void bt485_set_rs3(uint8_t rs3, bt485_ramdac_t *ramdac) -{ - ramdac->rs3 = rs3 ? 1 : 0; -} - -void bt485_ramdac_out(uint16_t addr, uint8_t val, bt485_ramdac_t *ramdac, svga_t *svga) -{ -// /*if (CS!=0xC000) */pclog("OUT RAMDAC %04X %02X %i %04X:%04X %i\n",addr,val,sdac_ramdac.magic_count,CS,pc, sdac_ramdac.rs2); - uint8_t reg = addr & 3; - reg |= (ramdac->rs2 ? 4 : 0); - reg |= (ramdac->rs3 ? 8 : 0); - pclog("BT485 RAMDAC: Writing %02X to register %02X\n", val, reg); - svga_out(addr, val, svga); - return; - - switch (addr) - { - case 0x3C6: - if (val == 0xff) - { - ramdac->rs2 = 0; - ramdac->magic_count = 0; - break; - } - if (ramdac->magic_count < 4) break; - if (ramdac->magic_count == 4) - { - ramdac->command = val; -// pclog("RAMDAC command reg now %02X\n", val); - 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; - } - svga_recalctimings(svga); - } - //ramdac->magic_count = 0; - break; - - case 0x3C7: - ramdac->magic_count = 0; - if (ramdac->rs2) - ramdac->rindex = val; - break; - case 0x3C8: - ramdac->magic_count = 0; - if (ramdac->rs2) - ramdac->windex = val; - break; - case 0x3C9: - ramdac->magic_count = 0; - if (ramdac->rs2) - { - if (!ramdac->reg_ff) ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0xff00) | val; - else ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0x00ff) | (val << 8); - ramdac->reg_ff = !ramdac->reg_ff; -// pclog("RAMDAC reg %02X now %04X\n", ramdac->windex, ramdac->regs[ramdac->windex]); - if (!ramdac->reg_ff) ramdac->windex++; - } - break; - } - svga_out(addr, val, svga); -} - -uint8_t bt485_ramdac_in(uint16_t addr, bt485_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); - uint8_t reg = addr & 3; - reg |= (ramdac->rs2 ? 4 : 0); - reg |= (ramdac->rs3 ? 8 : 0); - pclog("BT485 RAMDAC: Reading register %02X\n", reg); - return svga_in(addr, svga); - - switch (addr) - { - case 0x3C6: - ramdac->reg_ff = 0; - if (ramdac->magic_count < 5) - ramdac->magic_count++; - if (ramdac->magic_count == 4) - { - temp = 0x70; /*SDAC ID*/ - ramdac->rs2 = 1; - } - if (ramdac->magic_count == 5) - { - temp = ramdac->command; - ramdac->magic_count = 0; - } - return temp; - case 0x3C7: -// if (ramdac->magic_count < 4) -// { - ramdac->magic_count=0; -// break; -// } - if (ramdac->rs2) return ramdac->rindex; - break; - case 0x3C8: -// if (ramdac->magic_count < 4) -// { - ramdac->magic_count=0; -// break; -// } - if (ramdac->rs2) return ramdac->windex; - break; - case 0x3C9: -// if (ramdac->magic_count < 4) -// { - ramdac->magic_count=0; -// break; -// } - if (ramdac->rs2) - { - if (!ramdac->reg_ff) temp = ramdac->regs[ramdac->rindex] & 0xff; - else temp = ramdac->regs[ramdac->rindex] >> 8; - ramdac->reg_ff = !ramdac->reg_ff; - if (!ramdac->reg_ff) - { - ramdac->rindex++; - ramdac->magic_count = 0; - } - return temp; - } - break; - } - return svga_in(addr, svga); -} - -float bt485_getclock(int clock, void *p) -{ - bt485_ramdac_t *ramdac = (bt485_ramdac_t *)p; - float t; - int m, n1, n2; -// pclog("SDAC_Getclock %i %04X\n", clock, ramdac->regs[clock]); - if (clock == 0) return 25175000.0; - if (clock == 1) return 28322000.0; - clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ - m = (ramdac->regs[clock] & 0x7f) + 2; - n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; - n2 = ((ramdac->regs[clock] >> 13) & 0x07); - t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); -// pclog("BT485 clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); - return t; -} diff --git a/src/video/vid_bt485_ramdac.h b/src/video/vid_bt485_ramdac.h deleted file mode 100644 index 12d535359..000000000 --- a/src/video/vid_bt485_ramdac.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright holders: Tenshi - see COPYING for more details -*/ -typedef struct bt485_ramdac_t -{ - int magic_count; - uint8_t command; - int windex, rindex; - uint16_t regs[256]; - int reg_ff; - int rs2; - int rs3; -} bt485_ramdac_t; - -void bt485_ramdac_out(uint16_t addr, uint8_t val, bt485_ramdac_t *ramdac, svga_t *svga); -uint8_t bt485_ramdac_in(uint16_t addr, bt485_ramdac_t *ramdac, svga_t *svga); - -float bt485_getclock(int clock, void *p); diff --git a/src/video/vid_bt48x_ramdac.c b/src/video/vid_bt48x_ramdac.c new file mode 100644 index 000000000..53dec87a6 --- /dev/null +++ b/src/video/vid_bt48x_ramdac.c @@ -0,0 +1,513 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the Brooktree BT484-485A true colour RAMDAC + * family. + * + * Version: @(#)vid_bt48x_ramdac.c 1.0.16 2019/01/12 + * + * Authors: Miran Grca, + * TheCollector1995, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 TheCollector1995. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../mem.h" +#include "../timer.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_bt48x_ramdac.h" + + +enum { + BT484 = 0, + ATT20C504, + BT485, + ATT20C505, + BT485A +}; + + +static void +bt48x_set_bpp(bt48x_ramdac_t *ramdac, svga_t *svga) +{ + if ((!(ramdac->cmd_r2 & 0x20)) || ((ramdac->type >= BT485A) && ((ramdac->cmd_r3 & 0x60) == 0x60))) + svga->bpp = 8; + else if ((ramdac->type >= BT485A) && ((ramdac->cmd_r3 & 0x60) == 0x40)) + svga->bpp = 24; + else switch (ramdac->cmd_r1 & 0x60) { + case 0x00: + svga->bpp = 32; + break; + case 0x20: + if (ramdac->cmd_r1 & 0x08) + svga->bpp = 16; + else + svga->bpp = 15; + break; + case 0x40: + svga->bpp = 8; + break; + case 0x60: + svga->bpp = 4; + break; + } + svga_recalctimings(svga); +} + + +void +bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *ramdac, svga_t *svga) +{ + uint32_t o32; + uint8_t *cd; + uint16_t index; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x03ff; + rs |= (!!rs2 << 2); + rs |= (!!rs3 << 3); + if (ramdac->type < BT485) + da_mask = 0x00ff; + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + case 0x03: + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = val; + if (ramdac->type >= BT485) + svga->dac_addr |= ((int) (ramdac->cmd_r3 & 0x03) << 8); + if (svga->dac_status) + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + svga_out(addr, val, svga); + break; + case 0x05: /* Ext Palette Data Register (RS value = 0101) */ + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + index = svga->dac_addr & 3; + ramdac->extpal[index].r = svga->dac_r; + ramdac->extpal[index].g = svga->dac_g; + ramdac->extpal[index].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + ramdac->extpallook[index] = makecol32(ramdac->extpal[index].r, ramdac->extpal[index].g, ramdac->extpal[index].b); + else + ramdac->extpallook[index] = makecol32(video_6to8[ramdac->extpal[index].r & 0x3f], video_6to8[ramdac->extpal[index].g & 0x3f], video_6to8[ramdac->extpal[index].b & 0x3f]); + + if (svga->ext_overscan && !index) { + o32 = svga->overscan_color; + svga->overscan_color = ramdac->extpallook[0]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + svga->dac_addr = (svga->dac_addr + 1) & 0xff; + svga->dac_pos = 0; + break; + } + break; + case 0x06: /* Command Register 0 (RS value = 0110) */ + ramdac->cmd_r0 = val; + svga->ramdac_type = (val & 0x02) ? RAMDAC_8BIT : RAMDAC_6BIT; + break; + case 0x08: /* Command Register 1 (RS value = 1000) */ + ramdac->cmd_r1 = val; + bt48x_set_bpp(ramdac, svga); + break; + case 0x09: /* Command Register 2 (RS value = 1001) */ + ramdac->cmd_r2 = val; + svga->dac_hwcursor.ena = !!(val & 0x03); + bt48x_set_bpp(ramdac, svga); + break; + case 0x0a: + if ((ramdac->type >= BT485) && (ramdac->cmd_r0 & 0x80)) { + switch ((svga->dac_addr & ((ramdac->type >= BT485A) ? 0xff : 0x3f))) { + case 0x01: + /* Command Register 3 (RS value = 1010) */ + ramdac->cmd_r3 = val; + if (ramdac->type >= BT485A) + bt48x_set_bpp(ramdac, svga); + svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = (val & 4) ? 64 : 32; + svga->dac_hwcursor.yoff = (svga->dac_hwcursor.ysize == 32) ? 32 : 0; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_addr = (svga->dac_addr & 0x00ff) | ((val & 0x03) << 8); + svga_recalctimings(svga); + break; + case 0x02: + case 0x20: + case 0x21: + case 0x22: + if (ramdac->type != BT485A) + break; + else if (svga->dac_addr == 2) { + ramdac->cmd_r4 = val; + break; + } + break; + } + } + break; + case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ + index = svga->dac_addr & da_mask; + if ((ramdac->type >= BT485) && (svga->dac_hwcursor.xsize == 64)) + cd = (uint8_t *) ramdac->cursor64_data; + else { + index &= 0xff; + cd = (uint8_t *) ramdac->cursor32_data; + } + + cd[index] = val; + + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x0c: /* Cursor X Low Register (RS value = 1100) */ + ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + break; + case 0x0d: /* Cursor X High Register (RS value = 1101) */ + ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + break; + case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ + ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + break; + case 0x0f: /* Cursor Y High Register (RS value = 1111) */ + ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + break; + } + + return; +} + + +uint8_t +bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp = 0xff; + uint8_t *cd; + uint16_t index; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x03ff; + rs |= (!!rs2 << 2); + rs |= (!!rs3 << 3); + if (ramdac->type < BT485) + da_mask = 0x00ff; + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + temp = svga_in(addr, svga); + break; + case 0x03: /* Palette Read Index Register (RS value = 0011) */ + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + temp = svga->dac_addr & 0xff; + break; + case 0x05: /* Ext Palette Data Register (RS value = 0101) */ + index = (svga->dac_addr - 1) & 3; + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].r; + else + temp = ramdac->extpal[index].r & 0x3f; + break; + case 1: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].g; + else + temp = ramdac->extpal[index].g & 0x3f; + break; + case 2: + svga->dac_pos=0; + svga->dac_addr = svga->dac_addr + 1; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].b; + else + temp = ramdac->extpal[index].b & 0x3f; + break; + } + break; + case 0x06: /* Command Register 0 (RS value = 0110) */ + temp = ramdac->cmd_r0; + break; + case 0x08: /* Command Register 1 (RS value = 1000) */ + temp = ramdac->cmd_r1; + break; + case 0x09: /* Command Register 2 (RS value = 1001) */ + temp = ramdac->cmd_r2; + break; + case 0x0a: + if ((ramdac->type >= BT485) && (ramdac->cmd_r0 & 0x80)) { + switch ((svga->dac_addr & ((ramdac->type >= BT485A) ? 0xff : 0x3f))) { + case 0x00: + default: + temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00); + break; + case 0x01: + temp = ramdac->cmd_r3 & 0xfc; + temp |= (svga->dac_addr & 0x300) >> 8; + break; + case 0x02: + case 0x20: + case 0x21: + case 0x22: + if (ramdac->type != BT485A) + break; + else if (svga->dac_addr == 2) { + temp = ramdac->cmd_r4; + break; + } else { + /* TODO: Red, Green, and Blue Signature Analysis Registers */ + temp = 0xff; + break; + } + break; + } + } else + temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00); + break; + case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ + index = (svga->dac_addr - 1) & da_mask; + if ((ramdac->type >= BT485) && (svga->dac_hwcursor.xsize == 64)) + cd = (uint8_t *) ramdac->cursor64_data; + else { + index &= 0xff; + cd = (uint8_t *) ramdac->cursor32_data; + } + + temp = cd[index]; + + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x0c: /* Cursor X Low Register (RS value = 1100) */ + temp = ramdac->hwc_x & 0xff; + break; + case 0x0d: /* Cursor X High Register (RS value = 1101) */ + temp = (ramdac->hwc_x >> 8) & 0xff; + break; + case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ + temp = ramdac->hwc_y & 0xff; + break; + case 0x0f: /* Cursor Y High Register (RS value = 1111) */ + temp = (ramdac->hwc_y >> 8) & 0xff; + break; + } + + return temp; +} + + +void +bt48x_hwcursor_draw(svga_t *svga, int displine) +{ + int x, xx, comb, b0, b1; + uint16_t dat[2]; + int offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff; + int pitch, bppl, mode, x_pos, y_pos; + uint32_t clr1, clr2, clr3, *p; + uint8_t *cd; + bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) svga->ramdac; + + clr1 = ramdac->extpallook[1]; + clr2 = ramdac->extpallook[2]; + clr3 = ramdac->extpallook[3]; + + /* The planes come in two parts, and each plane is 1bpp, + so a 32x32 cursor has 4 bytes per line, and a 64x64 + cursor has 8 bytes per line. */ + pitch = (svga->dac_hwcursor_latch.xsize >> 3); /* Bytes per line. */ + /* A 32x32 cursor has 128 bytes per line, and a 64x64 + cursor has 512 bytes per line. */ + bppl = (pitch * svga->dac_hwcursor_latch.ysize); /* Bytes per plane. */ + mode = ramdac->cmd_r2 & 0x03; + + if (svga->interlace && svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; + + if (svga->dac_hwcursor_latch.xsize == 64) + cd = (uint8_t *) ramdac->cursor64_data; + else + cd = (uint8_t *) ramdac->cursor32_data; + + for (x = 0; x < svga->dac_hwcursor_latch.xsize; x += 16) { + dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | + cd[svga->dac_hwcursor_latch.addr + 1]; + dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | + cd[svga->dac_hwcursor_latch.addr + bppl + 1]; + + for (xx = 0; xx < 16; xx++) { + b0 = (dat[0] >> (15 - xx)) & 1; + b1 = (dat[1] >> (15 - xx)) & 1; + comb = (b0 | (b1 << 1)); + + y_pos = displine; + x_pos = offset + svga->x_add; + p = buffer32->line[y_pos]; + + if (offset >= svga->dac_hwcursor_latch.x) { + switch (mode) { + case 1: /* Three Color */ + switch (comb) { + case 1: + p[x_pos] = clr1; + break; + case 2: + p[x_pos] = clr2; + break; + case 3: + p[x_pos] = clr3; + break; + } + break; + case 2: /* PM/Windows */ + switch (comb) { + case 0: + p[x_pos] = clr1; + break; + case 1: + p[x_pos] = clr2; + break; + case 3: + p[x_pos] ^= 0xffffff; + break; + } + break; + case 3: /* X-Windows */ + switch (comb) { + case 2: + p[x_pos] = clr1; + break; + case 3: + p[x_pos] = clr2; + break; + } + break; + } + } + offset++; + } + svga->dac_hwcursor_latch.addr += 2; + } + + if (svga->interlace && !svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; +} + + +void * +bt48x_ramdac_init(const device_t *info) +{ + bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) malloc(sizeof(bt48x_ramdac_t)); + memset(ramdac, 0, sizeof(bt48x_ramdac_t)); + + ramdac->type = info->local; + + /* Set the RAM DAC status byte to the correct ID bits. + + Both the BT484 and BT485 datasheets say this: + SR7-SR6: These bits are identification values. SR7=0 and SR6=1. + But all other sources seem to assume SR7=1 and SR6=0. */ + switch (ramdac->type) { + case BT484: + ramdac->status = 0x40; + break; + case ATT20C504: + ramdac->status = 0x40; + break; + case BT485: + ramdac->status = 0x60; + break; + case ATT20C505: + ramdac->status = 0xd0; + break; + case BT485A: + ramdac->status = 0x20; + break; + } + + return ramdac; +} + + +static void +bt48x_ramdac_close(void *priv) +{ + bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + + +const device_t bt484_ramdac_device = +{ + "Brooktree Bt484 RAMDAC", + 0, BT484, + bt48x_ramdac_init, bt48x_ramdac_close, + NULL, NULL, NULL, NULL +}; + +const device_t att20c504_ramdac_device = +{ + "AT&T 20c504 RAMDAC", + 0, ATT20C504, + bt48x_ramdac_init, bt48x_ramdac_close, + NULL, NULL, NULL, NULL +}; + +const device_t bt485_ramdac_device = +{ + "Brooktree Bt485 RAMDAC", + 0, BT485, + bt48x_ramdac_init, bt48x_ramdac_close, + NULL, NULL, NULL, NULL +}; + +const device_t att20c505_ramdac_device = +{ + "AT&T 20c505 RAMDAC", + 0, ATT20C505, + bt48x_ramdac_init, bt48x_ramdac_close, + NULL, NULL, NULL, NULL +}; + +const device_t bt485a_ramdac_device = +{ + "Brooktree Bt485A RAMDAC", + 0, BT485A, + bt48x_ramdac_init, bt48x_ramdac_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_bt48x_ramdac.h b/src/video/vid_bt48x_ramdac.h new file mode 100644 index 000000000..ce952e1e8 --- /dev/null +++ b/src/video/vid_bt48x_ramdac.h @@ -0,0 +1,44 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header of the emulation of the Brooktree BT484-BT485A + * true colour RAMDAC family. + * + * Version: @(#)vid_bt485_ramdac.h 1.0.5 2019/01/12 + * + * Authors: Miran Grca, + * TheCollector1995, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 TheCollector1995. + */ +typedef struct +{ + PALETTE extpal; + uint32_t extpallook[256]; + uint8_t cursor32_data[256]; + uint8_t cursor64_data[1024]; + int hwc_y, hwc_x; + uint8_t cmd_r0; + uint8_t cmd_r1; + uint8_t cmd_r2; + uint8_t cmd_r3; + uint8_t cmd_r4; + uint8_t status; + uint8_t type; +} bt48x_ramdac_t; + +extern void bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *ramdac, svga_t *svga); +extern uint8_t bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *ramdac, svga_t *svga); +extern void bt48x_hwcursor_draw(svga_t *svga, int displine); + +extern const device_t bt484_ramdac_device; +extern const device_t att20c504_ramdac_device; +extern const device_t bt485_ramdac_device; +extern const device_t att20c505_ramdac_device; +extern const device_t bt485a_ramdac_device; diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 6f12a01a5..2cb05a1d2 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -8,13 +8,13 @@ * * Emulation of the old and new IBM CGA graphics cards. * - * Version: @(#)vid_cga.c 1.0.16 2018/04/29 + * Version: @(#)vid_cga.c 1.0.20 2019/09/29 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -25,10 +25,10 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_cga.h" @@ -43,486 +43,535 @@ 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 + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static video_timings_t timing_cga = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + void cga_recalctimings(cga_t *cga); -void cga_out(uint16_t addr, uint8_t val, void *p) -{ - cga_t *cga = (cga_t *)p; - uint8_t old; - switch (addr) - { - case 0x3D4: - cga->crtcreg = val & 31; - return; - case 0x3D5: - old = cga->crtc[cga->crtcreg]; - cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; - if (old != val) - { - if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) - { - fullchange = changeframecount; - cga_recalctimings(cga); - } - } - return; - case 0x3D8: - if (((cga->cgamode ^ val) & 5) != 0) - { - cga->cgamode = val; - update_cga16_color(cga->cgamode); - } - if ((cga->cgamode ^ val) & 1) - { - cga_palette = (cga->rgb_type << 1); - cgapal_rebuild(); +void +cga_out(uint16_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *) p; + uint8_t old; + + switch (addr) { + case 0x3D4: + cga->crtcreg = val & 31; + return; + case 0x3D5: + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; + if (old != val) { + if ((cga->crtcreg < 0xe) || (cga->crtcreg > 0x10)) { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + case 0x3D8: + old = cga->cgamode; + cga->cgamode = val; + + if (old ^ val) { + if ((old ^ val) & 0x05) + update_cga16_color(val); + + cga_recalctimings(cga); + } + return; + case 0x3D9: + old = cga->cgacol; + cga->cgacol = val; + if (old ^ val) + cga_recalctimings(cga); + return; + } +} + + +uint8_t +cga_in(uint16_t addr, void *p) +{ + cga_t *cga = (cga_t *) p; + + uint8_t ret = 0xff; + + switch (addr) { + case 0x3D4: + ret = cga->crtcreg; + break; + case 0x3D5: + ret = cga->crtc[cga->crtcreg]; + break; + case 0x3DA: + ret = cga->cgastat; + break; + } + + return ret; +} + + +void +cga_waitstates(void *p) +{ + int ws_array[16] = {3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8}; + int ws; + + ws = ws_array[cycles & 0xf]; + sub_cycles(ws); +} + + +void +cga_write(uint32_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *) p; + + cga->vram[addr & 0x3fff] = val; + if (cga->snow_enabled) { + 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++; + cga_waitstates(cga); +} + + +uint8_t +cga_read(uint32_t addr, void *p) +{ + cga_t *cga = (cga_t *) p; + + cga_waitstates(cga); + if (cga->snow_enabled) { + 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++; + return cga->vram[addr & 0x3fff]; +} + + +void +cga_recalctimings(cga_t *cga) +{ + double disptime; + double _dispontime, _dispofftime; + + if (cga->cgamode & 1) { + disptime = (double) (cga->crtc[0] + 1); + _dispontime = (double) cga->crtc[1]; + } else { + disptime = (double) ((cga->crtc[0] + 1) << 1); + _dispontime = (double) (cga->crtc[1] << 1); + } + _dispofftime = disptime - _dispontime; + _dispontime = _dispontime * CGACONST; + _dispofftime = _dispofftime * CGACONST; + cga->dispontime = (uint64_t)(_dispontime); + cga->dispofftime = (uint64_t)(_dispofftime); +} + + +void +cga_poll(void *p) +{ + cga_t *cga = (cga_t *)p; + uint16_t ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c, xs_temp, ys_temp; + int oldvc; + uint8_t chr, attr; + uint8_t border; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + + if (!cga->linepos) { + timer_advance_u64(&cga->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(); + } + cga->lastline = cga->displine; + for (c = 0; c < 8; c++) { + if ((cga->cgamode & 0x12) == 0x12) { + buffer32->line[(cga->displine << 1)][c] = + buffer32->line[(cga->displine << 1) + 1][c] = 0; + if (cga->cgamode & 1) { + buffer32->line[(cga->displine << 1)][c + (cga->crtc[1] << 3) + 8] = + buffer32->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 3) + 8] = 0; + } else { + buffer32->line[(cga->displine << 1)][c + (cga->crtc[1] << 4) + 8] = + buffer32->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 4) + 8] = 0; + } + } else { + buffer32->line[(cga->displine << 1)][c] = + buffer32->line[(cga->displine << 1) + 1][c] = (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) { + buffer32->line[(cga->displine << 1)][c + (cga->crtc[1] << 3) + 8] = + buffer32->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 3) + 8] = (cga->cgacol & 15) + 16; + } else { + buffer32->line[(cga->displine << 1)][c + (cga->crtc[1] << 4) + 8] = + buffer32->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 4) + 8] = (cga->cgacol & 15) + 16; + } + } + } + if (cga->cgamode & 1) { + for (x = 0; x < cga->crtc[1]; x++) { + 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); + cols[1] = (attr & 15) + 16; + if (cga->cgamode & 0x20) { + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) + cols[1] = cols[0]; + } else + cols[0] = (attr >> 4) + 16; + if (drawcursor) { + for (c = 0; c < 8; c++) { + buffer32->line[(cga->displine << 1)][(x << 3) + c + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + } else { + for (c = 0; c < 8; c++) { + buffer32->line[(cga->displine << 1)][(x << 3) + c + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + cga->ma++; + } + } else if (!(cga->cgamode & 2)) { + for (x = 0; x < cga->crtc[1]; x++) { + 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); + cols[1] = (attr & 15) + 16; + if (cga->cgamode & 0x20) { + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80)) + cols[1] = cols[0]; + } else + cols[0] = (attr >> 4) + 16; + cga->ma++; + if (drawcursor) { + for (c = 0; c < 8; c++) { + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + } else { + for (c = 0; c < 8; c++) { + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1) + 1][(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; + if (cga->cgamode & 4) { + cols[1] = col | 3; /* Cyan */ + cols[2] = col | 4; /* Red */ + cols[3] = col | 7; /* White */ + } else if (cga->cgacol & 32) { + cols[1] = col | 3; /* Cyan */ + cols[2] = col | 5; /* Magenta */ + cols[3] = col | 7; /* White */ + } else { + cols[1] = col | 2; /* Green */ + cols[2] = col | 4; /* Red */ + cols[3] = col | 6; /* Yellow */ + } + for (x = 0; x < cga->crtc[1]; x++) { + 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++) { + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[dat >> 14]; + dat <<= 2; + } + } + } else { + cols[0] = 0; cols[1] = (cga->cgacol & 15) + 16; + for (x = 0; x < cga->crtc[1]; x++) { + 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++) { + buffer32->line[(cga->displine << 1)][(x << 4) + c + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + c + 8] = + cols[dat >> 15]; + dat <<= 1; + } + } + } + } else { + cols[0] = ((cga->cgamode & 0x12) == 0x12) ? 0 : (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) { + hline(buffer32, 0, (cga->displine << 1), ((cga->crtc[1] << 3) + 16) << 2, cols[0]); + hline(buffer32, 0, (cga->displine << 1) + 1, ((cga->crtc[1] << 3) + 16) << 2, cols[0]); + } else { + hline(buffer32, 0, (cga->displine << 1), ((cga->crtc[1] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, (cga->displine << 1) + 1, ((cga->crtc[1] << 4) + 16) << 2, cols[0]); + } + } + + if (cga->cgamode & 1) + x = (cga->crtc[1] << 3) + 16; + else + x = (cga->crtc[1] << 4) + 16; + + if (cga->composite) { + if (cga->cgamode & 0x10) + border = 0x00; + else + border = cga->cgacol & 0x0f; + + Composite_Process(cga->cgamode, border, x >> 2, buffer32->line[(cga->displine << 1)]); + Composite_Process(cga->cgamode, border, x >> 2, buffer32->line[(cga->displine << 1) + 1]); + } + + 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(&cga->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; + cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + } + switch (cga->crtc[10] & 0x60) { + case 0x20: + cga->cursoron = 0; + break; + case 0x60: + cga->cursoron = cga->cgablink & 0x10; + break; + default: + cga->cursoron = cga->cgablink & 0x08; + break; + } } - cga->cgamode = val; - return; - case 0x3D9: - cga->cgacol = val; - return; - } -} + 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) + 16; + else + x = (cga->crtc[1] << 4) + 16; + cga->lastline++; -uint8_t cga_in(uint16_t addr, void *p) -{ - cga_t *cga = (cga_t *)p; - switch (addr) - { - case 0x3D4: - return cga->crtcreg; - case 0x3D5: - return cga->crtc[cga->crtcreg]; - case 0x3DA: - return cga->cgastat; - } - return 0xFF; -} + xs_temp = x; + ys_temp = (cga->lastline - cga->firstline) << 1; -void cga_waitstates(void *p) -{ - cga_t *cga = (cga_t *)p; - int cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); - - cycles -= 8 - (cycle & 7); + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xs_temp < 64) xs_temp = 656; + if (ys_temp < 32) ys_temp = 400; + if (!enable_overscan) + xs_temp -= 16; - cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); - cycles -= 16 - (cycle & 15); - - cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); - cycles -= 3 - (cycle % 3); -} - -void cga_write(uint32_t addr, uint8_t val, void *p) -{ - cga_t *cga = (cga_t *)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; - } - egawrites++; - cga_waitstates(cga); -} - -uint8_t cga_read(uint32_t addr, void *p) -{ - cga_t *cga = (cga_t *)p; - cga_waitstates(cga); - 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]; - } - egareads++; - return cga->vram[addr & 0x3fff]; -} - -void cga_recalctimings(cga_t *cga) -{ - double disptime; - double _dispontime, _dispofftime; - if (cga->cgamode & 1) - { - disptime = (double) (cga->crtc[0] + 1); - _dispontime = (double) cga->crtc[1]; - } - else - { - disptime = (double) ((cga->crtc[0] + 1) << 1); - _dispontime = (double) (cga->crtc[1] << 1); - } - _dispofftime = disptime - _dispontime; - _dispontime = _dispontime * CGACONST; - _dispofftime = _dispofftime * CGACONST; - cga->dispontime = (int64_t)(_dispontime * (1LL << TIMER_SHIFT)); - cga->dispofftime = (int64_t)(_dispofftime * (1LL << TIMER_SHIFT)); -} - -void cga_poll(void *p) -{ - cga_t *cga = (cga_t *)p; - uint16_t ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x, c; - int oldvc; - uint8_t chr, attr; - uint16_t dat; - int cols[4]; - int col; - int oldsc; - - if (!cga->linepos) - { - cga->vidtime += cga->dispofftime; - cga->cgastat |= 1; - cga->linepos = 1; - oldsc = cga->sc; - if ((cga->crtc[8] & 3) == 3) - cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; - if (cga->cgadispon) - { - if (cga->displine < cga->firstline) - { - cga->firstline = cga->displine; - video_wait_for_buffer(); - } - cga->lastline = cga->displine; - for (c = 0; c < 8; c++) - { - if ((cga->cgamode & 0x12) == 0x12) - { - buffer->line[cga->displine][c] = 0; - if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = 0; - else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = 0; - } - else - { - buffer->line[cga->displine][c] = (cga->cgacol & 15) + 16; - if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = (cga->cgacol & 15) + 16; - else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = (cga->cgacol & 15) + 16; - } - } - if (cga->cgamode & 1) - { - for (x = 0; x < cga->crtc[1]; x++) - { - chr = cga->charbuffer[x << 1]; - attr = cga->charbuffer[(x << 1) + 1]; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); - if (cga->cgamode & 0x20) - { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; - if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) - cols[1] = cols[0]; - } - else - { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; - } - if (drawcursor) - { - for (c = 0; c < 8; c++) - buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; - } - else - { - for (c = 0; c < 8; c++) - buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } - cga->ma++; - } - } - else if (!(cga->cgamode & 2)) - { - for (x = 0; x < cga->crtc[1]; x++) - { - chr = cga->vram[((cga->ma << 1) & 0x3fff)]; - attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); - if (cga->cgamode & 0x20) - { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; - if ((cga->cgablink & 8) && (attr & 0x80)) cols[1] = cols[0]; - } - else - { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; - } - cga->ma++; - if (drawcursor) - { - for (c = 0; c < 8; c++) - buffer->line[cga->displine][(x << 4)+(c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; - } - else - { - for (c = 0; c < 8; c++) - buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->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; - if (cga->cgamode & 4) - { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; - } - else if (cga->cgacol & 32) - { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; - } - else - { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; - } - for (x = 0; x < cga->crtc[1]; x++) - { - dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; - cga->ma++; - for (c = 0; c < 8; c++) - { - buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = - buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; - dat <<= 2; - } - } - } - else - { - cols[0] = 0; cols[1] = (cga->cgacol & 15) + 16; - for (x = 0; x < cga->crtc[1]; x++) - { - dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; - cga->ma++; - for (c = 0; c < 16; c++) - { - buffer->line[cga->displine][(x << 4) + c + 8] = cols[dat >> 15]; - dat <<= 1; - } - } - } - } - else - { - cols[0] = ((cga->cgamode & 0x12) == 0x12) ? 0 : (cga->cgacol & 15) + 16; - if (cga->cgamode & 1) hline(buffer, 0, cga->displine, (cga->crtc[1] << 3) + 16, cols[0]); - else hline(buffer, 0, cga->displine, (cga->crtc[1] << 4) + 16, cols[0]); - } - - if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; - else x = (cga->crtc[1] << 4) + 16; - - if (cga->composite) - { - for (c = 0; c < x; c++) - buffer32->line[cga->displine][c] = buffer->line[cga->displine][c] & 0xf; - - Composite_Process(cga->cgamode, 0, x >> 2, buffer32->line[cga->displine]); - } - - cga->sc = oldsc; - if (cga->vc == cga->crtc[7] && !cga->sc) - cga->cgastat |= 8; - cga->displine++; - if (cga->displine >= 360) - cga->displine = 0; - } - else - { - cga->vidtime += cga->dispontime; - cga->linepos = 0; - if (cga->vsynctime) - { - cga->vsynctime--; - if (!cga->vsynctime) - cga->cgastat &= ~8; - } - if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) - { - cga->con = 0; - cga->coff = 1; - } - if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) - cga->maback = cga->ma; - if (cga->vadj) - { - cga->sc++; - cga->sc &= 31; - cga->ma = cga->maback; - cga->vadj--; - if (!cga->vadj) - { - cga->cgadispon = 1; - cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; - cga->sc = 0; - } - } - else if (cga->sc == cga->crtc[9]) - { - cga->maback = cga->ma; - cga->sc = 0; - oldvc = cga->vc; - cga->vc++; - cga->vc &= 127; - - if (cga->vc == cga->crtc[6]) - cga->cgadispon = 0; - - if (oldvc == cga->crtc[4]) - { - cga->vc = 0; - cga->vadj = cga->crtc[5]; - if (!cga->vadj) cga->cgadispon = 1; - if (!cga->vadj) cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; - if ((cga->crtc[10] & 0x60) == 0x20) cga->cursoron = 0; - else cga->cursoron = cga->cgablink & 8; - } - - if (cga->vc == cga->crtc[7]) - { - cga->cgadispon = 0; - cga->displine = 0; - cga->vsynctime = 16; - if (cga->crtc[7]) - { - if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; - else x = (cga->crtc[1] << 4) + 16; - cga->lastline++; - if ((x != xsize) || ((cga->lastline - cga->firstline) != ysize) || video_force_resize_get()) - { - xsize = x; - ysize = cga->lastline - cga->firstline; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, (ysize << 1) + 16); + if ((cga->cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); if (video_force_resize_get()) video_force_resize_set(0); - } - - 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, 0, (cga->lastline - cga->firstline) + 8, xsize, (cga->lastline - cga->firstline) + 8); - 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)]; - } - } + if (enable_overscan) { + if (cga->composite) + video_blit_memtoscreen(0, (cga->firstline - 4) << 1, 0, ((cga->lastline - cga->firstline) + 8) << 1, + xsize, ((cga->lastline - cga->firstline) + 8) << 1); + else + video_blit_memtoscreen_8(0, (cga->firstline - 4) << 1, 0, ((cga->lastline - cga->firstline) + 8) << 1, + xsize, ((cga->lastline - cga->firstline) + 8) << 1); + } else { + if (cga->composite) + video_blit_memtoscreen(8, cga->firstline << 1, 0, (cga->lastline - cga->firstline) << 1, + xsize, (cga->lastline - cga->firstline) << 1); + else + video_blit_memtoscreen_8(8, cga->firstline << 1, 0, (cga->lastline - cga->firstline) << 1, + xsize, (cga->lastline - cga->firstline) << 1); + } + } + + frames++; + + video_res_x = xsize; + video_res_y = ysize; + if (cga->cgamode & 1) { + video_res_x /= 8; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } else if (!(cga->cgamode & 2)) { + video_res_x /= 16; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } else if (!(cga->cgamode & 16)) { + video_res_x /= 2; + video_bpp = 2; + } else + video_bpp = 1; + } + cga->firstline = 1000; + cga->lastline = 0; + cga->cgablink++; + cga->oddeven ^= 1; + } + } else { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + } + if (cga->cgadispon) + cga->cgastat &= ~1; + if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) + cga->con = 1; + if (cga->cgadispon && (cga->cgamode & 1)) { + for (x = 0; x < (cga->crtc[1] << 1); x++) + cga->charbuffer[x] = cga->vram[(((cga->ma << 1) + x) & 0x3fff)]; + } + } } -void cga_init(cga_t *cga) + +void +cga_init(cga_t *cga) { - cga->composite = 0; + timer_add(&cga->timer, cga_poll, cga, 1); + cga->composite = 0; } -void *cga_standalone_init(const device_t *info) + +void * +cga_standalone_init(const device_t *info) { - int display_type; - cga_t *cga = malloc(sizeof(cga_t)); - memset(cga, 0, sizeof(cga_t)); + int display_type; + cga_t *cga = malloc(sizeof(cga_t)); - display_type = device_get_config_int("display_type"); - cga->composite = (display_type != CGA_RGB); - cga->revision = device_get_config_int("composite_type"); - cga->snow_enabled = device_get_config_int("snow_enabled"); + memset(cga, 0, sizeof(cga_t)); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_cga); - cga->vram = malloc(0x4000); + display_type = device_get_config_int("display_type"); + cga->composite = (display_type != CGA_RGB); + cga->revision = device_get_config_int("composite_type"); + cga->snow_enabled = device_get_config_int("snow_enabled"); - 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, MEM_MAPPING_EXTERNAL, cga); - io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); + cga->vram = malloc(0x4000); - overscan_x = overscan_y = 16; + cga_comp_init(cga->revision); + timer_add(&cga->timer, cga_poll, cga, 1); + mem_mapping_add(&cga->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL /*cga->vram*/, MEM_MAPPING_EXTERNAL, cga); + io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); - cga->rgb_type = device_get_config_int("rgb_type"); - cga_palette = (cga->rgb_type << 1); - cgapal_rebuild(); + overscan_x = overscan_y = 16; - return cga; + cga->rgb_type = device_get_config_int("rgb_type"); + cga_palette = (cga->rgb_type << 1); + cgapal_rebuild(); + + return cga; } -void cga_close(void *p) + +void +cga_close(void *p) { - cga_t *cga = (cga_t *)p; + cga_t *cga = (cga_t *) p; - free(cga->vram); - free(cga); + free(cga->vram); + free(cga); } -void cga_speed_changed(void *p) + +void +cga_speed_changed(void *p) { - cga_t *cga = (cga_t *)p; + cga_t *cga = (cga_t *) p; - cga_recalctimings(cga); + cga_recalctimings(cga); } + const device_config_t cga_config[] = { { @@ -584,6 +633,7 @@ const device_config_t cga_config[] = } }; + const device_t cga_device = { "CGA", diff --git a/src/video/vid_cga.h b/src/video/vid_cga.h index 74aba09c2..aa37f7fad 100644 --- a/src/video/vid_cga.h +++ b/src/video/vid_cga.h @@ -8,7 +8,7 @@ * * Emulation of the old and new IBM CGA graphics cards. * - * Version: @(#)vid_cga.h 1.0.3 2018/03/18 + * Version: @(#)vid_cga.h 1.0.4 2018/10/02 * * Author: Sarah Walker, * Miran Grca, @@ -36,8 +36,8 @@ typedef struct cga_t uint16_t ma, maback; int oddeven; - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; @@ -61,5 +61,7 @@ uint8_t cga_read(uint32_t addr, void *p); void cga_recalctimings(cga_t *cga); void cga_poll(void *p); +#ifdef EMU_DEVICE_H extern const device_config_t cga_config[]; extern const device_t cga_device; +#endif diff --git a/src/video/vid_cga_comp.c b/src/video/vid_cga_comp.c index 008627bcd..b5e87078f 100644 --- a/src/video/vid_cga_comp.c +++ b/src/video/vid_cga_comp.c @@ -9,13 +9,13 @@ * IBM CGA composite filter, borrowed from reenigne's DOSBox * patch and ported to C. * - * Version: @(#)vid_cga_comp.c 1.0.3 2017/11/04 + * Version: @(#)vid_cga_comp.c 1.0.5 2019/03/24 * * Authors: reenigne, * Miran Grca, * - * Copyright 2015-2017 reenigne. - * Copyright 2015-2017 Miran Grca. + * Copyright 2015-2019 reenigne. + * Copyright 2015-2019 Miran Grca. */ #include #include @@ -24,7 +24,7 @@ #include #include #include "../86box.h" -#include "../device.h" +#include "../timer.h" #include "../mem.h" #include "vid_cga.h" #include "vid_cga_comp.h" @@ -169,7 +169,7 @@ static int temp[SCALER_MAXWIDTH + 10]={0}; static int atemp[SCALER_MAXWIDTH + 2]={0}; static int btemp[SCALER_MAXWIDTH + 2]={0}; -Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine) +Bit32u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit32u *TempLine) { int x; Bit32u x2; @@ -177,7 +177,7 @@ Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool d int w = blocks*4; int *o; - Bit8u *rgbi; + Bit32u *rgbi; int *b; int *i; Bit32u* srgb; @@ -208,12 +208,12 @@ Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool d b = &CGA_Composite_Table[border*68]; for (x = 0; x < 4; ++x) OUT(b[(x+3)&3]); - OUT(CGA_Composite_Table[(border<<6) | ((*rgbi)<<2) | 3]); + OUT(CGA_Composite_Table[(border<<6) | ((*rgbi & 0x0f)<<2) | 3]); for (x = 0; x < w-1; ++x) { - OUT(CGA_Composite_Table[(rgbi[0]<<6) | (rgbi[1]<<2) | (x&3)]); + OUT(CGA_Composite_Table[((rgbi[0] & 0x0f)<<6) | ((rgbi[1] & 0x0f)<<2) | (x&3)]); ++rgbi; } - OUT(CGA_Composite_Table[((*rgbi)<<6) | (border<<2) | 3]); + OUT(CGA_Composite_Table[((*rgbi & 0x0f)<<6) | (border<<2) | 3]); for (x = 0; x < 5; ++x) OUT(b[x&3]); diff --git a/src/video/vid_cga_comp.h b/src/video/vid_cga_comp.h index fbea172e7..fc19ae252 100644 --- a/src/video/vid_cga_comp.h +++ b/src/video/vid_cga_comp.h @@ -9,12 +9,12 @@ * IBM CGA composite filter, borrowed from reenigne's DOSBox * patch and ported to C. * - * Version: @(#)vid_cga.h 1.0.0 2017/05/30 + * Version: @(#)vid_cga.h 1.0.1 2018/03/24 * * Author: reenigne, * Miran Grca, - * Copyright 2015-2017 reenigne. - * Copyright 2015-2017 Miran Grca. + * Copyright 2015-2018 reenigne. + * Copyright 2015-2018 Miran Grca. */ #define Bit8u uint8_t @@ -24,4 +24,4 @@ void update_cga16_color(uint8_t cgamode); void cga_comp_init(int revision); -Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine); +Bit32u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit32u *TempLine); diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 6e501e4ae..0ca557bd8 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,17 +9,13 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). * - * Version: @(#)vid_cl_54xx.c 1.0.20 2018/07/16 + * Version: @(#)vid_cl_54xx.c 1.0.32 2020/01/11 * - * Authors: Sarah Walker, - * Barry Rodewald, - * TheCollector1995, + * Authors: TheCollector1995, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2018 Barry Rodewald - * Copyright 2016-2018 TheCollector1995. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2020 TheCollector1995. + * Copyright 2016-2020 Miran Grca. */ #include #include @@ -34,11 +30,16 @@ #include "../pci.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_cl54xx.h" +#if defined(DEV_BRANCH) && defined(USE_CL5422) +#define BIOS_GD5420_PATH L"roms/video/cirruslogic/5420.vbi" +#define BIOS_GD5422_PATH L"roms/video/cirruslogic/cl5422.bin" +#endif #define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" #define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.bin" #define BIOS_GD5428_PATH L"roms/video/cirruslogic/vlbusjapan.BIN" @@ -52,6 +53,10 @@ #define BIOS_GD5446_STB_PATH L"roms/video/cirruslogic/stb nitro64v.BIN" #define BIOS_GD5480_PATH L"roms/video/cirruslogic/clgd5480.rom" +#define CIRRUS_ID_CLGD5402 0x89 +#define CIRRUS_ID_CLGD5420 0x8a +#define CIRRUS_ID_CLGD5422 0x8c +#define CIRRUS_ID_CLGD5424 0x94 #define CIRRUS_ID_CLGD5426 0x90 #define CIRRUS_ID_CLGD5428 0x98 #define CIRRUS_ID_CLGD5429 0x9c @@ -109,9 +114,12 @@ #define CIRRUS_BLT_START 0x02 #define CIRRUS_BLT_RESET 0x04 #define CIRRUS_BLT_FIFOUSED 0x10 +#define CIRRUS_BLT_PAUSED 0x20 +#define CIRRUS_BLT_APERTURE2 0x40 #define CIRRUS_BLT_AUTOSTART 0x80 // control 0x33 +#define CIRRUS_BLTMODEEXT_BACKGROUNDONLY 0x08 #define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 #define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02 #define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 @@ -126,7 +134,8 @@ typedef struct gd54xx_t { mem_mapping_t mmio_mapping; - mem_mapping_t linear_mapping; + mem_mapping_t linear_mapping; + mem_mapping_t aperture2_mapping; svga_t svga; @@ -138,7 +147,6 @@ typedef struct gd54xx_t uint8_t vclk_n[4]; uint8_t vclk_d[4]; - uint32_t bank[2]; struct { uint8_t state; @@ -146,44 +154,56 @@ typedef struct gd54xx_t } ramdac; struct { - uint32_t fg_col, bg_col; uint16_t width, height; uint16_t dst_pitch, src_pitch; - uint32_t dst_addr, src_addr; - uint8_t mask, mode, rop; - uint8_t modeext; - uint8_t status; uint16_t trans_col, trans_mask; + uint16_t height_internal; + uint16_t msd_buf_pos, msd_buf_cnt; + uint8_t status; + uint8_t mask, mode, rop, modeext; + uint8_t ms_is_dest, msd_buf[32]; + + uint32_t fg_col, bg_col; uint32_t dst_addr_backup, src_addr_backup; - uint16_t width_backup, height_internal; + uint32_t dst_addr, src_addr; + uint32_t sys_src32, sys_cnt; + /* Internal state */ + int pixel_width, pattern_x; int x_count, y_count; - int sys_tx; - uint8_t sys_cnt; - uint32_t sys_buf; - uint16_t pixel_cnt; - uint16_t scan_cnt; + int xx_count, dir; + int unlock_special; } blt; - int pci, vlb; + int pci, vlb; + int countminusone; - uint8_t pci_regs[256]; - uint8_t int_line; + uint8_t pci_regs[256]; + uint8_t int_line, unlocked; - int card; + uint8_t fc; /* Feature Connector */ - uint32_t lfb_base; + int card; - int mmio_vram_overlap; + uint32_t lfb_base; - uint32_t extpallook[256]; - PALETTE extpal; + int mmio_vram_overlap; + + uint32_t extpallook[256]; + PALETTE extpal; } gd54xx_t; + +static video_timings_t timing_gd54xx_isa = {VIDEO_ISA, 3, 3, 6, 8, 8, 12}; +static video_timings_t timing_gd54xx_vlb_pci = {VIDEO_BUS, 4, 4, 8, 10, 10, 20}; + + static void gd543x_mmio_write(uint32_t addr, uint8_t val, void *p); static void +gd543x_mmio_writeb(uint32_t addr, uint8_t val, void *p); +static void gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p); static void gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p); @@ -200,8 +220,35 @@ gd54xx_recalc_banking(gd54xx_t *gd54xx); static void gd543x_recalc_mapping(gd54xx_t *gd54xx); +static void +gd54xx_reset_blit(gd54xx_t *gd54xx); static void -gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga); +gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *svga); + + +/* Returns 1 if the card is a 5422+ */ +static int +gd54xx_is_5422(svga_t *svga) +{ + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) + return 1; + else + return 0; +} + + +/* Returns 1 if the card supports the 8-bpp/16-bpp transparency color or mask. */ +static int +gd54xx_has_transp(svga_t *svga, int mask) +{ + if (((svga->crtc[0x27] == CIRRUS_ID_CLGD5446) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5480)) && + !mask) + return 1; /* 5446 and 5480 have mask but not transparency. */ + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5426) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5428)) + return 1; /* 5426 and 5428 have both. */ + else + return 0; /* The rest have neither. */ +} /* Returns 1 if the card is a 5434, 5436/46, or 5480. */ @@ -222,7 +269,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = &gd54xx->svga; uint8_t old; int c; - uint8_t o; + uint8_t o, index; uint32_t o32; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) @@ -270,16 +317,26 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga->seqaddr = val; break; case 0x3c5: + if ((svga->seqaddr == 2) && !gd54xx->unlocked) { + o = svga->seqregs[svga->seqaddr & 0x1f]; + svga_out(addr, val, svga); + svga->seqregs[svga->seqaddr & 0x1f] = (o & 0xf0) | (val & 0x0f); + return; + } else if ((svga->seqaddr > 6) && !gd54xx->unlocked) + return; + if (svga->seqaddr > 5) { o = svga->seqregs[svga->seqaddr & 0x1f]; svga->seqregs[svga->seqaddr & 0x1f] = val; - switch (svga->seqaddr & 0x1f) { + switch (svga->seqaddr) { case 6: val &= 0x17; if (val == 0x12) svga->seqregs[6] = 0x12; else svga->seqregs[6] = 0x0f; + if (svga->crtc[0x27] < CIRRUS_ID_CLGD5429) + gd54xx->unlocked = (svga->seqregs[6] == 0x12); break; case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ gd54xx->vclk_n[svga->seqaddr-0x0b] = val; @@ -296,34 +353,51 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga->hwcursor.y = (val << 3) | (svga->seqaddr >> 5); break; case 0x12: - if (val & 0x80) + svga->ext_overscan = !!(val & 0x80); + if (svga->ext_overscan && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5426)) svga->overscan_color = gd54xx->extpallook[2]; else svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; svga_recalctimings(svga); svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; - svga->hwcursor.xsize = svga->hwcursor.ysize = (val & CIRRUS_CURSOR_LARGE) ? 64 : 32; - if (val & CIRRUS_CURSOR_LARGE) - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) + svga->hwcursor.xsize = svga->hwcursor.ysize = + ((val & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)) ? 64 : 32; else - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3f) * 256)); + svga->hwcursor.xsize = 32; + svga->hwcursor.yoff = (svga->hwcursor.ysize == 32) ? 32 : 0; + + if ((svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)) + svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); + else + svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((svga->seqregs[0x13] & 0x3f) * 256)); break; case 0x13: - if (svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3c) * 256)); + if ((svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)) + svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((val & 0x3c) * 256)); else - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3f) * 256)); + svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((val & 0x3f) * 256)); break; case 0x07: - svga->set_reset_disabled = svga->seqregs[7] & 1; + if (gd54xx_is_5422(svga)) + gd543x_recalc_mapping(gd54xx); + else + svga->seqregs[svga->seqaddr] &= 0x0f; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) + svga->set_reset_disabled = svga->seqregs[7] & 1; case 0x17: - gd543x_recalc_mapping(gd54xx); + if (gd54xx_is_5422(svga)) + gd543x_recalc_mapping(gd54xx); + else + return; break; } return; } break; - case 0x3C6: + case 0x3c6: + if (!gd54xx->unlocked) + break; if (gd54xx->ramdac.state == 4) { gd54xx->ramdac.state = 0; gd54xx->ramdac.ctrl = val; @@ -332,7 +406,11 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) } gd54xx->ramdac.state = 0; break; - case 0x3C9: + case 0x3c7: case 0x3c8: + gd54xx->ramdac.state = 0; + break; + case 0x3c9: + gd54xx->ramdac.state = 0; svga->dac_status = 0; svga->fullchange = changeframecount; switch (svga->dac_pos) { @@ -345,180 +423,216 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga->dac_pos++; break; case 2: + index = svga->dac_addr & 0xff; if (svga->seqregs[0x12] & 2) { - gd54xx->extpal[svga->dac_write].r = svga->dac_r; - gd54xx->extpal[svga->dac_write].g = svga->dac_g; - gd54xx->extpal[svga->dac_write].b = val; - gd54xx->extpallook[svga->dac_write & 15] = makecol32(video_6to8[gd54xx->extpal[svga->dac_write].r & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].g & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].b & 0x3f]); - if ((svga->seqregs[0x12] & 0x80) && ((svga->dac_write & 15) == 2)) { + index &= 0x0f; + gd54xx->extpal[index].r = svga->dac_r; + gd54xx->extpal[index].g = svga->dac_g; + gd54xx->extpal[index].b = val; + gd54xx->extpallook[index] = makecol32(video_6to8[gd54xx->extpal[index].r & 0x3f], video_6to8[gd54xx->extpal[index].g & 0x3f], video_6to8[gd54xx->extpal[index].b & 0x3f]); + if (svga->ext_overscan && (index == 2)) { o32 = svga->overscan_color; svga->overscan_color = gd54xx->extpallook[2]; if (o32 != svga->overscan_color) svga_recalctimings(svga); } - svga->dac_write = (svga->dac_write + 1) & 15; } else { - 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; - svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); - svga->dac_write = (svga->dac_write + 1) & 255; + svga->vgapal[index].r = svga->dac_r; + svga->vgapal[index].g = svga->dac_g; + svga->vgapal[index].b = val; + svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f], video_6to8[svga->vgapal[index].g & 0x3f], video_6to8[svga->vgapal[index].b & 0x3f]); } + svga->dac_addr = (svga->dac_addr + 1) & 255; svga->dac_pos = 0; break; } return; + case 0x3ce: + /* Per the CL-GD 5446 manual: bits 0-5 are the GDC register index, bits 6-7 are reserved. */ + svga->gdcaddr = val/* & 0x3f*/; + return; case 0x3cf: - if (svga->gdcaddr == 0) - gd543x_mmio_write(0xb8000, val, gd54xx); - if (svga->gdcaddr == 1) - gd543x_mmio_write(0xb8004, val, gd54xx); - - if (svga->gdcaddr == 5) { - svga->gdcreg[5] = val; - if (svga->gdcreg[0xb] & 0x04) - svga->writemode = svga->gdcreg[5] & 7; - else - svga->writemode = svga->gdcreg[5] & 3; - svga->readmode = val & 8; - svga->chain2_read = val & 0x10; + if ((svga->gdcaddr > 0x1f) && ((svga->crtc[0x27] <= CIRRUS_ID_CLGD5422) || + (svga->crtc[0x27] == CIRRUS_ID_CLGD5424))) return; - } - if (svga->gdcaddr == 6) { - if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { - svga->gdcreg[6] = val; - gd543x_recalc_mapping(gd54xx); + o = svga->gdcreg[svga->gdcaddr]; + + if ((svga->gdcaddr < 2) && !gd54xx->unlocked) + svga->gdcreg[svga->gdcaddr] = (svga->gdcreg[svga->gdcaddr] & 0xf0) | (val & 0x0f); + else if ((svga->gdcaddr <= 8) || gd54xx->unlocked) + svga->gdcreg[svga->gdcaddr] = val; + + if (svga->gdcaddr <= 8) { + switch (svga->gdcaddr) { + case 0: + gd543x_mmio_write(0xb8000, val, gd54xx); + break; + case 1: + gd543x_mmio_write(0xb8004, val, gd54xx); + break; + case 2: + svga->colourcompare = val; + break; + case 4: + svga->readplane = val & 3; + break; + case 5: + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = val & 7; + else + svga->writemode = val & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + break; + case 6: + if ((o ^ val) & 0x0c) + gd543x_recalc_mapping(gd54xx); + break; + case 7: + svga->colournocare = val; + break; } - svga->gdcreg[6] = val; - return; - } - if (svga->gdcaddr > 8) { - svga->gdcreg[svga->gdcaddr & 0x3f] = val; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + if (((svga->gdcaddr == 5) && ((val ^ o) & 0x70)) || + ((svga->gdcaddr == 6) && ((val ^ o) & 1))) + svga_recalctimings(svga); + } else { switch (svga->gdcaddr) { case 0x09: case 0x0a: case 0x0b: - gd54xx_recalc_banking(gd54xx); if (svga->gdcreg[0xb] & 0x04) svga->writemode = svga->gdcreg[5] & 7; else svga->writemode = svga->gdcreg[5] & 3; + svga->adv_flags = 0; + if (svga->gdcreg[0xb] & 0x01) + svga->adv_flags = FLAG_EXTRA_BANKS; + if (svga->gdcreg[0xb] & 0x02) + svga->adv_flags |= FLAG_ADDR_BY8; + if (svga->gdcreg[0xb] & 0x08) + svga->adv_flags |= FLAG_LATCH8; + gd54xx_recalc_banking(gd54xx); break; - - case 0x10: + + case 0x10: gd543x_mmio_write(0xb8001, val, gd54xx); break; - case 0x11: + case 0x11: gd543x_mmio_write(0xb8005, val, gd54xx); break; - case 0x12: + case 0x12: gd543x_mmio_write(0xb8002, val, gd54xx); break; - case 0x13: + case 0x13: gd543x_mmio_write(0xb8006, val, gd54xx); break; - case 0x14: + case 0x14: gd543x_mmio_write(0xb8003, val, gd54xx); break; - case 0x15: + case 0x15: gd543x_mmio_write(0xb8007, val, gd54xx); break; - - case 0x20: + + case 0x20: gd543x_mmio_write(0xb8008, val, gd54xx); break; - case 0x21: + case 0x21: gd543x_mmio_write(0xb8009, val, gd54xx); break; - case 0x22: + case 0x22: gd543x_mmio_write(0xb800a, val, gd54xx); break; - case 0x23: + case 0x23: gd543x_mmio_write(0xb800b, val, gd54xx); break; - case 0x24: + case 0x24: gd543x_mmio_write(0xb800c, val, gd54xx); break; - case 0x25: + case 0x25: gd543x_mmio_write(0xb800d, val, gd54xx); break; - case 0x26: + case 0x26: gd543x_mmio_write(0xb800e, val, gd54xx); break; - case 0x27: + case 0x27: gd543x_mmio_write(0xb800f, val, gd54xx); break; - - case 0x28: + + case 0x28: gd543x_mmio_write(0xb8010, val, gd54xx); break; - case 0x29: + case 0x29: gd543x_mmio_write(0xb8011, val, gd54xx); break; - case 0x2a: + case 0x2a: gd543x_mmio_write(0xb8012, val, gd54xx); break; - case 0x2c: + case 0x2c: gd543x_mmio_write(0xb8014, val, gd54xx); break; - case 0x2d: + case 0x2d: gd543x_mmio_write(0xb8015, val, gd54xx); break; - case 0x2e: + case 0x2e: gd543x_mmio_write(0xb8016, val, gd54xx); break; - case 0x2f: + case 0x2f: gd543x_mmio_write(0xb8017, val, gd54xx); break; - case 0x30: + case 0x30: gd543x_mmio_write(0xb8018, val, gd54xx); break; - - case 0x32: + + case 0x32: gd543x_mmio_write(0xb801a, val, gd54xx); break; - case 0x33: + case 0x33: gd543x_mmio_write(0xb801b, val, gd54xx); break; - - case 0x31: + + case 0x31: gd543x_mmio_write(0xb8040, val, gd54xx); break; - - case 0x34: + + case 0x34: gd543x_mmio_write(0xb801c, val, gd54xx); break; - - case 0x35: + + case 0x35: gd543x_mmio_write(0xb801d, val, gd54xx); break; - case 0x38: + case 0x38: gd543x_mmio_write(0xb8020, val, gd54xx); break; - case 0x39: + case 0x39: gd543x_mmio_write(0xb8021, val, gd54xx); - break; - + break; } - return; } - break; - case 0x3D4: + return; + case 0x3d4: svga->crtcreg = val & 0x3f; return; - case 0x3D5: + case 0x3d5: + if (((svga->crtcreg == 0x19) || (svga->crtcreg == 0x1a) || + (svga->crtcreg == 0x1b) || (svga->crtcreg == 0x1d) || + (svga->crtcreg == 0x25) || (svga->crtcreg == 0x27)) && + !gd54xx->unlocked) + return; 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; @@ -537,112 +651,270 @@ gd54xx_in(uint16_t addr, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - uint8_t temp; + uint8_t index, ret = 0xff; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3d0) && !(svga->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { case 0x3c4: - if ((svga->seqregs[6] & 0x17) == 0x12) - { - temp = svga->seqaddr; - if ((temp & 0x1e) == 0x10) - { - if (temp & 1) - temp = ((svga->hwcursor.y & 7) << 5) | 0x11; - else - temp = ((svga->hwcursor.x & 7) << 5) | 0x10; - } - return temp; - } - return svga->seqaddr; - + if (svga->seqregs[6] == 0x12) { + ret = svga->seqaddr; + if ((ret & 0x1e) == 0x10) { + if (ret & 1) + ret = ((svga->hwcursor.y & 7) << 5) | 0x11; + else + ret = ((svga->hwcursor.x & 7) << 5) | 0x10; + } + } else + ret = svga->seqaddr; + break; + case 0x3c5: - if (svga->seqaddr > 5) { + if ((svga->seqaddr == 2) && !gd54xx->unlocked) + ret = svga_in(addr, svga) & 0x0f; + else if ((svga->seqaddr > 6) && !gd54xx->unlocked) + ret = 0xff; + else if (svga->seqaddr > 5) { + ret = svga->seqregs[svga->seqaddr & 0x3f]; switch (svga->seqaddr) { case 6: - return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; + ret = svga->seqregs[6]; + break; case 0x0b: case 0x0c: case 0x0d: case 0x0e: - return gd54xx->vclk_n[svga->seqaddr-0x0b]; + ret = gd54xx->vclk_n[svga->seqaddr-0x0b]; + break; case 0x17: - temp = svga->gdcreg[0x17] & ~(7 << 3); + ret = svga->gdcreg[0x17] & ~(7 << 3); if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { if (gd54xx->vlb) - temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); + ret |= (CL_GD5429_SYSTEM_BUS_VESA << 3); else - temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3); + ret |= (CL_GD5429_SYSTEM_BUS_ISA << 3); } else { if (gd54xx->pci) - temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3); + ret |= (CL_GD543X_SYSTEM_BUS_PCI << 3); else if (gd54xx->vlb) - temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3); + ret |= (CL_GD543X_SYSTEM_BUS_VESA << 3); else - temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3); + ret |= (CL_GD543X_SYSTEM_BUS_ISA << 3); } - return temp; + break; + case 0x18: + ret = svga->seqregs[0x18] & 0xfe; + break; case 0x1b: case 0x1c: case 0x1d: case 0x1e: - return gd54xx->vclk_d[svga->seqaddr-0x1b]; + ret = gd54xx->vclk_d[svga->seqaddr - 0x1b]; + break; } - return svga->seqregs[svga->seqaddr & 0x3f]; + break; + } else + ret = svga_in(addr, svga); + break; + case 0x3c6: + if (!gd54xx->unlocked) + ret = svga_in(addr, svga); + else if (gd54xx->ramdac.state == 4) { + /* CL-GD 5428 does not lock the register when it's read. */ + if (svga->crtc[0x27] != CIRRUS_ID_CLGD5428) + gd54xx->ramdac.state = 0; + ret = gd54xx->ramdac.ctrl; + } else { + gd54xx->ramdac.state++; + if (gd54xx->ramdac.state == 4) + ret = gd54xx->ramdac.ctrl; + else + ret = svga_in(addr, svga); } break; + case 0x3c7: case 0x3c8: + gd54xx->ramdac.state = 0; + ret = svga_in(addr, svga); + break; case 0x3c9: + gd54xx->ramdac.state = 0; svga->dac_status = 3; + index = (svga->dac_addr - 1) & 0xff; + if (svga->seqregs[0x12] & 2) + index &= 0x0f; switch (svga->dac_pos) { case 0: svga->dac_pos++; if (svga->seqregs[0x12] & 2) - return gd54xx->extpal[svga->dac_read].r & 0x3f; + ret = gd54xx->extpal[index].r & 0x3f; else - return svga->vgapal[svga->dac_read].r & 0x3f; + ret = svga->vgapal[index].r & 0x3f; + break; case 1: svga->dac_pos++; if (svga->seqregs[0x12] & 2) - return gd54xx->extpal[svga->dac_read].g & 0x3f; + ret = gd54xx->extpal[index].g & 0x3f; else - return svga->vgapal[svga->dac_read].g & 0x3f; + ret = svga->vgapal[index].g & 0x3f; + break; case 2: svga->dac_pos=0; - if (svga->seqregs[0x12] & 2) { - svga->dac_read = (svga->dac_read + 1) & 15; - return gd54xx->extpal[(svga->dac_read - 1) & 15].b & 0x3f; - } else { - svga->dac_read = (svga->dac_read + 1) & 255; - return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; - } + svga->dac_addr = (svga->dac_addr + 1) & 255; + if (svga->seqregs[0x12] & 2) + ret = gd54xx->extpal[index].b & 0x3f; + else + ret = svga->vgapal[index].b & 0x3f; + break; } - return 0xFF; - case 0x3C6: - if (gd54xx->ramdac.state == 4) { - gd54xx->ramdac.state = 0; - return gd54xx->ramdac.ctrl; - } - gd54xx->ramdac.state++; + break; + case 0x3ce: + ret = svga->gdcaddr & 0x3f; break; case 0x3cf: - if (svga->gdcaddr > 8) { - return svga->gdcreg[svga->gdcaddr & 0x3f]; + if (svga->gdcaddr >= 0x10) { + if ((svga->gdcaddr > 8) && !gd54xx->unlocked) + ret = 0xff; + else if ((svga->gdcaddr > 0x1f) && ((svga->crtc[0x27] <= CIRRUS_ID_CLGD5422) || + (svga->crtc[0x27] == CIRRUS_ID_CLGD5424))) + ret = 0xff; + else switch (svga->gdcaddr) { + case 0x10: + ret = gd543x_mmio_read(0xb8001, gd54xx); + break; + case 0x11: + ret = gd543x_mmio_read(0xb8005, gd54xx); + break; + case 0x12: + ret = gd543x_mmio_read(0xb8002, gd54xx); + break; + case 0x13: + ret = gd543x_mmio_read(0xb8006, gd54xx); + break; + case 0x14: + ret = gd543x_mmio_read(0xb8003, gd54xx); + break; + case 0x15: + ret = gd543x_mmio_read(0xb8007, gd54xx); + break; + + case 0x20: + ret = gd543x_mmio_read(0xb8008, gd54xx); + break; + case 0x21: + ret = gd543x_mmio_read(0xb8009, gd54xx); + break; + case 0x22: + ret = gd543x_mmio_read(0xb800a, gd54xx); + break; + case 0x23: + ret = gd543x_mmio_read(0xb800b, gd54xx); + break; + case 0x24: + ret = gd543x_mmio_read(0xb800c, gd54xx); + break; + case 0x25: + ret = gd543x_mmio_read(0xb800d, gd54xx); + break; + case 0x26: + ret = gd543x_mmio_read(0xb800e, gd54xx); + break; + case 0x27: + ret = gd543x_mmio_read(0xb800f, gd54xx); + break; + + case 0x28: + ret = gd543x_mmio_read(0xb8010, gd54xx); + break; + case 0x29: + ret = gd543x_mmio_read(0xb8011, gd54xx); + break; + case 0x2a: + ret = gd543x_mmio_read(0xb8012, gd54xx); + break; + + case 0x2c: + ret = gd543x_mmio_read(0xb8014, gd54xx); + break; + case 0x2d: + ret = gd543x_mmio_read(0xb8015, gd54xx); + break; + case 0x2e: + ret = gd543x_mmio_read(0xb8016, gd54xx); + break; + + case 0x2f: + ret = gd543x_mmio_read(0xb8017, gd54xx); + break; + case 0x30: + ret = gd543x_mmio_read(0xb8018, gd54xx); + break; + + case 0x32: + ret = gd543x_mmio_read(0xb801a, gd54xx); + break; + + case 0x33: + ret = gd543x_mmio_read(0xb801b, gd54xx); + break; + + case 0x31: + ret = gd543x_mmio_read(0xb8040, gd54xx); + break; + + case 0x34: + ret = gd543x_mmio_read(0xb801c, gd54xx); + break; + + case 0x35: + ret = gd543x_mmio_read(0xb801d, gd54xx); + break; + + case 0x38: + ret = gd543x_mmio_read(0xb8020, gd54xx); + break; + + case 0x39: + ret = gd543x_mmio_read(0xb8021, gd54xx); + break; + } + } else { + if ((svga->gdcaddr < 2) && !gd54xx->unlocked) + ret = (svga->gdcreg[svga->gdcaddr] & 0x0f); + else + ret = svga->gdcreg[svga->gdcaddr]; } break; - case 0x3D4: - return svga->crtcreg; - case 0x3D5: - switch (svga->crtcreg) { + case 0x3d4: + ret = svga->crtcreg; + break; + case 0x3d5: + ret = svga->crtc[svga->crtcreg]; + if (((svga->crtcreg == 0x19) || (svga->crtcreg == 0x1a) || + (svga->crtcreg == 0x1b) || (svga->crtcreg == 0x1d) || + (svga->crtcreg == 0x25) || (svga->crtcreg == 0x27)) && + !gd54xx->unlocked) + ret = 0xff; + else switch (svga->crtcreg) { + case 0x22: /*Graphis Data Latches Readback Register*/ + /*Should this be & 7 if 8 byte latch is enabled? */ + ret = svga->latch.b[svga->gdcreg[4] & 3]; + break; case 0x24: /*Attribute controller toggle readback (R)*/ - return svga->attrff << 7; + ret = svga->attrff << 7; + break; case 0x26: /*Attribute controller index readback (R)*/ - return svga->attraddr & 0x3f; + ret = svga->attraddr & 0x3f; + break; case 0x27: /*ID*/ - return svga->crtc[0x27]; /*GD542x/GD543x*/ + ret = svga->crtc[0x27]; /*GD542x/GD543x*/ + break; case 0x28: /*Class ID*/ if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5430) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5440)) - return 0xff; /*Standard CL-GD5430/40*/ + ret = 0xff; /*Standard CL-GD5430/40*/ break; } - return svga->crtc[svga->crtcreg]; + break; + default: + ret = svga_in(addr, svga); + break; } - return svga_in(addr, svga); + + return ret; } @@ -651,18 +923,31 @@ gd54xx_recalc_banking(gd54xx_t *gd54xx) { svga_t *svga = &gd54xx->svga; - if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) - gd54xx->bank[0] = svga->gdcreg[0x09] << 14; - else - gd54xx->bank[0] = svga->gdcreg[0x09] << 12; - - if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) { - if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) - gd54xx->bank[1] = svga->gdcreg[0x0a] << 14; + if (!gd54xx_is_5422(svga)) { + svga->extra_banks[0] = (svga->gdcreg[0x09] & 0x7f) << 12; + + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) + svga->extra_banks[1] = (svga->gdcreg[0x0a] & 0x7f) << 12; else - gd54xx->bank[1] = svga->gdcreg[0x0a] << 12; - } else - gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; + svga->extra_banks[1] = svga->extra_banks[0] + 0x8000; + } else { + if ((svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) && + (svga->crtc[0x27] >= CIRRUS_ID_CLGD5426) && (svga->crtc[0x27] != CIRRUS_ID_CLGD5424)) + svga->extra_banks[0] = svga->gdcreg[0x09] << 14; + else + svga->extra_banks[0] = svga->gdcreg[0x09] << 12; + + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) { + if ((svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) && + (svga->crtc[0x27] >= CIRRUS_ID_CLGD5426) && (svga->crtc[0x27] != CIRRUS_ID_CLGD5424)) + svga->extra_banks[1] = svga->gdcreg[0x0a] << 14; + else + svga->extra_banks[1] = svga->gdcreg[0x0a] << 12; + } else + svga->extra_banks[1] = svga->extra_banks[0] + 0x8000; + } + + svga->write_bank = svga->read_bank = svga->extra_banks[0]; } @@ -670,6 +955,7 @@ static void gd543x_recalc_mapping(gd54xx_t *gd54xx) { svga_t *svga = &gd54xx->svga; + uint32_t base, size; if (!(gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { mem_mapping_disable(&svga->mapping); @@ -680,8 +966,9 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) gd54xx->mmio_vram_overlap = 0; - if (!(svga->seqregs[7] & 0xf0)) { + if (!gd54xx_is_5422(svga) || !(svga->seqregs[7] & 0xf0) || !(svga->seqregs[0x07] & 0x01)) { mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_disable(&gd54xx->aperture2_mapping); switch (svga->gdcreg[6] & 0x0c) { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); @@ -701,14 +988,18 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) gd54xx->mmio_vram_overlap = 1; break; } - if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) - mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); - else + + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x07] & 0x01) && + (svga->crtc[0x27] >= CIRRUS_ID_CLGD5426) && (svga->crtc[0x27] != CIRRUS_ID_CLGD5424)) { + if (gd54xx->mmio_vram_overlap) { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x08000); + } else + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + } else mem_mapping_disable(&gd54xx->mmio_mapping); } else { - uint32_t base, size; - - if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || (!gd54xx->pci && !gd54xx->vlb)) { + if ((svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) || (!gd54xx->pci && !gd54xx->vlb)) { if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { base = (svga->seqregs[7] & 0xf0) << 16; size = 1 * 1024 * 1024; @@ -732,19 +1023,22 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) mem_mapping_disable(&svga->mapping); mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); - if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { - if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) { - if (size >= (4 * 1024 * 1024)) - mem_mapping_disable(&gd54xx->mmio_mapping); /* MMIO is handled in the linear read/write functions */ - else { - mem_mapping_set_addr(&gd54xx->linear_mapping, base, size - 256); - mem_mapping_set_addr(&gd54xx->mmio_mapping, base + size - 256, 0x00100); - } - } else + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5426) && + (svga->crtc[0x27] != CIRRUS_ID_CLGD5424)) { + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) + mem_mapping_disable(&gd54xx->mmio_mapping); /* MMIO is handled in the linear read/write functions */ + else mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); } else mem_mapping_disable(&gd54xx->mmio_mapping); - } + + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_APERTURE2) && + ((gd54xx->blt.mode & (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC)) == + (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC))) + mem_mapping_set_addr(&gd54xx->aperture2_mapping, 0xbc000, 0x04000); + else + mem_mapping_disable(&gd54xx->aperture2_mapping); + } } @@ -752,12 +1046,13 @@ static void gd54xx_recalctimings(svga_t *svga) { gd54xx_t *gd54xx = (gd54xx_t *)svga->p; - uint8_t clocksel; + uint8_t clocksel, rdmask; svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); svga->interlace = (svga->crtc[0x1a] & 0x01); + svga->map8 = svga->pallook; if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) svga->render = svga_render_8bpp_highres; else if (svga->gdcreg[5] & 0x40) @@ -769,10 +1064,18 @@ gd54xx_recalctimings(svga_t *svga) if (gd54xx->ramdac.ctrl & 0x80) { if (gd54xx->ramdac.ctrl & 0x40) { - switch (gd54xx->ramdac.ctrl & 0xf) { + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5428) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5426)) + rdmask = 0xf; + else + rdmask = 0x7; + + switch (gd54xx->ramdac.ctrl & rdmask) { case 0: svga->bpp = 15; - svga->render = svga_render_15bpp_highres; + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_highres; + else + svga->render = svga_render_15bpp_highres; break; case 1: @@ -792,62 +1095,54 @@ gd54xx_recalctimings(svga_t *svga) } break; - case 0xf: - switch (svga->seqregs[7] & CIRRUS_SR7_BPP_MASK) { - case CIRRUS_SR7_BPP_32: - svga->bpp = 32; - svga->render = svga_render_32bpp_highres; - svga->rowoffset *= 2; - break; + case 8: + svga->bpp = 8; + svga->map8 = video_8togs; + svga->render = svga_render_8bpp_highres; + break; - case CIRRUS_SR7_BPP_24: - svga->bpp = 24; - svga->render = svga_render_24bpp_highres; - break; - - case CIRRUS_SR7_BPP_16: - case CIRRUS_SR7_BPP_16_DOUBLEVCLK: - svga->bpp = 16; - svga->render = svga_render_16bpp_highres; - break; - - case CIRRUS_SR7_BPP_8: - svga->bpp = 8; - svga->render = svga_render_8bpp_highres; - break; - } + case 9: + svga->bpp = 8; + svga->map8 = video_8to32; + svga->render = svga_render_8bpp_highres; break; } } else { svga->bpp = 15; - svga->render = svga_render_15bpp_highres; + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_highres; + else + svga->render = svga_render_15bpp_highres; } } clocksel = (svga->miscout >> 2) & 3; if (!gd54xx->vclk_n[clocksel] || !gd54xx->vclk_d[clocksel]) - svga->clock = cpuclock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); + svga->clock = (cpuclock * (float)(1ull << 32)) / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); else { int n = gd54xx->vclk_n[clocksel] & 0x7f; int d = (gd54xx->vclk_d[clocksel] & 0x3e) >> 1; int m = gd54xx->vclk_d[clocksel] & 0x01 ? 2 : 1; float freq = (14318184.0 * ((float)n / ((float)d * m))); - switch (svga->seqregs[7] & (gd54xx_is_5434(svga) ? 0xe : 6)) { - case 2: - freq /= 2.0; - break; - case 4: - if (!gd54xx_is_5434(svga)) - freq /= 3.0; - break; + if (gd54xx_is_5422(svga)) { + switch (svga->seqregs[7] & (gd54xx_is_5434(svga) ? 0xe : 6)) { + case 2: + freq /= 2.0; + break; + case 4: + if (!gd54xx_is_5434(svga)) + freq /= 3.0; + break; + } } - svga->clock = cpuclock / freq; + svga->clock = (cpuclock * (double)(1ull << 32)) / freq; } svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; } + static void gd54xx_hwcursor_draw(svga_t *svga, int displine) { @@ -855,14 +1150,10 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) int x, xx, comb, b0, b1; uint8_t dat[2]; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int y_add, x_add; int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; uint32_t bgcol = gd54xx->extpallook[0x00]; uint32_t fgcol = gd54xx->extpallook[0x0f]; - y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; - x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; - if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += pitch; @@ -883,16 +1174,16 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) break; case 1: /* The pixel is shown in the cursor background color */ - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = bgcol; + ((uint32_t *)buffer32->line[displine])[offset + svga->x_add] = bgcol; break; case 2: /* The pixel is shown as the inverse of the original screen pixel (XOR cursor) */ - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + ((uint32_t *)buffer32->line[displine])[offset + svga->x_add] ^= 0xffffff; break; case 3: /* The pixel is shown in the cursor foreground color */ - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = fgcol; + ((uint32_t *)buffer32->line[displine])[offset + svga->x_add] = fgcol; break; } } @@ -909,89 +1200,73 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) svga->hwcursor_latch.addr += pitch; } -static void -gd54xx_memsrc_rop(gd54xx_t *gd54xx, svga_t *svga, uint8_t src, uint8_t dst) -{ - uint8_t res = src; - svga->changedvram[(gd54xx->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; +static void +gd54xx_rop(gd54xx_t *gd54xx, uint8_t *res, uint8_t *dst, const uint8_t *src) { switch (gd54xx->blt.rop) { - case 0x00: res = 0; break; - case 0x05: res = src & dst; break; - case 0x06: res = dst; break; - case 0x09: res = src & ~dst; break; - case 0x0b: res = ~ dst; break; - case 0x0d: res = src; break; - case 0x0e: res = 0xff; break; - case 0x50: res = ~ src & dst; break; - case 0x59: res = src ^ dst; break; - case 0x6d: res = src | dst; break; - case 0x90: res = ~(src | dst); break; - case 0x95: res = ~(src ^ dst); break; - case 0xad: res = src | ~dst; break; - case 0xd0: res = ~src; break; - case 0xd6: res = ~src | dst; break; - case 0xda: res = ~(src & dst); break; + case 0x00: *res = 0x00; break; + case 0x05: *res = *src & *dst; break; + case 0x06: *res = *dst; break; + case 0x09: *res = *src & ~*dst; break; + case 0x0b: *res = ~*dst; break; + case 0x0d: *res = *src; break; + case 0x0e: *res = 0xff; break; + case 0x50: *res = ~*src & *dst; break; + case 0x59: *res = *src ^ *dst; break; + case 0x6d: *res = *src | *dst; break; + case 0x90: *res = ~(*src | *dst); break; + case 0x95: *res = ~(*src ^ *dst); break; + case 0xad: *res = *src | ~*dst; break; + case 0xd0: *res = ~*src; break; + case 0xd6: *res = ~*src | *dst; break; + case 0xda: *res = ~(*src & *dst); break; } +} - /* handle transparency compare */ - if(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { /* TODO: 16-bit compare */ - /* if ROP result matches the transparency colour, don't change the pixel */ - if((res & (~gd54xx->blt.trans_mask & 0xff)) == ((gd54xx->blt.trans_col & 0xff) & (~gd54xx->blt.trans_mask & 0xff))) - return; + +static uint8_t +gd54xx_mem_sys_dest_read(gd54xx_t *gd54xx) +{ + uint8_t ret = 0xff; + + if (gd54xx->blt.msd_buf_cnt != 0) { + ret = gd54xx->blt.msd_buf[gd54xx->blt.msd_buf_pos++]; + gd54xx->blt.msd_buf_cnt--; + + if (gd54xx->blt.msd_buf_cnt == 0) { + if (gd54xx->countminusone == 1) { + gd54xx->blt.msd_buf_pos = 0; + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && + !(gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) + gd54xx_start_blit(0xff, 8, gd54xx, &gd54xx->svga); + else + gd54xx_start_blit(0xffffffff, 32, gd54xx, &gd54xx->svga); + } else + gd54xx_reset_blit(gd54xx); /* End of blit, do no more. */ } - - svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask] = res; -} - - -/* non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored */ -static void -gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) -{ - /* TODO: add support for reverse direction */ - uint8_t x, pixel; - - for (x=0;x<32;x+=8) { - pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); - if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) - gd54xx_memsrc_rop(gd54xx, svga, pixel, svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); - gd54xx->blt.dst_addr_backup++; - gd54xx->blt.pixel_cnt++; - } - if (gd54xx->blt.pixel_cnt > gd54xx->blt.width) { - gd54xx->blt.pixel_cnt = 0; - gd54xx->blt.scan_cnt++; - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch*gd54xx->blt.scan_cnt); - } - if (gd54xx->blt.scan_cnt > gd54xx->blt.height) { - gd54xx->blt.sys_tx = 0; /* BitBLT complete */ - gd543x_recalc_mapping(gd54xx); } + + return ret; } static void -gd54xx_blt_write_w(uint32_t addr, uint16_t val, void *p) +gd54xx_mem_sys_src_write(gd54xx_t *gd54xx, uint8_t val) { - gd54xx_t *gd54xx = (gd54xx_t *)p; + int i; - gd54xx_start_blit(val, 16, gd54xx, &gd54xx->svga); -} + gd54xx->blt.sys_src32 &= ~(0xff << (gd54xx->blt.sys_cnt << 3)); + gd54xx->blt.sys_src32 |= (val << (gd54xx->blt.sys_cnt << 3)); + gd54xx->blt.sys_cnt = (gd54xx->blt.sys_cnt + 1) & 3; - -static void -gd54xx_blt_write_l(uint32_t addr, uint32_t val, void *p) -{ - gd54xx_t *gd54xx = (gd54xx_t *)p; - - if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { - gd54xx_start_blit(val & 0xff, 8, gd54xx, &gd54xx->svga); - gd54xx_start_blit((val>>8) & 0xff, 8, gd54xx, &gd54xx->svga); - gd54xx_start_blit((val>>16) & 0xff, 8, gd54xx, &gd54xx->svga); - gd54xx_start_blit((val>>24) & 0xff, 8, gd54xx, &gd54xx->svga); - } else - gd54xx_start_blit(val, 32, gd54xx, &gd54xx->svga); + if (gd54xx->blt.sys_cnt == 0) { + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && + !(gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) { + for (i = 0; i < 32; i += 8) + gd54xx_start_blit((gd54xx->blt.sys_src32 >> i) & 0xff, 8, gd54xx, &gd54xx->svga); + } else + gd54xx_start_blit(gd54xx->blt.sys_src32, 32, gd54xx, &gd54xx->svga); + } } @@ -1000,22 +1275,19 @@ gd54xx_write(uint32_t addr, uint8_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - - if (gd54xx->blt.sys_tx) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_cnt++; - if(gd54xx->blt.sys_cnt >= 4) { - gd54xx_blit_dword(gd54xx, svga); - gd54xx->blt.sys_cnt = 0; - } - } - return; - } - addr &= svga->banked_mask; - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_mem_sys_src_write(gd54xx, val); + return; + } + + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_write(addr, val, svga); + return; + } + + addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1]; svga_write_linear(addr, val, svga); } @@ -1026,16 +1298,20 @@ gd54xx_writew(uint32_t addr, uint16_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - - if (gd54xx->blt.sys_tx) - { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); - return; - } - - addr &= svga->banked_mask; - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr + 1, val >> 8, gd54xx); + return; + } + + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_writew(addr, val, svga); + return; + } + + addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1]; if (svga->writemode < 4) svga_writew_linear(addr, val, svga); @@ -1052,17 +1328,21 @@ gd54xx_writel(uint32_t addr, uint32_t val, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - if (gd54xx->blt.sys_tx) - { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); - gd54xx_write(addr+2, val >> 16, gd54xx); - gd54xx_write(addr+3, val >> 24, gd54xx); - return; - } + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr + 1, val >> 8, gd54xx); + gd54xx_write(addr + 2, val >> 16, gd54xx); + gd54xx_write(addr + 3, val >> 24, gd54xx); + return; + } - addr &= svga->banked_mask; - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_writel(addr, val, svga); + return; + } + + addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1]; if (svga->writemode < 4) svga_writel_linear(addr, val, svga); @@ -1134,20 +1414,51 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) static uint8_t gd54xx_get_aperture(uint32_t addr) { - uint32_t ap = addr >> 22; - return (uint8_t) (ap & 0x03); + uint32_t ap = addr >> 22; + return (uint8_t) (ap & 0x03); +} + + +static int +gd54xx_aperture2_enabled(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) + return 0; + + if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) + return 0; + + if (!(gd54xx->blt.status & CIRRUS_BLT_APERTURE2)) + return 0; + + return 1; } static uint8_t gd54xx_readb_linear(uint32_t addr, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); addr &= 0x003fffff; /* 4 MB mask */ + if ((svga->seqregs[0x07] & 0x01) == 0) + return svga_read_linear(addr, svga); + + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + return gd543x_mmio_read(addr & 0x000000ff, gd54xx); + } + + /* Do mem sys dest reads here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) + return gd54xx_mem_sys_dest_read(gd54xx); + switch (ap) { case 0: default: @@ -1164,61 +1475,52 @@ gd54xx_readb_linear(uint32_t addr, void *p) return 0xff; } - if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) - return gd543x_mmio_read(addr & 0x000000ff, gd54xx); - } - - return svga_read_linear(addr, p); + return svga_read_linear(addr, svga); } static uint16_t gd54xx_readw_linear(uint32_t addr, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); - uint16_t temp, temp2; + uint16_t temp; addr &= 0x003fffff; /* 4 MB mask */ - if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x07] & 0x01) == 0) + return svga_readw_linear(addr, svga); + + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { - if (ap == 2) - addr ^= 0x00000002; - temp = gd543x_mmio_readw(addr & 0x000000ff, gd54xx); - - switch(ap) { - case 0: - default: - return temp; - case 1: - case 2: - temp2 = temp >> 8; - temp2 |= ((temp & 0xff) << 8); - return temp; - case 3: - return 0xffff; - } + return temp; } } + /* Do mem sys dest reads here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + temp = gd54xx_readb_linear(addr, p); + temp |= gd54xx_readb_linear(addr + 1, p) << 8; + return temp; + } + switch (ap) { case 0: default: - return svga_readw_linear(addr, p); + return svga_readw_linear(addr, svga); case 2: /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ addr ^= 0x00000002; case 1: - temp = svga_readb_linear(addr + 1, p); - temp |= (svga_readb_linear(addr, p) << 8); + temp = svga_readb_linear(addr + 1, svga); + temp |= (svga_readb_linear(addr, svga) << 8); if (svga->fast) - cycles -= video_timing_read_w; + sub_cycles(video_timing_read_w); return temp; case 3: @@ -1230,64 +1532,56 @@ gd54xx_readw_linear(uint32_t addr, void *p) static uint32_t gd54xx_readl_linear(uint32_t addr, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); - uint32_t temp, temp2; + uint32_t temp; addr &= 0x003fffff; /* 4 MB mask */ - if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x07] & 0x01) == 0) + return svga_readl_linear(addr, svga); + + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); - - switch(ap) { - case 0: - default: - return temp; - case 1: - temp2 = temp >> 24; - temp2 |= ((temp >> 16) & 0xff) << 8; - temp2 |= ((temp >> 8) & 0xff) << 16; - temp2 |= (temp & 0xff) << 24; - - return temp2; - case 2: - temp2 = (temp >> 8) & 0xff; - temp2 |= (temp & 0xff) << 8; - temp2 = ((temp >> 24) & 0xff) << 16; - temp2 = ((temp >> 16) & 0xff) << 24; - - return temp2; - case 3: - return 0xffffffff; - } + return temp; } } + /* Do mem sys dest reads here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + temp = gd54xx_readb_linear(addr, p); + temp |= gd54xx_readb_linear(addr + 1, p) << 8; + temp |= gd54xx_readb_linear(addr + 2, p) << 16; + temp |= gd54xx_readb_linear(addr + 3, p) << 24; + return temp; + } + switch (ap) { case 0: default: - return svga_readw_linear(addr, p); + return svga_readl_linear(addr, svga); case 1: - temp = svga_readb_linear(addr + 1, p); - temp |= (svga_readb_linear(addr, p) << 8); - temp |= (svga_readb_linear(addr + 3, p) << 16); - temp |= (svga_readb_linear(addr + 2, p) << 24); + temp = svga_readb_linear(addr + 1, svga); + temp |= (svga_readb_linear(addr, svga) << 8); + temp |= (svga_readb_linear(addr + 3, svga) << 16); + temp |= (svga_readb_linear(addr + 2, svga) << 24); if (svga->fast) - cycles -= video_timing_read_l; + sub_cycles(video_timing_read_l); return temp; case 2: - temp = svga_readb_linear(addr + 3, p); - temp |= (svga_readb_linear(addr + 2, p) << 8); - temp |= (svga_readb_linear(addr + 1, p) << 16); - temp |= (svga_readb_linear(addr, p) << 24); + temp = svga_readb_linear(addr + 3, svga); + temp |= (svga_readb_linear(addr + 2, svga) << 8); + temp |= (svga_readb_linear(addr + 1, svga) << 16); + temp |= (svga_readb_linear(addr, svga) << 24); if (svga->fast) - cycles -= video_timing_read_l; + sub_cycles(video_timing_read_l); return temp; case 3: @@ -1296,15 +1590,123 @@ gd54xx_readl_linear(uint32_t addr, void *p) } +static uint8_t +gd5436_aperture2_readb(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) + return gd54xx_mem_sys_dest_read(gd54xx); + + return 0xff; +} + + +static uint16_t +gd5436_aperture2_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + uint16_t ret = 0xffff; + + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd5436_aperture2_readb(addr, p); + ret |= gd5436_aperture2_readb(addr + 1, p) << 8; + return ret; + } + + return ret; +} + + +static uint32_t +gd5436_aperture2_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + uint32_t ret = 0xffffffff; + + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd5436_aperture2_readb(addr, p); + ret |= gd5436_aperture2_readb(addr + 1, p) << 8; + ret |= gd5436_aperture2_readb(addr + 2, p) << 16; + ret |= gd5436_aperture2_readb(addr + 3, p) << 24; + return ret; + } + + return ret; +} + + +static void +gd5436_aperture2_writeb(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest + && gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) + gd54xx_mem_sys_src_write(gd54xx, val); +} + + +static void +gd5436_aperture2_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest + && gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd5436_aperture2_writeb(addr, val, gd54xx); + gd5436_aperture2_writeb(addr + 1, val >> 8, gd54xx); + } +} + + +static void +gd5436_aperture2_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest + && gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd5436_aperture2_writeb(addr, val, gd54xx); + gd5436_aperture2_writeb(addr + 1, val >> 8, gd54xx); + gd5436_aperture2_writeb(addr + 2, val >> 16, gd54xx); + gd5436_aperture2_writeb(addr + 3, val >> 24, gd54xx); + } +} + + static void gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); + + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_write_linear(addr, val, svga); + return; + } + addr &= 0x003fffff; /* 4 MB mask */ + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); + return; + } + } + + /* Do mem sys src writes here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_mem_sys_src_write(gd54xx, val); + return; + } + switch (ap) { case 0: default: @@ -1321,24 +1723,6 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) return; } - if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) - gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); - } - - if (gd54xx->blt.sys_tx) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_cnt++; - if(gd54xx->blt.sys_cnt >= 4) { - gd54xx_blit_dword(gd54xx, svga); - gd54xx->blt.sys_cnt = 0; - } - } - return; - } - svga_write_linear(addr, val, svga); } @@ -1346,39 +1730,33 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) static void gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); - uint16_t temp; - if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { - switch(ap) { - case 0: - default: - gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); - return; - case 2: - addr ^= 0x00000002; - case 1: - temp = (val >> 8); - temp |= ((val & 0xff) << 8); - gd543x_mmio_writew(addr & 0x000000ff, temp, gd54xx); - case 3: - return; - } - } - } - - if (gd54xx->blt.sys_tx) { - gd54xx_writeb_linear(addr, val, svga); - gd54xx_writeb_linear(addr+1, val >> 8, svga); + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_writew_linear(addr, val, svga); return; } addr &= 0x003fffff; /* 4 MB mask */ + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); + return; + } + } + + /* Do mem sys src writes here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_writeb_linear(addr, val, gd54xx); + gd54xx_writeb_linear(addr + 1, val >> 8, gd54xx); + return; + } + if (svga->writemode < 4) { switch(ap) { case 0: @@ -1392,7 +1770,7 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) svga_writeb_linear(addr, val >> 8, svga); if (svga->fast) - cycles -= video_timing_write_w; + sub_cycles(video_timing_write_w); case 3: return; } @@ -1418,49 +1796,35 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) static void gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); - uint32_t temp; - if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { - switch(ap) { - case 0: - default: - gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); - return; - case 2: - temp = (val >> 24); - temp |= ((val >> 16) & 0xff) << 8; - temp |= ((val >> 8) & 0xff) << 16; - temp |= (val & 0xff) << 24; - gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); - return; - case 1: - temp = ((val >> 8) & 0xff); - temp |= (val & 0xff) << 8; - temp |= (val >> 24) << 16; - temp |= ((val >> 16) & 0xff) << 24; - gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); - return; - case 3: - return; - } - } - } - - if (gd54xx->blt.sys_tx) { - gd54xx_writeb_linear(addr, val, svga); - gd54xx_writeb_linear(addr+1, val >> 8, svga); - gd54xx_writeb_linear(addr+2, val >> 16, svga); - gd54xx_writeb_linear(addr+3, val >> 24, svga); + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_writel_linear(addr, val, svga); return; } addr &= 0x003fffff; /* 4 MB mask */ - + + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); + return; + } + } + + /* Do mem sys src writes here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_writeb_linear(addr, val, gd54xx); + gd54xx_writeb_linear(addr + 1, val >> 8, gd54xx); + gd54xx_writeb_linear(addr + 2, val >> 16, gd54xx); + gd54xx_writeb_linear(addr + 3, val >> 24, gd54xx); + return; + } + if (svga->writemode < 4) { switch(ap) { case 0: @@ -1483,7 +1847,7 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) } if (svga->fast) - cycles -= video_timing_write_l; + sub_cycles(video_timing_write_l); } else { switch(ap) { case 0: @@ -1516,8 +1880,15 @@ gd54xx_read(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - addr &= svga->banked_mask; - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if ((svga->seqregs[0x07] & 0x01) == 0) + return svga_read(addr, svga); + + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) + return gd54xx_mem_sys_dest_read(gd54xx); + + addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1]; return svga_read_linear(addr, svga); } @@ -1527,9 +1898,19 @@ gd54xx_readw(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint16_t ret; - addr &= svga->banked_mask; - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + if ((svga->seqregs[0x07] & 0x01) == 0) + return svga_readw(addr, svga); + + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd54xx_read(addr, p); + ret |= gd54xx_read(addr + 1, p) << 8; + return ret; + } + + addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1]; return svga_readw_linear(addr, svga); } @@ -1539,9 +1920,21 @@ gd54xx_readl(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint32_t ret; - addr &= svga->banked_mask; - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + if ((svga->seqregs[0x07] & 0x01) == 0) + return svga_readl(addr, svga); + + if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd54xx_read(addr, p); + ret |= gd54xx_read(addr + 1, p) << 8; + ret |= gd54xx_read(addr + 2, p) << 16; + ret |= gd54xx_read(addr + 3, p) << 24; + return ret; + } + + addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1]; return svga_readl_linear(addr, svga); } @@ -1561,173 +1954,185 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - + uint8_t old; + if (gd543x_do_mmio(svga, addr)) { switch (addr & 0xff) { - case 0x00: - if (gd54xx_is_5434(svga)) + case 0x00: + if (gd54xx_is_5434(svga)) gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffffff00) | val; - else + else gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00) | val; - break; - case 0x01: - if (gd54xx_is_5434(svga)) + break; + case 0x01: + if (gd54xx_is_5434(svga)) gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffff00ff) | (val << 8); - else + else gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ff) | (val << 8); - break; - case 0x02: - if (gd54xx_is_5434(svga)) + break; + case 0x02: + if (gd54xx_is_5434(svga)) gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00ffff) | (val << 16); - break; - case 0x03: - if (gd54xx_is_5434(svga)) + break; + case 0x03: + if (gd54xx_is_5434(svga)) gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ffffff) | (val << 24); - break; + break; - case 0x04: - if (gd54xx_is_5434(svga)) + case 0x04: + if (gd54xx_is_5434(svga)) gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffffff00) | val; - else + else gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00) | val; - break; - case 0x05: - if (gd54xx_is_5434(svga)) + break; + case 0x05: + if (gd54xx_is_5434(svga)) gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffff00ff) | (val << 8); - else + else gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ff) | (val << 8); - break; - case 0x06: - if (gd54xx_is_5434(svga)) + break; + case 0x06: + if (gd54xx_is_5434(svga)) gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00ffff) | (val << 16); - break; - case 0x07: - if (gd54xx_is_5434(svga)) + break; + case 0x07: + if (gd54xx_is_5434(svga)) gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ffffff) | (val << 24); - break; + break; - case 0x08: - gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; - break; - case 0x09: - gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); - if (gd54xx_is_5434(svga)) + case 0x08: + gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; + break; + case 0x09: + gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); + if (gd54xx_is_5434(svga)) gd54xx->blt.width &= 0x1fff; - else + else gd54xx->blt.width &= 0x07ff; - break; - case 0x0a: - gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; - break; - case 0x0b: - gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); - gd54xx->blt.height &= 0x03ff; - break; - case 0x0c: - gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; - break; - case 0x0d: - gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); - break; - case 0x0e: - gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; - break; - case 0x0f: - gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); - break; + break; + case 0x0a: + gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; + break; + case 0x0b: + gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.height &= 0x07ff; + else + gd54xx->blt.height &= 0x03ff; + break; + case 0x0c: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); + gd54xx->blt.dst_pitch &= 0x1fff; + break; + case 0x0e: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); + gd54xx->blt.src_pitch &= 0x1fff; + break; - case 0x10: - gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; - break; - case 0x11: - gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); - break; - case 0x12: - gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); - if (gd54xx_is_5434(svga)) + case 0x10: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) gd54xx->blt.dst_addr &= 0x3fffff; - else + else gd54xx->blt.dst_addr &= 0x1fffff; - - if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_AUTOSTART)) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_tx = 1; - gd54xx->blt.sys_cnt = 0; - gd54xx->blt.sys_buf = 0; - gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; - gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; - } else - gd54xx_start_blit(0, -1, gd54xx, svga); - } - break; - case 0x14: - gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; - break; - case 0x15: - gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); - break; - case 0x16: - gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); - if (gd54xx_is_5434(svga)) + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_AUTOSTART) && + !(gd54xx->blt.status & CIRRUS_BLT_BUSY)) { + gd54xx->blt.status |= CIRRUS_BLT_BUSY; + gd54xx_start_blit(0, 0xffffffff, gd54xx, svga); + } + break; + + case 0x14: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) gd54xx->blt.src_addr &= 0x3fffff; - else + else gd54xx->blt.src_addr &= 0x1fffff; - break; + break; - case 0x17: - gd54xx->blt.mask = val; - break; - case 0x18: - gd54xx->blt.mode = val; - break; + case 0x17: + gd54xx->blt.mask = val; + break; + case 0x18: + gd54xx->blt.mode = val; + gd543x_recalc_mapping(gd54xx); + break; - case 0x1a: - gd54xx->blt.rop = val; - break; + case 0x1a: + gd54xx->blt.rop = val; + break; - case 0x1b: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) - gd54xx->blt.modeext = val; - break; - - case 0x1c: - gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; - break; - - case 0x1d: - gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); - break; - - case 0x20: - gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; - break; - - case 0x21: - gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); - break; - - case 0x40: - gd54xx->blt.status = val; - if (gd54xx->blt.status & CIRRUS_BLT_START) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_tx = 1; - gd54xx->blt.sys_cnt = 0; - gd54xx->blt.sys_buf = 0; - gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; - gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; - } else - gd54xx_start_blit(0, -1, gd54xx, svga); - } - break; - } + case 0x1b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.modeext = val; + break; + + case 0x1c: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; + break; + case 0x1d: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); + break; + + case 0x20: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; + break; + case 0x21: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); + break; + + case 0x40: + old = gd54xx->blt.status; + gd54xx->blt.status = val; + gd543x_recalc_mapping(gd54xx); + if (!(old & CIRRUS_BLT_RESET) && (gd54xx->blt.status & CIRRUS_BLT_RESET)) + gd54xx_reset_blit(gd54xx); + else if (!(old & CIRRUS_BLT_START) && (gd54xx->blt.status & CIRRUS_BLT_START)) { + gd54xx->blt.status |= CIRRUS_BLT_BUSY; + gd54xx_start_blit(0, 0xffffffff, gd54xx, svga); + } + break; + } } else if (gd54xx->mmio_vram_overlap) gd54xx_write(addr, val, gd54xx); } +static void +gd543x_mmio_writeb(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (!gd543x_do_mmio(svga, addr) && !gd54xx->blt.ms_is_dest && + gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_mem_sys_src_write(gd54xx, val); + return; + } + + gd543x_mmio_write(addr, val, p); +} + + static void gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) { @@ -1736,10 +2141,16 @@ gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) if (gd543x_do_mmio(svga, addr)) { gd543x_mmio_write(addr, val & 0xff, gd54xx); - gd543x_mmio_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr + 1, val >> 8, gd54xx); } else if (gd54xx->mmio_vram_overlap) { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr + 1, val >> 8, gd54xx); + } else { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr + 1, val >> 8, gd54xx); + } } } @@ -1756,10 +2167,18 @@ gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) gd543x_mmio_write(addr+2, val >> 16, gd54xx); gd543x_mmio_write(addr+3, val >> 24, gd54xx); } else if (gd54xx->mmio_vram_overlap) { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); - gd54xx_write(addr+2, val >> 16, gd54xx); - gd54xx_write(addr+3, val >> 24, gd54xx); + if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr+2, val >> 16, gd54xx); + gd543x_mmio_write(addr+3, val >> 24, gd54xx); + } else { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + } } } @@ -1769,17 +2188,139 @@ gd543x_mmio_read(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint8_t ret = 0xff; if (gd543x_do_mmio(svga, addr)) { switch (addr & 0xff) { - case 0x40: /*BLT status*/ - return 0; + case 0x00: + ret = gd54xx->blt.bg_col & 0xff; + break; + case 0x01: + ret = (gd54xx->blt.bg_col >> 8) & 0xff; + break; + case 0x02: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.bg_col >> 16) & 0xff; + break; + case 0x03: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.bg_col >> 24) & 0xff; + break; + + case 0x04: + ret = gd54xx->blt.fg_col & 0xff; + break; + case 0x05: + ret = (gd54xx->blt.fg_col >> 8) & 0xff; + break; + case 0x06: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.fg_col >> 16) & 0xff; + break; + case 0x07: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.fg_col >> 24) & 0xff; + break; + + case 0x08: + ret = gd54xx->blt.width & 0xff; + break; + case 0x09: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.width >> 8) & 0x1f; + else + ret = (gd54xx->blt.width >> 8) & 0x07; + break; + case 0x0a: + ret = gd54xx->blt.height & 0xff; + break; + case 0x0b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + ret = (gd54xx->blt.height >> 8) & 0x07; + else + ret = (gd54xx->blt.height >> 8) & 0x03; + break; + case 0x0c: + ret = gd54xx->blt.dst_pitch & 0xff; + break; + case 0x0d: + ret = (gd54xx->blt.dst_pitch >> 8) & 0x1f; + break; + case 0x0e: + ret = gd54xx->blt.src_pitch & 0xff; + break; + case 0x0f: + ret = (gd54xx->blt.src_pitch >> 8) & 0x1f; + break; + + case 0x10: + ret = gd54xx->blt.dst_addr & 0xff; + break; + case 0x11: + ret = (gd54xx->blt.dst_addr >> 8) & 0xff; + break; + case 0x12: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.dst_addr >> 16) & 0x3f; + else + ret = (gd54xx->blt.dst_addr >> 16) & 0x1f; + break; + + case 0x14: + ret = gd54xx->blt.src_addr & 0xff; + break; + case 0x15: + ret = (gd54xx->blt.src_addr >> 8) & 0xff; + break; + case 0x16: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.src_addr >> 16) & 0x3f; + else + ret = (gd54xx->blt.src_addr >> 16) & 0x1f; + break; + + case 0x17: + ret = gd54xx->blt.mask; + break; + case 0x18: + ret = gd54xx->blt.mode; + break; + + case 0x1a: + ret = gd54xx->blt.rop; + break; + + case 0x1b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + ret = gd54xx->blt.modeext; + break; + + case 0x1c: + ret = gd54xx->blt.trans_col & 0xff; + break; + case 0x1d: + ret = (gd54xx->blt.trans_col >> 8) & 0xff; + break; + + case 0x20: + ret = gd54xx->blt.trans_mask & 0xff; + break; + case 0x21: + ret = (gd54xx->blt.trans_mask >> 8) & 0xff; + break; + + case 0x40: + ret = gd54xx->blt.status; + break; } - return 0xff; /*All other registers read-only*/ + } else if (gd54xx->mmio_vram_overlap) + ret = gd54xx_read(addr, gd54xx); + else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd54xx_mem_sys_dest_read(gd54xx); } - else if (gd54xx->mmio_vram_overlap) - return gd54xx_read(addr, gd54xx); - return 0xff; + + return ret; } @@ -1788,12 +2329,20 @@ gd543x_mmio_readw(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint16_t ret = 0xffff; if (gd543x_do_mmio(svga, addr)) - return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); + ret = gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); else if (gd54xx->mmio_vram_overlap) - return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); - return 0xffff; + ret = gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); + else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd543x_mmio_read(addr, p); + ret |= gd543x_mmio_read(addr + 1, p) << 8; + return ret; + } + + return ret; } @@ -1802,292 +2351,461 @@ gd543x_mmio_readl(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint32_t ret = 0xffffffff; if (gd543x_do_mmio(svga, addr)) - return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); + ret = gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); else if (gd54xx->mmio_vram_overlap) - return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); - return 0xffffffff; + ret = gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); + else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + ret = gd543x_mmio_read(addr, p); + ret |= gd543x_mmio_read(addr + 1, p) << 8; + ret |= gd543x_mmio_read(addr + 2, p) << 16; + ret |= gd543x_mmio_read(addr + 3, p) << 24; + return ret; + } + + return ret; } -static void -gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) +static uint8_t +gd54xx_color_expand(gd54xx_t *gd54xx, int mask, int shift) { - int blt_mask = 0; - int x_max = 0; + uint8_t ret; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) + ret = gd54xx->blt.fg_col >> (shift << 3); + else + ret = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + + return ret; +} + + +static int +gd54xx_get_pixel_width(gd54xx_t *gd54xx) +{ + int ret = 1; - int shift = 0, last_x = 0; - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { case CIRRUS_BLTMODE_PIXELWIDTH8: - blt_mask = gd54xx->blt.mask & 7; - x_max = 8; + ret = 1; break; case CIRRUS_BLTMODE_PIXELWIDTH16: - blt_mask = gd54xx->blt.mask & 7; - x_max = 16; - blt_mask *= 2; + ret = 2; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - blt_mask = (gd54xx->blt.mask & 0x1f); - x_max = 24; + ret = 3; break; case CIRRUS_BLTMODE_PIXELWIDTH32: - blt_mask = gd54xx->blt.mask & 7; - x_max = 32; - blt_mask *= 4; + ret = 4; break; } - last_x = (x_max >> 3) - 1; + return ret; +} - if (count == -1) { + +static void +gd54xx_blit(gd54xx_t *gd54xx, uint8_t mask, uint8_t *dst, uint8_t target, int skip) +{ + int is_transp, is_bgonly; + + /* skip indicates whether or not it is a pixel to be skipped (used for left skip); + mask indicates transparency or not (only when transparent comparison is enabled): + color expand: direct pattern bit; 1 = write, 0 = do not write + (the other way around in inverse mode); + normal 8-bpp or 16-bpp: does not match transparent color = write, + matches transparent color = do not write */ + + /* Make sure to always ignore transparency and skip in case of mem sys dest. */ + is_transp = (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSDEST) ? 0 : (gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP); + is_bgonly = (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSDEST) ? 0 : (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_BACKGROUNDONLY); + skip = (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSDEST) ? 0 : skip; + + if (is_transp) { + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && + (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)) + mask = !mask; + + /* If mask is 1 and it is not a pixel to be skipped, write it. */ + if (mask && !skip) + *dst = target; + } else if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && is_bgonly) { + /* If mask is 1 or it is not a pixel to be skipped, write it. + (Skip only background pixels.) */ + if (mask || !skip) + *dst = target; + } else { + /* If if it is not a pixel to be skipped, write it. */ + if (!skip) + *dst = target; + } +} + + +static int +gd54xx_transparent_comp(gd54xx_t *gd54xx, uint32_t xx, uint8_t src) +{ + svga_t *svga = &gd54xx->svga; + int ret = 1; + + if ((gd54xx->blt.pixel_width <= 2) && gd54xx_has_transp(svga, 0)) { + ret = src ^ ((uint8_t *) &(gd54xx->blt.trans_col))[xx]; + if (gd54xx_has_transp(svga, 1)) + ret &= ~(((uint8_t *) &(gd54xx->blt.trans_mask))[xx]); + ret = !ret; + } + + return ret; +} + + +static void +gd54xx_pattern_copy(gd54xx_t *gd54xx) +{ + uint8_t target, src, *dst; + int x, y, pattern_y, pattern_pitch; + uint32_t bitmask = 0, xx, pixel; + uint32_t srca, srca2, dsta; + svga_t *svga = &gd54xx->svga; + + pattern_pitch = gd54xx->blt.pixel_width << 3; + + if (gd54xx->blt.pixel_width == 3) + pattern_pitch = 32; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + pattern_pitch = 1; + + dsta = gd54xx->blt.dst_addr & svga->vram_mask; + /* The vertical offset is in the three low-order bits of the Source Address register. */ + pattern_y = gd54xx->blt.src_addr & 0x07; + + /* Mode Pattern bytes Pattern line bytes + --------------------------------------------------- + Color Expansion 8 1 + 8-bpp 64 8 + 16-bpp 128 16 + 24-bpp 256 32 + 32-bpp 256 32 + */ + + /* The boundary has to be equal to the size of the pattern. */ + srca = (gd54xx->blt.src_addr & ~0x07) & svga->vram_mask; + + for (y = 0; y <= gd54xx->blt.height; y++) { + /* Go to the correct pattern line. */ + srca2 = srca + (pattern_y * pattern_pitch); + pixel = 0; + for (x = 0; x <= gd54xx->blt.width; x += gd54xx->blt.pixel_width) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) + bitmask = 1; + else + bitmask = svga->vram[srca2 & svga->vram_mask] & (0x80 >> pixel); + } + for (xx = 0; xx < gd54xx->blt.pixel_width; xx++) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + src = gd54xx_color_expand(gd54xx, bitmask, xx); + else { + src = svga->vram[(srca2 + (x % (gd54xx->blt.pixel_width << 3)) + xx) & svga->vram_mask]; + bitmask = gd54xx_transparent_comp(gd54xx, xx, src); + } + dst = &(svga->vram[(dsta + x + xx) & svga->vram_mask]); + target = *dst; + gd54xx_rop(gd54xx, &target, &target, &src); + if (gd54xx->blt.pixel_width == 3) + gd54xx_blit(gd54xx, bitmask, dst, target, ((x + xx) < gd54xx->blt.pattern_x)); + else + gd54xx_blit(gd54xx, bitmask, dst, target, (x < gd54xx->blt.pattern_x)); + } + pixel = (pixel + 1) & 7; + svga->changedvram[((dsta + x) & svga->vram_mask) >> 12] = changeframecount; + } + pattern_y = (pattern_y + 1) & 7; + dsta += gd54xx->blt.dst_pitch; + } +} + + +static void +gd54xx_reset_blit(gd54xx_t *gd54xx) +{ + gd54xx->countminusone = 0; + gd54xx->blt.status &= ~(CIRRUS_BLT_START|CIRRUS_BLT_BUSY|CIRRUS_BLT_FIFOUSED); +} + + +/* Each blit is either 1 byte -> 1 byte (non-color expand blit) + or 1 byte -> 8/16/24/32 bytes (color expand blit). */ +static void +gd54xx_mem_sys_src(gd54xx_t *gd54xx, uint32_t cpu_dat, uint32_t count) +{ + uint8_t *dst, exp, target; + int mask_shift; + uint32_t byte_pos, bitmask = 0; + svga_t *svga = &gd54xx->svga; + + gd54xx->blt.ms_is_dest = 0; + + if (gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSDEST | CIRRUS_BLTMODE_PATTERNCOPY)) + gd54xx_reset_blit(gd54xx); + else if (count == 0xffffffff) { gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; - gd54xx->blt.width_backup = gd54xx->blt.width; - gd54xx->blt.height_internal = gd54xx->blt.height; - gd54xx->blt.x_count = 0; - if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) - gd54xx->blt.y_count = gd54xx->blt.src_addr & 7; - else - gd54xx->blt.y_count = 0; - - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { - if (!(svga->seqregs[7] & 0xf0)) { - mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); - mem_mapping_set_p(&svga->mapping, gd54xx); - } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); - mem_mapping_set_p(&gd54xx->linear_mapping, gd54xx); - } - gd543x_recalc_mapping(gd54xx); - return; - } else { - if (!(svga->seqregs[7] & 0xf0)) { - mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); - mem_mapping_set_p(&gd54xx->svga.mapping, gd54xx); - } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); - mem_mapping_set_p(&gd54xx->linear_mapping, svga); - } - gd543x_recalc_mapping(gd54xx); - } - } else if (gd54xx->blt.height_internal == 0xffff) + gd54xx->blt.x_count = gd54xx->blt.xx_count = 0; + gd54xx->blt.y_count = 0; + gd54xx->countminusone = 1; + gd54xx->blt.sys_src32 = 0x00000000; + gd54xx->blt.sys_cnt = 0; return; + } else if (gd54xx->countminusone) { + if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) || (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) { + if (!gd54xx->blt.xx_count && !gd54xx->blt.x_count) + byte_pos = (((gd54xx->blt.mask >> 5) & 3) << 3); + else + byte_pos = 0; + mask_shift = 31 - byte_pos; + if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) + cpu_dat >>= byte_pos; + } else + mask_shift = 7; + + while (mask_shift > -1) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + bitmask = (cpu_dat >> mask_shift) & 0x01; + exp = gd54xx_color_expand(gd54xx, bitmask, gd54xx->blt.xx_count); + } else { + exp = cpu_dat & 0xff; + bitmask = gd54xx_transparent_comp(gd54xx, gd54xx->blt.xx_count, exp); + } + + dst = &(svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); + target = *dst; + gd54xx_rop(gd54xx, &target, &target, &exp); + if ((gd54xx->blt.pixel_width == 3) && (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) + gd54xx_blit(gd54xx, bitmask, dst, target, ((gd54xx->blt.x_count + gd54xx->blt.xx_count) < gd54xx->blt.pattern_x)); + else + gd54xx_blit(gd54xx, bitmask, dst, target, (gd54xx->blt.x_count < gd54xx->blt.pattern_x)); + + gd54xx->blt.dst_addr_backup += gd54xx->blt.dir; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + gd54xx->blt.xx_count = (gd54xx->blt.xx_count + 1) % gd54xx->blt.pixel_width; + + svga->changedvram[(gd54xx->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; + + if (!gd54xx->blt.xx_count) { + /* 1 mask bit = 1 blitted pixel */ + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + mask_shift--; + else { + cpu_dat >>= 8; + mask_shift -= 8; + } + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + gd54xx->blt.x_count = (gd54xx->blt.x_count + gd54xx->blt.pixel_width) % (gd54xx->blt.width + 1); + else + gd54xx->blt.x_count = (gd54xx->blt.x_count + 1) % (gd54xx->blt.width + 1); + + if (!gd54xx->blt.x_count) { + gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) % (gd54xx->blt.height + 1); + if (gd54xx->blt.y_count) + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch * gd54xx->blt.y_count * gd54xx->blt.dir); + else { + /* If we're here, the blit is over, reset. */ + gd54xx_reset_blit(gd54xx); + } + /* Stop blitting and request new data if end of line reached. */ + return; + } + } + } + } +} + + +static void +gd54xx_normal_blit(uint32_t count, gd54xx_t *gd54xx, svga_t *svga) +{ + uint8_t src = 0, dst; + uint16_t width = gd54xx->blt.width; + int x_max = 0, shift = 0, mask = 0; + uint32_t src_addr = gd54xx->blt.src_addr; + uint32_t dst_addr = gd54xx->blt.dst_addr; + + x_max = gd54xx->blt.pixel_width << 3; + + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.height_internal = gd54xx->blt.height; + gd54xx->blt.x_count = 0; + gd54xx->blt.y_count = 0; while (count) { - uint8_t src = 0, dst; - int mask = 0; + src = 0; + mask = 0; - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { - if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { - if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) - mask = (cpu_dat >> 31); - else - mask = cpu_dat & 0x80; - - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; - shift = 0; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - shift = (gd54xx->blt.x_count & 1); - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - shift = (gd54xx->blt.x_count % 3); - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - shift = (gd54xx->blt.x_count & 3); - break; - } - - src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); - - if (shift == last_x) { - cpu_dat <<= 1; - count--; - } - } else { - /*This must stay for general purpose Cirrus drivers to render fine in WinNT 3.5x*/ - src = cpu_dat & 0xff; - cpu_dat >>= 8; - count -= 8; - mask = 1; - } + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / gd54xx->blt.pixel_width)); + shift = (gd54xx->blt.x_count % gd54xx->blt.pixel_width); + src = gd54xx_color_expand(gd54xx, mask, shift); } else { - switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { - case 0x00: - src = svga->vram[gd54xx->blt.src_addr & svga->vram_mask]; - gd54xx->blt.src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); - mask = 1; - break; - case CIRRUS_BLTMODE_PATTERNCOPY: - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~7)) + (gd54xx->blt.y_count << 3) + (gd54xx->blt.x_count & 7)]; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~15)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count % 24)]; - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; - break; - } - mask = 1; - break; - case CIRRUS_BLTMODE_COLOREXPAND: - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> gd54xx->blt.x_count); - shift = 0; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 1)); - shift = (gd54xx->blt.dst_addr & 1); - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); - shift = (gd54xx->blt.dst_addr % 3); - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); - shift = (gd54xx->blt.dst_addr & 3); - break; - } - src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); - break; - case CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND: - if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - shift = 0; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - shift = (gd54xx->blt.dst_addr & 1); - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - shift = (gd54xx->blt.dst_addr % 3); - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - shift = (gd54xx->blt.dst_addr & 3); - break; - } - src = (gd54xx->blt.fg_col >> (shift << 3)); - } else { - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> gd54xx->blt.x_count); - shift = 0; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 1)); - shift = (gd54xx->blt.dst_addr & 1); - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); - shift = (gd54xx->blt.dst_addr % 3); - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 2)); - shift = (gd54xx->blt.dst_addr & 3); - break; - } - - src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); - } - break; - } - count--; + src = svga->vram[src_addr & svga->vram_mask]; + src_addr += gd54xx->blt.dir; + mask = 1; } - dst = svga->vram[gd54xx->blt.dst_addr & svga->vram_mask]; - svga->changedvram[(gd54xx->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount; + count--; - switch (gd54xx->blt.rop) { - case 0x00: dst = 0; break; - case 0x05: dst = src & dst; break; - case 0x06: dst = dst; break; - case 0x09: dst = src & ~dst; break; - case 0x0b: dst = ~ dst; break; - case 0x0d: dst = src; break; - case 0x0e: dst = 0xff; break; - case 0x50: dst = ~ src & dst; break; - case 0x59: dst = src ^ dst; break; - case 0x6d: dst = src | dst; break; - case 0x90: dst = ~(src | dst); break; - case 0x95: dst = ~(src ^ dst); break; - case 0xad: dst = src | ~dst; break; - case 0xd0: dst = ~src; break; - case 0xd6: dst = ~src | dst; break; - case 0xda: dst = ~(src & dst); break; - } - - if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { - if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && - !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && mask)) - svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; - } else { - if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && - !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) - svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; - } + dst = svga->vram[dst_addr & svga->vram_mask]; + svga->changedvram[(dst_addr & svga->vram_mask) >> 12] = changeframecount; - gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + gd54xx_rop(gd54xx, (uint8_t *) &dst, (uint8_t *) &dst, (const uint8_t *) &src); + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)) + mask = !mask; + + /* This handles 8bpp and 16bpp non-color-expanding transparent comparisons. */ + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && + ((gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) <= CIRRUS_BLTMODE_PIXELWIDTH16) && + (src != ((gd54xx->blt.trans_mask >> (shift << 3)) & 0xff))) + mask = 0; + + if (((gd54xx->blt.width - width) >= gd54xx->blt.pattern_x) && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) { + svga->vram[dst_addr & svga->vram_mask] = dst; + } + + dst_addr += gd54xx->blt.dir; gd54xx->blt.x_count++; if (gd54xx->blt.x_count == x_max) { gd54xx->blt.x_count = 0; - if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == CIRRUS_BLTMODE_COLOREXPAND) - gd54xx->blt.src_addr++; + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + src_addr++; } - gd54xx->blt.width--; + width--; + if (width == 0xffff) { + width = gd54xx->blt.width; + dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + (gd54xx->blt.dst_pitch * gd54xx->blt.dir); + gd54xx->blt.y_count = (gd54xx->blt.y_count + gd54xx->blt.dir) & 7; - if (gd54xx->blt.width == 0xffff) { - gd54xx->blt.width = gd54xx->blt.width_backup; + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (gd54xx->blt.x_count != 0) + src_addr++; + } else + src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + (gd54xx->blt.src_pitch * gd54xx->blt.dir); - gd54xx->blt.dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.dst_pitch : gd54xx->blt.dst_pitch); - - switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { - case 0x00: - gd54xx->blt.src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.src_pitch : gd54xx->blt.src_pitch); - break; - case CIRRUS_BLTMODE_COLOREXPAND: - if (gd54xx->blt.x_count != 0) - gd54xx->blt.src_addr++; - break; - } + dst_addr &= svga->vram_mask; + gd54xx->blt.dst_addr_backup &= svga->vram_mask; + src_addr &= svga->vram_mask; + gd54xx->blt.src_addr_backup &= svga->vram_mask; gd54xx->blt.x_count = 0; - if (gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) - gd54xx->blt.y_count = (gd54xx->blt.y_count - 1) & 7; - else - gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) & 7; gd54xx->blt.height_internal--; if (gd54xx->blt.height_internal == 0xffff) { - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { - if (!(svga->seqregs[7] & 0xf0)) { - mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); - mem_mapping_set_p(&svga->mapping, gd54xx); - } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); - mem_mapping_set_p(&gd54xx->linear_mapping, svga); - } - gd543x_recalc_mapping(gd54xx); - } + gd54xx_reset_blit(gd54xx); return; } - - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) - return; } } + + /* Count exhausted, stuff still left to blit. */ + gd54xx_reset_blit(gd54xx); +} + + +static void +gd54xx_mem_sys_dest(uint32_t count, gd54xx_t *gd54xx, svga_t *svga) +{ + gd54xx->blt.ms_is_dest = 1; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_PATTERNCOPY) { + fatal("mem sys dest pattern copy not allowed (see 1994 manual)\n"); + gd54xx_reset_blit(gd54xx); + } else if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + fatal("mem sys dest color expand not allowed (see 1994 manual)\n"); + gd54xx_reset_blit(gd54xx); + } else { + if (count == 0xffffffff) { + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + gd54xx->blt.msd_buf_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.x_count = gd54xx->blt.xx_count = 0; + gd54xx->blt.y_count = 0; + gd54xx->countminusone = 1; + count = 32; + } + + gd54xx->blt.msd_buf_pos = 0; + + while (gd54xx->blt.msd_buf_pos < 32) { + gd54xx->blt.msd_buf[gd54xx->blt.msd_buf_pos & 0x1f] = svga->vram[gd54xx->blt.src_addr_backup & svga->vram_mask]; + gd54xx->blt.src_addr_backup += gd54xx->blt.dir; + gd54xx->blt.msd_buf_pos++; + + gd54xx->blt.x_count = (gd54xx->blt.x_count + 1) % (gd54xx->blt.width + 1); + + if (!gd54xx->blt.x_count) { + gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) % (gd54xx->blt.height + 1); + + if (gd54xx->blt.y_count) + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr + (gd54xx->blt.src_pitch * gd54xx->blt.y_count * gd54xx->blt.dir); + else + gd54xx->countminusone = 2; /* Signal end of blit. */ + /* End of line reached, stop and notify regardless of how much we already transferred. */ + goto request_more_data; + } + } + + /* End of while. */ +request_more_data: + /* If the byte count we have blitted are not divisible by 4, round them up. */ + if (gd54xx->blt.msd_buf_pos & 3) + gd54xx->blt.msd_buf_cnt = (gd54xx->blt.msd_buf_pos & ~3) + 4; + else + gd54xx->blt.msd_buf_cnt = gd54xx->blt.msd_buf_pos; + gd54xx->blt.msd_buf_pos = 0; + return; + } +} + + +static void +gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *svga) +{ + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) && + !(gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) && + !(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP)) + gd54xx->blt.dir = -1; + else + gd54xx->blt.dir = 1; + + gd54xx->blt.pixel_width = gd54xx_get_pixel_width(gd54xx); + + if (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + if (gd54xx->blt.pixel_width == 3) + gd54xx->blt.pattern_x = gd54xx->blt.mask & 0x1f; /* (Mask & 0x1f) bytes. */ + else + gd54xx->blt.pattern_x = (gd54xx->blt.mask & 0x07) * gd54xx->blt.pixel_width; /* (Mask & 0x07) pixels. */ + } else + gd54xx->blt.pattern_x = 0; /* No skip in normal blit mode. */ + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) + gd54xx_mem_sys_src(gd54xx, cpu_dat, count); + else if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSDEST) + gd54xx_mem_sys_dest(count, gd54xx, svga); + else if (gd54xx->blt.mode & CIRRUS_BLTMODE_PATTERNCOPY) { + gd54xx_pattern_copy(gd54xx); + gd54xx_reset_blit(gd54xx); + } else + gd54xx_normal_blit(count, gd54xx, svga); } @@ -2111,7 +2829,6 @@ cl_pci_read(int func, int addr, void *p) case PCI_REG_COMMAND: return gd54xx->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ - // case 0x07: return 0 << 1; /*Fast DEVSEL timing*/ case 0x07: return 0x02; /*Fast DEVSEL timing*/ case 0x08: return gd54xx->rev; /*Revision ID*/ @@ -2156,7 +2873,7 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) case 0x13: gd54xx->lfb_base = val << 24; - gd543x_recalc_mapping(gd54xx); + gd543x_recalc_mapping(gd54xx); break; case 0x30: case 0x32: case 0x33: @@ -2181,6 +2898,7 @@ static void gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); svga_t *svga = &gd54xx->svga; int id = info->local & 0xff; + int vram; wchar_t *romfn = NULL; memset(gd54xx, 0, sizeof(gd54xx_t)); @@ -2189,7 +2907,19 @@ static void gd54xx->rev = 0; gd54xx->has_bios = 1; + switch (id) { +#if defined(DEV_BRANCH) && defined(USE_CL5422) + case CIRRUS_ID_CLGD5402: + case CIRRUS_ID_CLGD5420: + romfn = BIOS_GD5420_PATH; + break; + case CIRRUS_ID_CLGD5422: + case CIRRUS_ID_CLGD5424: + romfn = BIOS_GD5422_PATH; + break; +#endif + case CIRRUS_ID_CLGD5426: romfn = BIOS_GD5426_PATH; break; @@ -2243,34 +2973,89 @@ static void break; } - gd54xx->vram_size = device_get_config_int("memory"); - gd54xx->vram_mask = (gd54xx->vram_size << 20) - 1; + if (id >= CIRRUS_ID_CLGD5420) + vram = device_get_config_int("memory"); + else + vram = 0; + + if (vram) + gd54xx->vram_size = vram << 20; + else + gd54xx->vram_size = 1 << 19; + + gd54xx->vram_mask = gd54xx->vram_size - 1; if (romfn) rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size << 20, + if (info->flags & DEVICE_ISA) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_isa); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_vlb_pci); + + svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size, gd54xx_recalctimings, gd54xx_in, gd54xx_out, gd54xx_hwcursor_draw, NULL); - svga_set_ven_write(&gd54xx->svga, gd54xx_write_modes45); + svga->ven_write = gd54xx_write_modes45; + if (vram <= 1) + svga->decode_mask = gd54xx->vram_mask; mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); mem_mapping_set_p(&svga->mapping, gd54xx); - mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_write, gd543x_mmio_writew, gd543x_mmio_writel, NULL, 0, gd54xx); - mem_mapping_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, 0, svga); + mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, + gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, + gd543x_mmio_writeb, gd543x_mmio_writew, gd543x_mmio_writel, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_disable(&gd54xx->mmio_mapping); + mem_mapping_add(&gd54xx->linear_mapping, 0, 0, + gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, + gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_add(&gd54xx->aperture2_mapping, 0, 0, + gd5436_aperture2_readb, gd5436_aperture2_readw, gd5436_aperture2_readl, + gd5436_aperture2_writeb, gd5436_aperture2_writew, gd5436_aperture2_writel, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_disable(&gd54xx->aperture2_mapping); io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); svga->hwcursor.yoff = 32; svga->hwcursor.xoff = 0; +#if defined(DEV_BRANCH) && defined(USE_CL5422) + if (id >= CIRRUS_ID_CLGD5420) { + gd54xx->vclk_n[0] = 0x4a; + gd54xx->vclk_d[0] = 0x2b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + gd54xx->vclk_n[2] = 0x45; + gd54xx->vclk_d[2] = 0x30; + gd54xx->vclk_n[3] = 0x7e; + gd54xx->vclk_d[3] = 0x33; + } else { + gd54xx->vclk_n[0] = 0x66; + gd54xx->vclk_d[0] = 0x3b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + gd54xx->vclk_n[2] = 0x45; + gd54xx->vclk_d[2] = 0x2c; + gd54xx->vclk_n[3] = 0x7e; + gd54xx->vclk_d[3] = 0x33; + } +#else gd54xx->vclk_n[0] = 0x4a; gd54xx->vclk_d[0] = 0x2b; gd54xx->vclk_n[1] = 0x5b; gd54xx->vclk_d[1] = 0x2f; + gd54xx->vclk_n[2] = 0x45; + gd54xx->vclk_d[2] = 0x30; + gd54xx->vclk_n[3] = 0x7e; + gd54xx->vclk_d[3] = 0x33; +#endif - gd54xx->bank[1] = 0x8000; + svga->extra_banks[1] = 0x8000; if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); @@ -2282,10 +3067,28 @@ static void gd54xx->pci_regs[0x33] = 0x00; svga->crtc[0x27] = id; - + + svga->seqregs[6] = 0x0f; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) + gd54xx->unlocked = 1; + return gd54xx; } +#if defined(DEV_BRANCH) && defined(USE_CL5422) +static int +gd5420_available(void) +{ + return rom_present(BIOS_GD5420_PATH); +} + +static int +gd5422_available(void) +{ + return rom_present(BIOS_GD5422_PATH); +} +#endif + static int gd5426_available(void) { @@ -2362,7 +3165,7 @@ void gd54xx_close(void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; - + svga_close(&gd54xx->svga); free(gd54xx); @@ -2386,6 +3189,28 @@ gd54xx_force_redraw(void *p) gd54xx->svga.fullchange = changeframecount; } +#if defined(DEV_BRANCH) && defined(USE_CL5422) +static const device_config_t gd5422_config[] = +{ + { + "memory","Memory size",CONFIG_SELECTION,"",1, + { + { + "512 KB",0 + }, + { + "1 MB",1 + }, + { + "" + } + }, + }, + { + "","",-1 + } +}; +#endif static const device_config_t gd5428_config[] = { @@ -2468,6 +3293,58 @@ static const device_config_t gd5434_config[] = } }; +#if defined(DEV_BRANCH) && defined(USE_CL5422) +const device_t gd5402_isa_device = +{ + "Cirrus Logic GD-5402 (ACUMOS AVGA2)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5402, + gd54xx_init, gd54xx_close, + NULL, + gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + NULL, +}; + +const device_t gd5420_isa_device = +{ + "Cirrus Logic GD-5420", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5420, + gd54xx_init, gd54xx_close, + NULL, + gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5422_config, +}; + +const device_t gd5422_isa_device = { + "Cirrus Logic GD-5422", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5422, + gd54xx_init, gd54xx_close, + NULL, + gd5422_available, /* Common BIOS between 5422 and 5424 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5422_config, +}; + +const device_t gd5424_vlb_device = { + "Cirrus Logic GD-5424", + DEVICE_VLB, + CIRRUS_ID_CLGD5424, + gd54xx_init, gd54xx_close, + NULL, + gd5422_available, /* Common BIOS between 5422 and 5424 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5422_config, +}; +#endif + const device_t gd5426_vlb_device = { "Cirrus Logic CL-GD 5426 (VLB)", diff --git a/src/video/vid_cl54xx.h b/src/video/vid_cl54xx.h index 654a6326e..b777d28dc 100644 --- a/src/video/vid_cl54xx.h +++ b/src/video/vid_cl54xx.h @@ -1,6 +1,12 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ +#if defined(DEV_BRANCH) && defined(USE_CL5422) +extern const device_t gd5402_isa_device; +extern const device_t gd5420_isa_device; +extern const device_t gd5422_isa_device; +extern const device_t gd5424_vlb_device; +#endif extern const device_t gd5426_vlb_device; extern const device_t gd5428_isa_device; extern const device_t gd5428_vlb_device; diff --git a/src/video/vid_colorplus.c b/src/video/vid_colorplus.c index 95d82c70f..80393ecbb 100644 --- a/src/video/vid_colorplus.c +++ b/src/video/vid_colorplus.c @@ -8,7 +8,7 @@ * * Plantronics ColorPlus emulation. * - * Version: @(#)vid_colorplus.c 1.0.9 2018/04/26 + * Version: @(#)vid_colorplus.c 1.0.10 2018/09/19 * * Authors: Sarah Walker, * Miran Grca, @@ -25,10 +25,10 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../lpt.h" #include "../pit.h" #include "../mem.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_cga.h" @@ -52,6 +52,9 @@ #define COMPOSITE_NEW 1 +video_timings_t timing_colorplus = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + + void cga_recalctimings(cga_t *cga); void colorplus_out(uint16_t addr, uint8_t val, void *p) @@ -92,11 +95,12 @@ void colorplus_write(uint32_t addr, uint8_t val, void *p) colorplus->cga.vram[addr & 0x7fff] = val; if (colorplus->cga.snow_enabled) { - colorplus->cga.charbuffer[ ((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc] = val; - colorplus->cga.charbuffer[(((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + int offset = ((timer_get_remaining_u64(&colorplus->cga.timer) / CGACONST) * 2) & 0xfc; + colorplus->cga.charbuffer[offset] = colorplus->cga.vram[addr & 0x7fff]; + colorplus->cga.charbuffer[offset | 1] = colorplus->cga.vram[addr & 0x7fff]; } egawrites++; - cycles -= 4; + sub_cycles(4); } uint8_t colorplus_read(uint32_t addr, void *p) @@ -113,11 +117,12 @@ uint8_t colorplus_read(uint32_t addr, void *p) { addr &= 0x3FFF; } - cycles -= 4; + sub_cycles(4); if (colorplus->cga.snow_enabled) { - colorplus->cga.charbuffer[ ((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc] = colorplus->cga.vram[addr & 0x7fff]; - colorplus->cga.charbuffer[(((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc) | 1] = colorplus->cga.vram[addr & 0x7fff]; + int offset = ((timer_get_remaining_u64(&colorplus->cga.timer) / CGACONST) * 2) & 0xfc; + colorplus->cga.charbuffer[offset] = colorplus->cga.vram[addr & 0x7fff]; + colorplus->cga.charbuffer[offset | 1] = colorplus->cga.vram[addr & 0x7fff]; } egareads++; return colorplus->cga.vram[addr & 0x7fff]; @@ -155,7 +160,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; @@ -172,8 +177,9 @@ 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; + buffer32->line[colorplus->cga.displine][c] = + buffer32->line[colorplus->cga.displine][c + (colorplus->cga.crtc[1] << 4) + 8] = + (colorplus->cga.cgacol & 15) + 16; } if (colorplus->control & COLORPLUS_320x200_MODE) { @@ -186,9 +192,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)]; + buffer32->line[colorplus->cga.displine][(x << 4) + (c << 1) + 8] = + buffer32->line[colorplus->cga.displine][(x << 4) + (c << 1) + 1 + 8] = + cols16[(dat0 >> 14) | ((dat1 >> 14) << 2)]; dat0 <<= 2; dat1 <<= 2; } @@ -225,8 +231,8 @@ void colorplus_poll(void *p) colorplus->cga.ma++; for (c = 0; c < 16; c++) { - buffer->line[colorplus->cga.displine][(x << 4) + c + 8] = - cols[(dat0 >> 15) | ((dat1 >> 15) << 1)]; + buffer32->line[colorplus->cga.displine][(x << 4) + c + 8] = + cols[(dat0 >> 15) | ((dat1 >> 15) << 1)]; dat0 <<= 1; dat1 <<= 1; } @@ -236,18 +242,13 @@ 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]); + hline(buffer32, 0, colorplus->cga.displine, (colorplus->cga.crtc[1] << 4) + 16, cols[0]); } x = (colorplus->cga.crtc[1] << 4) + 16; if (colorplus->cga.composite) - { - for (c = 0; c < x; c++) - buffer32->line[colorplus->cga.displine][c] = buffer->line[colorplus->cga.displine][c] & 0xf; - Composite_Process(colorplus->cga.cgamode, 0, x >> 2, buffer32->line[colorplus->cga.displine]); - } colorplus->cga.sc = oldsc; if (colorplus->cga.vc == colorplus->cga.crtc[7] && !colorplus->cga.sc) @@ -258,7 +259,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) { @@ -392,6 +393,8 @@ void *colorplus_standalone_init(const device_t *info) colorplus_t *colorplus = malloc(sizeof(colorplus_t)); memset(colorplus, 0, sizeof(colorplus_t)); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_colorplus); + /* Copied from the CGA init. Ideally this would be done by * calling a helper function rather than duplicating code */ display_type = device_get_config_int("display_type"); @@ -401,8 +404,8 @@ void *colorplus_standalone_init(const device_t *info) colorplus->cga.vram = malloc(0x8000); - cga_comp_init(1); - timer_add(colorplus_poll, &colorplus->cga.vidtime, TIMER_ALWAYS_ENABLED, colorplus); + cga_comp_init(colorplus->cga.revision); + 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, MEM_MAPPING_EXTERNAL, colorplus); io_sethandler(0x03d0, 0x0010, colorplus_in, NULL, NULL, colorplus_out, NULL, NULL, colorplus); diff --git a/src/video/vid_compaq_cga.c b/src/video/vid_compaq_cga.c index c502aa6dd..f17c526a1 100644 --- a/src/video/vid_compaq_cga.c +++ b/src/video/vid_compaq_cga.c @@ -1,3 +1,23 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the Compaq CGA graphics cards. + * + * Version: @(#)vid_compaq_cga.c 1.0.0 2019/01/02 + * + * Authors: John Elliott, + * Sarah Walker, + * Miran Grca, + * + * Copyright 2016-2019 John Elliott. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ #include #include #include @@ -7,431 +27,453 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_cga.h" #include "vid_cga_comp.h" + #define CGA_RGB 0 #define CGA_COMPOSITE 1 + +static uint32_t vflags; +static uint8_t mdaattr[256][2][2]; + + typedef struct compaq_cga_t { - cga_t cga; - uint32_t flags; + cga_t cga; } compaq_cga_t; -static uint8_t mdaattr[256][2][2]; -void compaq_cga_recalctimings(compaq_cga_t *self) +#ifdef ENABLE_COMPAQ_CGA_LOG +int compaq_cga_do_log = ENABLE_COMPAQ_CGA_LOG; + + +static void +compaq_cga_log(const char *fmt, ...) { - 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 = (int)(_dispontime * (1 << TIMER_SHIFT)); - self->cga.dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + va_list ap; + + if (compaq_cga_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define compaq_cga_log(fmt, ...) +#endif + + +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) + +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 = 0; - int blink = 0; + 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, xs_temp, ys_temp; + int oldvc; + uint8_t chr, attr; + uint8_t border; + uint8_t cols[4]; + int oldsc; + int underline = 0; + int blink = 0; - /* If in graphics mode or character height is not 13, behave as CGA */ - if ((self->cga.cgamode & 0x12) || (self->cga.crtc[9] != 13)) - { - overscan_x = overscan_y = 16; - cga_poll(&self->cga); - return; - } else - overscan_x = overscan_y = 0; + /* If in graphics mode or character height is not 13, behave as CGA */ + if ((self->cga.cgamode & 0x12) || (self->cga.crtc[9] != 13)) { + overscan_x = overscan_y = 16; + cga_poll(&self->cga); + return; + } else + overscan_x = overscan_y = 0; -/* We are in Compaq 350-line CGA territory */ - if (!self->cga.linepos) - { - self->cga.vidtime += 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); + /* 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(); + compaq_cga_log("Firstline %i\n", firstline); + } + self->cga.lastline = self->cga.displine; - 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); - if (self->flags) { - underline = 0; - blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); - } - if (self->flags && (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) + 16; - cols[0] = ((attr >> 4) & 7) + 16; - if (self->flags) { - if (blink) - cols[1] = cols[0]; - } else { - if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) - cols[1] = cols[0]; - } - } - else - { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; - } - if (self->flags && 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); - if (self->flags) { - underline = 0; - blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); - } - if (self->flags && (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) + 16; - cols[0] = ((attr >> 4) & 7) + 16; - if (self->flags) { - if (blink) - cols[1] = cols[0]; - } else { - if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) - cols[1] = cols[0]; - } - } - else - { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; - } - self->cga.ma++; - if (self->flags && 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] ^ 15; - } - 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) + 16; - 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]); - } + cols[0] = (self->cga.cgacol & 15) + 16; - if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3) + 16; - else x = (self->cga.crtc[1] << 4) + 16; - - if (self->cga.composite) - { - for (c = 0; c < x; c++) - buffer32->line[self->cga.displine][c] = ((uint32_t *)buffer32->line[self->cga.displine])[c] & 0xf; - - if (self->flags) - Composite_Process(self->cga.cgamode & 0x7F, 0, x >> 2, buffer32->line[self->cga.displine]); + for (c = 0; c < 8; c++) { + buffer32->line[self->cga.displine][c] = cols[0]; + if (self->cga.cgamode & 1) + buffer32->line[self->cga.displine][c + (self->cga.crtc[1] << 3) + 8] = cols[0]; else - Composite_Process(self->cga.cgamode, 0, x >> 2, buffer32->line[self->cga.displine]); - } - else - { - for (c = 0; c < x; c++) - buffer->line[self->cga.displine][c] = ((uint32_t *)buffer32->line[self->cga.displine])[c]; - } + buffer32->line[self->cga.displine][c + (self->cga.crtc[1] << 4) + 8] = cols[0]; + } - 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 - { - self->cga.vidtime += 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.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); - if (self->cga.vc == self->cga.crtc[6]) - self->cga.cgadispon = 0; + if (vflags) { + underline = 0; + blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + } - 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 (vflags && (self->cga.cgamode & 0x80)) { + cols[0] = mdaattr[attr][blink][0]; + cols[1] = mdaattr[attr][blink][1]; - 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]) - { -// printf("Lastline %i Firstline %i %i\n",self->cga.lastline,self->cga.firstline,self->cga.lastline-self->cga.firstline); + if ((self->cga.sc == 12) && ((attr & 7) == 1)) + underline = 1; + } else if (self->cga.cgamode & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; - if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3); - else x = (self->cga.crtc[1] << 4); - self->cga.lastline++; - if (x != xsize || (self->cga.lastline - self->cga.firstline) != ysize) - { - xsize = x; - ysize = self->cga.lastline - self->cga.firstline; -// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,self->cga.crtc[1]); + if (vflags) { + if (blink) + cols[1] = cols[0]; + } else { + if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) + cols[1] = cols[0]; + } + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, ysize); - } - - if (self->cga.composite) - video_blit_memtoscreen(8, self->cga.firstline, 0, ysize, xsize, ysize); - else - video_blit_memtoscreen_8(8, self->cga.firstline, 0, ysize, xsize, ysize); - frames++; + if (vflags && underline) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c + 8] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + 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); - 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)]; - } - } + if (vflags) { + underline = 0; + blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + } -} + if (vflags && (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) + 16; + cols[0] = ((attr >> 4) & 7) + 16; -void *compaq_cga_init(const device_t *info) -{ - int display_type; - int c; - compaq_cga_t *self = malloc(sizeof(compaq_cga_t)); - memset(self, 0, sizeof(compaq_cga_t)); + if (vflags) { + if (blink) + cols[1] = cols[0]; + } else { + if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) + cols[1] = cols[0]; + } + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + self->cga.ma++; - display_type = device_get_config_int("display_type"); - self->cga.composite = (display_type != CGA_RGB); - self->cga.revision = device_get_config_int("composite_type"); - self->cga.snow_enabled = device_get_config_int("snow_enabled"); + if (vflags && underline) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4)+(c << 1) + 8] = + buffer32->line[self->cga.displine][(x << 4)+(c << 1) + 9] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4)+(c << 1) + 8] = + 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] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 8] = + 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) + 16; - self->cga.vram = malloc(0x4000); - - cga_comp_init(self->cga.revision); - timer_add(compaq_cga_poll, &self->cga.vidtime, TIMER_ALWAYS_ENABLED, self); - 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); - - if (info->local) { - for (c = 0; c < 256; c++) { - mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 16; - if (c & 8) mdaattr[c][0][1] = 15 + 16; - else mdaattr[c][0][1] = 7 + 16; - } - mdaattr[0x70][0][1] = 16; - mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 16 + 15; - mdaattr[0xF0][0][1] = 16; - mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 16 + 15; - mdaattr[0x78][0][1] = 16 + 7; - mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 16 + 15; - mdaattr[0xF8][0][1] = 16 + 7; - mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 16 + 15; - mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 16; - mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 16; - mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 16; - mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; + 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]); } - self->flags = info->local; + if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3) + 16; + else x = (self->cga.crtc[1] << 4) + 16; - overscan_x = overscan_y = 16; + if (self->cga.composite) { + if (self->cga.cgamode & 0x10) + border = 0x00; + else + border = self->cga.cgacol & 0x0f; - self->cga.rgb_type = device_get_config_int("rgb_type"); - cga_palette = (self->cga.rgb_type << 1); - cgapal_rebuild(); - - 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); + if (vflags) + Composite_Process(self->cga.cgamode & 0x7f, border, x >> 2, buffer32->line[self->cga.displine]); + else + Composite_Process(self->cga.cgamode, border, x >> 2, buffer32->line[self->cga.displine]); } - else - { - cga_recalctimings(&self->cga); - } + + 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]) { + compaq_cga_log("Lastline %i Firstline %i %i\n", self->cga.lastline, + self->cga.firstline ,self->cga.lastline - self->cga.firstline); + + if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3); + else x = (self->cga.crtc[1] << 4); + + self->cga.lastline++; + + xs_temp = x; + ys_temp = (self->cga.lastline - self->cga.firstline); + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xsize < 64) xs_temp = 656; + if (ysize < 32) ys_temp = 400; + if (!enable_overscan) + xsize -= 16; + + if ((self->cga.cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan) { + if (self->cga.composite) + video_blit_memtoscreen(0, self->cga.firstline - 8, 0, ysize + 16, xsize + 16, ysize + 16); + else + video_blit_memtoscreen_8(0, self->cga.firstline - 8, 0, ysize + 16, xsize + 16, ysize + 16); + } else { + if (self->cga.composite) + video_blit_memtoscreen(8, self->cga.firstline, 0, ysize, xsize, ysize); + else + video_blit_memtoscreen_8(8, self->cga.firstline, 0, ysize, xsize, ysize); + } + } + + frames++; + + video_res_x = xsize; + if (enable_overscan) + 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(const device_t *info) +{ + int display_type; + int c; + compaq_cga_t *self = malloc(sizeof(compaq_cga_t)); + memset(self, 0, sizeof(compaq_cga_t)); + + display_type = device_get_config_int("display_type"); + self->cga.composite = (display_type != CGA_RGB); + self->cga.revision = device_get_config_int("composite_type"); + self->cga.snow_enabled = device_get_config_int("snow_enabled"); + + self->cga.vram = malloc(0x4000); + + cga_comp_init(self->cga.revision); + 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 /*self->cga.vram*/, MEM_MAPPING_EXTERNAL, self); + io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, self); + + if (info->local) { + for (c = 0; c < 256; c++) { + mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 16; + if (c & 8) mdaattr[c][0][1] = 15 + 16; + else mdaattr[c][0][1] = 7 + 16; + } + + mdaattr[0x70][0][1] = 16; + mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 16 + 15; + mdaattr[0xF0][0][1] = 16; + mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 16 + 15; + mdaattr[0x78][0][1] = 16 + 7; + mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 16 + 15; + mdaattr[0xF8][0][1] = 16 + 7; + mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 16 + 15; + mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 16; + mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 16; + mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 16; + mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; + } + + vflags = info->local; + + overscan_x = overscan_y = 16; + + self->cga.rgb_type = device_get_config_int("rgb_type"); + cga_palette = (self->cga.rgb_type << 1); + cgapal_rebuild(); + + self->cga.crtc[9] = 13; + + 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 const device_config_t cga_config[]; const device_t compaq_cga_device = diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 426d23957..acda3edde 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -6,17 +6,16 @@ * * This file is part of the 86Box distribution. * - * Emulation of the EGA, Chips & Technologies SuperEGA, and - * AX JEGA graphics cards. + * Emulation of the EGA and Chips & Technologies SuperEGA + * graphics cards. * - * Version: @(#)vid_ega.c 1.0.17 2018/04/26 + * Version: @(#)vid_ega.c 1.0.23 2019/11/19 * * Authors: Sarah Walker, * Miran Grca, - * akm * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -26,1161 +25,1002 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_ega.h" #include "vid_ega_render.h" +void ega_doblit(int y1, int y2, int wx, int wy, ega_t *ega); + + #define BIOS_IBM_PATH L"roms/video/ega/ibm_6277356_ega_card_u44_27128.bin" #define BIOS_CPQ_PATH L"roms/video/ega/108281-001.bin" #define BIOS_SEGA_PATH L"roms/video/ega/lega.vbi" enum { - EGA_IBM = 0, - EGA_COMPAQ, - EGA_SUPEREGA + EGA_IBM = 0, + EGA_COMPAQ, + EGA_SUPEREGA }; -extern uint8_t edatlookup[4][4]; +static video_timings_t timing_ega = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; +static uint8_t ega_rotate[8][256]; +static uint32_t pallook16[256], pallook64[256]; +static int old_overscan_color = 0; -static uint8_t ega_rotate[8][256]; +extern uint8_t edatlookup[4][4]; -static uint32_t pallook16[256], pallook64[256]; +/* 3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour): + 7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines). */ +int egaswitchread, egaswitches=9; +int update_overscan = 0; -/*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/ -int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/ -static int old_overscan_color = 0; - -int update_overscan = 0; - -#ifdef JEGA -uint8_t jfont_sbcs_19[SBCS19_LEN]; /* 256 * 19( * 8) */ -uint8_t jfont_dbcs_16[DBCS16_LEN]; /* 65536 * 16 * 2 (* 8) */ - -typedef struct { - char id[ID_LEN]; - char name[NAME_LEN]; - unsigned char width; - unsigned char height; - unsigned char type; -} fontx_h; - -typedef struct { - uint16_t start; - uint16_t end; -} fontxTbl; - -static __inline int ega_jega_enabled(ega_t *ega) +void +ega_out(uint16_t addr, uint8_t val, void *p) { - if (!ega->is_jega) - { - return 0; - } + ega_t *ega = (ega_t *)p; + int c; + uint8_t o, old; - return !(ega->RMOD1 & 0x40); -} + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; -void ega_jega_write_font(ega_t *ega) -{ - unsigned int chr = ega->RDFFB; - unsigned int chr_2 = ega->RDFSB; - - ega->RSTAT &= ~0x02; - - /* Check if the character code is in the Wide character set of Shift-JIS */ - if (((chr >= 0x40) && (chr <= 0x7e)) || ((chr >= 0x80) && (chr <= 0xfc))) - { - if (ega->font_index >= 32) - { - ega->font_index = 0; + switch (addr) { + case 0x3c0: case 0x3c1: + if (!ega->attrff) { + ega->attraddr = val & 31; + if ((val & 0x20) != ega->attr_palette_enable) { + fullchange = 3; + ega->attr_palette_enable = val & 0x20; + ega_recalctimings(ega); + } + } else { + o = ega->attrregs[ega->attraddr & 31]; + ega->attrregs[ega->attraddr & 31] = val; + if (ega->attraddr < 16) + fullchange = changeframecount; + if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); + else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); + } + } + /* Recalculate timings on change of attribute register 0x11 + (overscan border color) too. */ + if (ega->attraddr == 0x10) { + if (o != val) + ega_recalctimings(ega); + } else if (ega->attraddr == 0x11) { + ega->overscan_color = ega->vres ? pallook16[val & 0x0f] : pallook64[val & 0x3f]; + if (o != val) + ega_recalctimings(ega); + } else if (ega->attraddr == 0x12) + ega->plane_mask = val & 0xf; } - chr <<= 8; - /* Fix vertical character position */ - chr |= chr_2; - if (ega->font_index < 16) - { - jfont_dbcs_16[(chr * 32) + (ega->font_index * 2)] = ega->RDFAP; /* 16x16 font */ + ega->attrff ^= 1; + break; + case 0x3c2: + o = ega->miscout; + egaswitchread = (val & 0xc) >> 2; + ega->vres = !(val & 0x80); + ega->pallook = ega->vres ? pallook16 : pallook64; + ega->vidclock = val & 4; + ega->miscout = val; + ega->overscan_color = ega->vres ? pallook16[ega->attrregs[0x11] & 0x0f] : pallook64[ega->attrregs[0x11] & 0x3f]; + if ((o ^ val) & 0x80) + ega_recalctimings(ega); + break; + case 0x3c4: + ega->seqaddr = val; + break; + case 0x3c5: + o = ega->seqregs[ega->seqaddr & 0xf]; + ega->seqregs[ega->seqaddr & 0xf] = val; + if (o != val && (ega->seqaddr & 0xf) == 1) + ega_recalctimings(ega); + switch (ega->seqaddr & 0xf) { + case 1: + if (ega->scrblank && !(val & 0x20)) + fullchange = 3; + ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); + break; + case 2: + ega->writemask = val & 0xf; + break; + case 3: + ega->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + ega->charseta = ((val & 3) * 0x10000) + 2; + break; + case 4: + ega->chain2_write = !(val & 4); + break; } - else - { - jfont_dbcs_16[(chr * 32) + ((ega->font_index - 16) * 2) + 1] = ega->RDFAP; /* 16x16 font */ + break; + case 0x3ce: + ega->gdcaddr = val; + break; + case 0x3cf: + ega->gdcreg[ega->gdcaddr & 15] = val; + switch (ega->gdcaddr & 15) { + case 2: + ega->colourcompare = val; + break; + case 4: + ega->readplane = val & 3; + break; + case 5: + ega->writemode = val & 3; + ega->readmode = val & 8; + ega->chain2_read = val & 0x10; + break; + case 6: + switch (val & 0xc) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000); + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000); + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000); + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000); + break; + } + break; + case 7: + ega->colournocare = val; + break; } - } - else - { - if (ega->font_index >= 19) - { - ega->font_index = 0; + break; + case 0x3d0: case 0x3d4: + ega->crtcreg = val & 31; + return; + case 0x3d1: case 0x3d5: + if ((ega->crtcreg < 7) && (ega->crtc[0x11] & 0x80)) + return; + if ((ega->crtcreg == 7) && (ega->crtc[0x11] & 0x80)) + val = (ega->crtc[7] & ~0x10) | (val & 0x10); + old = ega->crtc[ega->crtcreg]; + ega->crtc[ega->crtcreg] = val; + if (old != val) { + if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) { + fullchange = changeframecount; + ega_recalctimings(ega); + } } - jfont_sbcs_19[(chr * 19) + ega->font_index] = ega->RDFAP; /* 8x19 font */ - } - ega->font_index++; - ega->RSTAT |= 0x02; -} - -void ega_jega_read_font(ega_t *ega) -{ - unsigned int chr = ega->RDFFB; - unsigned int chr_2 = ega->RDFSB; - - ega->RSTAT &= ~0x02; - - /* Check if the character code is in the Wide character set of Shift-JIS */ - if (((chr >= 0x40) && (chr <= 0x7e)) || ((chr >= 0x80) && (chr <= 0xfc))) - { - if (ega->font_index >= 32) - { - ega->font_index = 0; - } - chr <<= 8; - /* Fix vertical character position */ - chr |= chr_2; - if (ega->font_index < 16) - { - ega->RDFAP = jfont_dbcs_16[(chr * 32) + (ega->font_index * 2)]; /* 16x16 font */ - } - else - { - ega->RDFAP = jfont_dbcs_16[(chr * 32) + ((ega->font_index - 16) * 2) + 1]; /* 16x16 font */ - } - } - else - { - if (ega->font_index >= 19) - { - ega->font_index = 0; - } - ega->RDFAP = jfont_sbcs_19[(chr * 19) + ega->font_index]; /* 8x19 font */ - } - ega->font_index++; - ega->RSTAT |= 0x02; -} -#endif - - -void ega_out(uint16_t addr, uint8_t val, void *p) -{ - ega_t *ega = (ega_t *)p; - int c; - uint8_t o, old; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) - addr ^= 0x60; - - switch (addr) - { - case 0x3c0: - case 0x3c1: - if (!ega->attrff) - ega->attraddr = val & 31; - else - { - ega->attrregs[ega->attraddr & 31] = val; - if (ega->attraddr < 16) - fullchange = changeframecount; - if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) - { - for (c = 0; c < 16; c++) - { - if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); - else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); - } - } - } - ega->attrff ^= 1; - break; - case 0x3c2: - egaswitchread = val & 0xc; - ega->vres = !(val & 0x80); - ega->pallook = ega->vres ? pallook16 : pallook64; - ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ - ega->miscout=val; - break; - case 0x3c4: - ega->seqaddr = val; - break; - case 0x3c5: - o = ega->seqregs[ega->seqaddr & 0xf]; - ega->seqregs[ega->seqaddr & 0xf] = val; - if (o != val && (ega->seqaddr & 0xf) == 1) - ega_recalctimings(ega); - switch (ega->seqaddr & 0xf) - { - case 1: - if (ega->scrblank && !(val & 0x20)) - fullchange = 3; - ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); - break; - case 2: - ega->writemask = val & 0xf; - break; - case 3: - ega->charsetb = (((val >> 2) & 3) * 0x10000) + 2; - ega->charseta = ((val & 3) * 0x10000) + 2; - break; - case 4: - ega->chain2_write = !(val & 4); - break; - } - break; - case 0x3ce: - ega->gdcaddr = val; - break; - case 0x3cf: - ega->gdcreg[ega->gdcaddr & 15] = val; - switch (ega->gdcaddr & 15) - { - case 2: - ega->colourcompare = val; - break; - case 4: - ega->readplane = val & 3; - break; - case 5: - ega->writemode = val & 3; - ega->readmode = val & 8; - ega->chain2_read = val & 0x10; - break; - case 6: - switch (val & 0xc) - { - case 0x0: /*128k at A0000*/ - mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000); - break; - case 0x4: /*64k at A0000*/ - mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000); - break; - case 0x8: /*32k at B0000*/ - mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000); - break; - case 0xC: /*32k at B8000*/ - mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000); - break; - } - break; - case 7: - ega->colournocare = val; - break; - } - break; - case 0x3d0: - case 0x3d4: - ega->crtcreg = val & 31; - return; - case 0x3d1: - case 0x3d5: - if (ega->crtcreg <= 7 && ega->crtc[0x11] & 0x80) return; - old = ega->crtc[ega->crtcreg]; - ega->crtc[ega->crtcreg] = val; - if (old != val) - { - if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) - { - fullchange = changeframecount; - ega_recalctimings(ega); - } - } - break; - } + break; + } } uint8_t ega_in(uint16_t addr, void *p) { - ega_t *ega = (ega_t *)p; + ega_t *ega = (ega_t *)p; + uint8_t ret = 0xff; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) - addr ^= 0x60; + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; - switch (addr) - { - case 0x3c0: - return ega->attraddr; - case 0x3c1: - return ega->attrregs[ega->attraddr]; - case 0x3c2: - switch (egaswitchread) - { - case 0xc: return (egaswitches & 1) ? 0x10 : 0; - case 0x8: return (egaswitches & 2) ? 0x10 : 0; - case 0x4: return (egaswitches & 4) ? 0x10 : 0; - case 0x0: return (egaswitches & 8) ? 0x10 : 0; - } - break; - case 0x3c4: - return ega->seqaddr; - case 0x3c5: - return ega->seqregs[ega->seqaddr & 0xf]; - case 0x3c8: - return 2; - case 0x3cc: - return ega->miscout; - case 0x3ce: - return ega->gdcaddr; - case 0x3cf: - return ega->gdcreg[ega->gdcaddr & 0xf]; - case 0x3d0: - case 0x3d4: - return ega->crtcreg; - case 0x3d1: - case 0x3d5: - return ega->crtc[ega->crtcreg]; - case 0x3da: - ega->attrff = 0; - ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/ - return ega->stat; - } - return 0xff; + switch (addr) { + case 0x3c0: + ret = ega->attraddr | ega->attr_palette_enable; + break; + case 0x3c1: + ret = ega->attrregs[ega->attraddr]; + break; + case 0x3c2: + ret = (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00; + break; + case 0x3c4: + ret = ega->seqaddr; + break; + case 0x3c5: + ret = ega->seqregs[ega->seqaddr & 0xf]; + break; + case 0x3c8: + ret = 2; + break; + case 0x3cc: + ret = ega->miscout; + break; + case 0x3ce: + ret = ega->gdcaddr; + break; + case 0x3cf: + ret = ega->gdcreg[ega->gdcaddr & 0xf]; + break; + case 0x3d0: case 0x3d4: + ret = ega->crtcreg; + break; + case 0x3d1: + case 0x3d5: + ret = ega->crtc[ega->crtcreg]; + break; + case 0x3da: + ega->attrff = 0; + ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/ + ret = ega->stat; + break; + } + + return ret; } -void ega_recalctimings(ega_t *ega) +void +ega_recalctimings(ega_t *ega) { - double _dispontime, _dispofftime, disptime; - double crtcconst; + double _dispontime, _dispofftime, disptime; + double crtcconst; - ega->vtotal = ega->crtc[6]; - ega->dispend = ega->crtc[0x12]; - ega->vsyncstart = ega->crtc[0x10]; - ega->split = ega->crtc[0x18]; + ega->vtotal = ega->crtc[6]; + ega->dispend = ega->crtc[0x12]; + ega->vsyncstart = ega->crtc[0x10]; + ega->split = ega->crtc[0x18]; - if (ega->crtc[7] & 1) ega->vtotal |= 0x100; - if (ega->crtc[7] & 32) ega->vtotal |= 0x200; - ega->vtotal += 2; + if (ega->crtc[7] & 1) ega->vtotal |= 0x100; + if (ega->crtc[7] & 32) ega->vtotal |= 0x200; + ega->vtotal += 2; - if (ega->crtc[7] & 2) ega->dispend |= 0x100; - if (ega->crtc[7] & 64) ega->dispend |= 0x200; - ega->dispend++; + if (ega->crtc[7] & 2) ega->dispend |= 0x100; + if (ega->crtc[7] & 64) ega->dispend |= 0x200; + ega->dispend++; - if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; - if (ega->crtc[7] & 128) ega->vsyncstart |= 0x200; - ega->vsyncstart++; + if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; + if (ega->crtc[7] & 128) ega->vsyncstart |= 0x200; + ega->vsyncstart++; - if (ega->crtc[7] & 0x10) ega->split |= 0x100; - if (ega->crtc[9] & 0x40) ega->split |= 0x200; - ega->split++; + if (ega->crtc[7] & 0x10) ega->split |= 0x100; + if (ega->crtc[9] & 0x40) ega->split |= 0x200; + ega->split++; - ega->hdisp = ega->crtc[1]; - ega->hdisp++; + ega->hdisp = ega->crtc[1]; + ega->hdisp++; - ega->rowoffset = ega->crtc[0x13]; - ega->rowcount = ega->crtc[9] & 0x1f; + ega->rowoffset = ega->crtc[0x13]; + + ega->linedbl = ega->crtc[9] & 0x80; + ega->rowcount = ega->crtc[9] & 0x1f; + + if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); + else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0)); + + ega->interlace = 0; + + ega->ma_latch = (ega->crtc[0xc] << 8) | ega->crtc[0xd]; + + ega->render = ega_render_blank; + if (!ega->scrblank && ega->attr_palette_enable) { + if (!(ega->gdcreg[6] & 1)) { + if (ega->seqregs[1] & 8) { + ega->render = ega_render_text_40; + ega->hdisp *= (ega->seqregs[1] & 1) ? 16 : 18; + } else { + ega->render = ega_render_text_80; + ega->hdisp *= (ega->seqregs[1] & 1) ? 8 : 9; + } + ega->hdisp_old = ega->hdisp; + } else { + ega->hdisp *= (ega->seqregs[1] & 8) ? 16 : 8; + ega->hdisp_old = ega->hdisp; + + switch (ega->gdcreg[5] & 0x20) { + case 0x00: + if (ega->seqregs[1] & 8) + ega->render = ega_render_4bpp_lowres; + else + ega->render = ega_render_4bpp_highres; + break; + case 0x20: + if (ega->seqregs[1] & 8) + ega->render = ega_render_2bpp_lowres; + else + ega->render = ega_render_2bpp_highres; + break; + } + } + } + + if (enable_overscan) { overscan_y = (ega->rowcount + 1) << 1; - if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); - else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0)); - - if (ega->seqregs[1] & 8) - { - disptime = (double) ((ega->crtc[0] + 2) << 1); - _dispontime = (double) ((ega->crtc[1] + 1) << 1); - - overscan_y <<= 1; - } else { - disptime = (double) (ega->crtc[0] + 2); - _dispontime = (double) (ega->crtc[1] + 1); - } if (overscan_y < 16) - { overscan_y = 16; + } + + overscan_x = (ega->seqregs[1] & 1) ? 16 : 18; + + if (ega->seqregs[1] & 8) + overscan_x <<= 1; + + ega->y_add = (overscan_y >> 1) - (ega->crtc[8] & 0x1f); + ega->x_add = (overscan_x >> 1); + + if (ega->seqregs[1] & 8) { + disptime = (double) ((ega->crtc[0] + 2) << 1); + _dispontime = (double) ((ega->crtc[1] + 1) << 1); + } else { + disptime = (double) (ega->crtc[0] + 2); + _dispontime = (double) (ega->crtc[1] + 1); + } + _dispofftime = disptime - _dispontime; + _dispontime = _dispontime * crtcconst; + _dispofftime = _dispofftime * crtcconst; + + ega->dispontime = (uint64_t)(_dispontime); + ega->dispofftime = (uint64_t)(_dispofftime); +} + + +void +ega_poll(void *p) +{ + ega_t *ega = (ega_t *)p; + int x, old_ma; + int wx = 640, wy = 350; + uint32_t blink_delay; + + if (!ega->linepos) { + timer_advance_u64(&ega->timer, ega->dispofftime); + ega->stat |= 1; + ega->linepos = 1; + + if (ega->dispon) { + ega->hdisp_on = 1; + + ega->ma &= ega->vrammask; + if (ega->firstline == 2000) { + ega->firstline = ega->displine; + video_wait_for_buffer(); + } + + if (ega->vres) { + old_ma = ega->ma; + + ega->displine <<= 1; + ega->y_add <<= 1; + + ega->render(ega); + + ega->x_add = (overscan_x >> 1); + ega_render_overscan_left(ega); + ega_render_overscan_right(ega); + ega->x_add = (overscan_x >> 1) - ega->scrollcache; + + ega->displine++; + + ega->ma = old_ma; + ega_render_overscan_left(ega); + ega->render(ega); + ega_render_overscan_right(ega); + + ega->y_add >>= 1; + ega->displine >>= 1; + } else { + ega_render_overscan_left(ega); + ega->render(ega); + ega_render_overscan_right(ega); + } + + if (ega->lastline < ega->displine) + ega->lastline = ega->displine; } - _dispofftime = disptime - _dispontime; - _dispontime = _dispontime * crtcconst; - _dispofftime = _dispofftime * crtcconst; - ega->dispontime = (int64_t)(_dispontime * (1LL << TIMER_SHIFT)); - ega->dispofftime = (int64_t)(_dispofftime * (1LL << TIMER_SHIFT)); + ega->displine++; + if (ega->interlace) + ega->displine++; + if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) + ega->stat &= ~8; + ega->vslines++; + if (ega->displine > 500) + ega->displine = 0; + } else { + timer_advance_u64(&ega->timer, ega->dispontime); + + if (ega->dispon) + ega->stat &= ~1; + ega->hdisp_on = 0; + + ega->linepos = 0; + if ((ega->sc == (ega->crtc[11] & 31)) || (ega->sc == ega->rowcount)) + ega->con = 0; + if (ega->dispon) { + if (ega->linedbl && !ega->linecountff) { + ega->linecountff = 1; + ega->ma = ega->maback; + } if (ega->sc == (ega->crtc[9] & 31)) { + ega->linecountff = 0; + ega->sc = 0; + + ega->maback += (ega->rowoffset << 3); + if (ega->interlace) + ega->maback += (ega->rowoffset << 3); + ega->maback &= ega->vrammask; + ega->ma = ega->maback; + } else { + ega->linecountff = 0; + ega->sc++; + ega->sc &= 31; + ega->ma = ega->maback; + } + } + ega->vc++; + ega->vc &= 1023; + if (ega->vc == ega->split) { + ega->ma = ega->maback = 0; + ega->sc = 0; + if (ega->attrregs[0x10] & 0x20) { + ega->scrollcache = 0; + ega->x_add = (overscan_x >> 1); + } + } + if (ega->vc == ega->dispend) { + ega->dispon = 0; + blink_delay = (ega->crtc[11] & 0x60) >> 5; + if (ega->crtc[10] & 0x20) + ega->cursoron = 0; + else if (blink_delay == 2) + ega->cursoron = ((ega->blink % 96) >= 48); + else + ega->cursoron = ega->blink & (16 + (16 * blink_delay)); + + if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) + fullchange = 2; + ega->blink = (ega->blink + 1) & 0x7f; + + if (fullchange) + fullchange--; + } + if (ega->vc == ega->vsyncstart) { + ega->dispon = 0; + ega->stat |= 8; + x = ega->hdisp; + + if (ega->interlace && !ega->oddeven) + ega->lastline++; + if (ega->interlace && ega->oddeven) + ega->firstline--; + + wx = x; + + if (ega->vres) { + wy = (ega->lastline - ega->firstline) << 1; + ega_doblit(ega->firstline_draw << 1, (ega->lastline_draw + 1) << 1, wx, wy, ega); + } else { + wy = ega->lastline - ega->firstline; + ega_doblit(ega->firstline_draw, ega->lastline_draw + 1, wx, wy, ega); + } + + frames++; + + ega->firstline = 2000; + ega->lastline = 0; + + ega->firstline_draw = 2000; + ega->lastline_draw = 0; + + ega->oddeven ^= 1; + + changeframecount = ega->interlace ? 3 : 2; + ega->vslines = 0; + + if (ega->interlace && ega->oddeven) + ega->ma = ega->maback = ega->ma_latch + (ega->rowoffset << 1); + else + ega->ma = ega->maback = ega->ma_latch; + ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; + + ega->ma <<= 2; + ega->maback <<= 2; + ega->ca <<= 2; + } + if (ega->vc == ega->vtotal) { + ega->vc = 0; + ega->sc = 0; + ega->dispon = 1; + ega->displine = (ega->interlace && ega->oddeven) ? 1 : 0; + + ega->scrollcache = (ega->attrregs[0x13] & 0x0f); + if (!(ega->gdcreg[6] & 1) && !(ega->attrregs[0x10] & 1)) { /*Text mode*/ + if (ega->seqregs[1] & 1) + ega->scrollcache &= 0x07; + else { + ega->scrollcache++; + if (ega->scrollcache > 8) + ega->scrollcache = 0; + } + } else + ega->scrollcache &= 0x07; + + if (ega->seqregs[1] & 8) + ega->scrollcache <<= 1; + + ega->x_add = (overscan_x >> 1) - ega->scrollcache; + + ega->linecountff = 0; + } + if (ega->sc == (ega->crtc[10] & 31)) + ega->con = 1; + } } -void ega_poll(void *p) +void +ega_doblit(int y1, int y2, int wx, int wy, ega_t *ega) { - ega_t *ega = (ega_t *)p; - int x; - int drawcursor = 0; - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - int y_add_ex = enable_overscan ? overscan_y : 0; - int x_add_ex = enable_overscan ? 16 : 0; - uint32_t *q, i, j; - int wx = 640, wy = 350; + int y_add = (enable_overscan) ? overscan_y : 0; + int x_add = (enable_overscan) ? overscan_x : 0; + int y_start = (enable_overscan) ? 0 : (overscan_y >> 1); + int x_start = (enable_overscan) ? 0 : (overscan_x >> 1); + int bottom = (overscan_y >> 1) + (ega->crtc[8] & 0x1f); + uint32_t *p; + int i, j; + int xs_temp, ys_temp; - if (!ega->linepos) - { - ega->vidtime += ega->dispofftime; + if (ega->vres) { + y_add <<= 1; + y_start <<= 1; + bottom <<= 1; + } - ega->stat |= 1; - ega->linepos = 1; + if ((wx <= 0) || (wy <= 0)) { + video_blit_memtoscreen(x_start, y_start, 0, 0, 0, 0); + return; + } - if (ega->dispon) - { - if (ega->firstline == 2000) - { - ega->firstline = ega->displine; - video_wait_for_buffer(); - } + if (y1 > y2) { + video_blit_memtoscreen(x_start, y_start, 0, 0, xsize + x_add, ysize + y_add); + return; + } - if (ega->scrblank) - { - ega_render_blank(ega); - } - else if (!(ega->gdcreg[6] & 1)) - { - if (fullchange) - { -#ifdef JEGA - if (ega_jega_enabled(ega)) - { - ega_render_text_jega(ega, drawcursor); - } - else - { - ega_render_text_standard(ega, drawcursor); - } -#else - ega_render_text_standard(ega, drawcursor); -#endif - } - } - else - { - switch (ega->gdcreg[5] & 0x20) - { - case 0x00: - if (ega->seqregs[1] & 8) - { - ega_render_4bpp_lowres(ega); - } - else - { - ega_render_4bpp_highres(ega); - } - break; - case 0x20: - ega_render_2bpp(ega); - break; - } - } - if (ega->lastline < ega->displine) - ega->lastline = ega->displine; - } + if (ega->vres) + ega->y_add <<= 1; - ega->displine++; - if (ega->interlace) - ega->displine++; - if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) - ega->stat &= ~8; - ega->vslines++; - if (ega->displine > 500) - ega->displine = 0; - } - else - { - ega->vidtime += ega->dispontime; - if (ega->dispon) - ega->stat &= ~1; - ega->linepos = 0; - if (ega->sc == (ega->crtc[11] & 31)) - ega->con = 0; - if (ega->dispon) - { - if (ega->sc == (ega->crtc[9] & 31)) - { - ega->sc = 0; - if (ega->sc == (ega->crtc[11] & 31)) - ega->con = 0; + xs_temp = wx; + ys_temp = wy + 1; + if (ega->vres) + ys_temp++; + if (xs_temp < 64) + xs_temp = 640; + if (ys_temp < 32) + ys_temp = 200; - ega->maback += (ega->rowoffset << 3); - if (ega->interlace) - ega->maback += (ega->rowoffset << 3); - ega->maback &= ega->vrammask; - ega->ma = ega->maback; - } - else - { - ega->sc++; - ega->sc &= 31; - ega->ma = ega->maback; - } - } - ega->vc++; - ega->vc &= 1023; - if (ega->vc == ega->split) - { - ega->ma = ega->maback = 0; - if (ega->attrregs[0x10] & 0x20) - ega->scrollcache = 0; - } - if (ega->vc == ega->dispend) - { - ega->dispon=0; - if (ega->crtc[10] & 0x20) ega->cursoron = 0; - else ega->cursoron = ega->blink & 16; - if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) - fullchange = 2; - ega->blink++; + if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { + /* Screen res has changed.. fix up, and let them know. */ + xsize = xs_temp; + ysize = ys_temp; - if (fullchange) - fullchange--; - } - if (ega->vc == ega->vsyncstart) - { - ega->dispon = 0; - ega->stat |= 8; - if (ega->seqregs[1] & 8) x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9) * 2; - else x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9); + if ((xsize > 1984) || (ysize > 2016)) { + /* 2048x2048 is the biggest safe render texture, to account for overscan, + we suppress overscan starting from x 1984 and y 2016. */ + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } else + suppress_overscan = 0; - if (ega->interlace && !ega->oddeven) ega->lastline++; - if (ega->interlace && ega->oddeven) ega->firstline--; + set_screen_size(xsize + x_add, ysize + y_add); - if ((x != xsize || (ega->lastline - ega->firstline + 1) != ysize) || update_overscan || video_force_resize_get()) - { - xsize = x; - ysize = ega->lastline - ega->firstline + 1; - if (xsize < 64) xsize = 640; - if (ysize < 32) ysize = 200; - y_add = enable_overscan ? 14 : 0; - x_add = enable_overscan ? 8 : 0; - y_add_ex = enable_overscan ? 28 : 0; - x_add_ex = enable_overscan ? 16 : 0; + if (video_force_resize_get()) + video_force_resize_set(0); + } - if ((xsize > 2032) || ((ysize + y_add_ex) > 2048)) - { - x_add = x_add_ex = 0; - y_add = y_add_ex = 0; - suppress_overscan = 1; - } - else - { - suppress_overscan = 0; - } + if ((wx >= 160) && ((wy + 1) >= 120)) { + /* Draw (overscan_size - scroll size) lines of overscan on top and bottom. */ + for (i = 0; i < ega->y_add; i++) { + p = &buffer32->line[i & 0x7ff][0]; - if (ega->vres) - set_screen_size(xsize + x_add_ex, (ysize << 1) + y_add_ex); - else - set_screen_size(xsize + x_add_ex, ysize + y_add_ex); + for (j = 0; j < (xsize + x_add); j++) + p[j] = ega->overscan_color; + } - if (video_force_resize_get()) - video_force_resize_set(0); - } + for (i = 0; i < bottom; i++) { + p = &buffer32->line[(ysize + ega->y_add + i) & 0x7ff][0]; - if (enable_overscan) - { - if ((x >= 160) && ((ega->lastline - ega->firstline) >= 120)) - { - /* Draw (overscan_size - scroll size) lines of overscan on top. */ - for (i = 0; i < (y_add - (ega->crtc[8] & 0x1f)); i++) - { - q = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + for (j = 0; j < (xsize + x_add); j++) + p[j] = ega->overscan_color; + } + } - for (j = 0; j < (xsize + x_add_ex); j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; - } - } + video_blit_memtoscreen(x_start, y_start, y1, y2 + y_add, xsize + x_add, ysize + y_add); - /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ - for (i = 0; i < (y_add + (ega->crtc[8] & 0x1f)); i++) - { - q = &((uint32_t *)buffer32->line[(ysize + y_add + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; - - for (j = 0; j < (xsize + x_add_ex); j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; - } - } - - for (i = (y_add - (ega->crtc[8] & 0x1f)); i < (ysize + y_add - (ega->crtc[8] & 0x1f)); i ++) - { - q = &((uint32_t *)buffer32->line[(i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; - - for (j = 0; j < x_add; j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; - q[xsize + x_add + j] = ega->pallook[ega->attrregs[0x11]]; - } - } - } - } - else - { - if (ega->crtc[8] & 0x1f) - { - /* Draw (scroll size) lines of overscan on the bottom. */ - for (i = 0; i < (ega->crtc[8] & 0x1f); i++) - { - q = &((uint32_t *)buffer32->line[(ysize + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; - - for (j = 0; j < xsize; j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; - } - } - } - } - - video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline + 1 + y_add_ex, xsize + x_add_ex, ega->lastline - ega->firstline + 1 + y_add_ex); - - frames++; - - ega->video_res_x = wx; - ega->video_res_y = wy + 1; - if (!(ega->gdcreg[6] & 1)) /*Text mode*/ - { - ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9; - ega->video_res_y /= (ega->crtc[9] & 31) + 1; - ega->video_bpp = 0; - } - else - { - if (ega->crtc[9] & 0x80) - ega->video_res_y /= 2; - if (!(ega->crtc[0x17] & 1)) - ega->video_res_y *= 2; - ega->video_res_y /= (ega->crtc[9] & 31) + 1; - if (ega->seqregs[1] & 8) - ega->video_res_x /= 2; - ega->video_bpp = (ega->gdcreg[5] & 0x20) ? 2 : 4; - } - - ega->firstline = 2000; - ega->lastline = 0; - - ega->maback = ega->ma = (ega->crtc[0xc] << 8)| ega->crtc[0xd]; - ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; - ega->ma <<= 2; - ega->maback <<= 2; - ega->ca <<= 2; - changeframecount = 2; - ega->vslines = 0; - } - if (ega->vc == ega->vtotal) - { - ega->vc = 0; - ega->sc = 0; - ega->dispon = 1; - ega->displine = (ega->interlace && ega->oddeven) ? 1 : 0; - ega->scrollcache = ega->attrregs[0x13] & 7; - } - if (ega->sc == (ega->crtc[10] & 31)) - ega->con = 1; - } + if (ega->vres) + ega->y_add >>= 1; } -void ega_write(uint32_t addr, uint8_t val, void *p) +void +ega_write(uint32_t addr, uint8_t val, void *p) { - ega_t *ega = (ega_t *)p; - uint8_t vala, valb, valc, vald; - int writemask2 = ega->writemask; + ega_t *ega = (ega_t *)p; + uint8_t vala, valb, valc, vald; + int writemask2 = ega->writemask; - egawrites++; - cycles -= video_timing_write_b; - - if (addr >= 0xB0000) addr &= 0x7fff; - else addr &= 0xffff; + egawrites++; + sub_cycles(video_timing_write_b); - if (ega->chain2_write) - { - writemask2 &= ~0xa; - if (addr & 1) - writemask2 <<= 1; - addr &= ~1; - if (addr & 0x4000) - addr |= 1; - addr &= ~0x4000; - } + if (addr >= 0xB0000) addr &= 0x7fff; + else addr &= 0xffff; - addr <<= 2; + if (ega->chain2_write) { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + if (addr & 0x4000) + addr |= 1; + addr &= ~0x4000; + } - if (addr >= ega->vram_limit) + addr <<= 2; + + if (addr >= ega->vram_limit) return; - if (!(ega->gdcreg[6] & 1)) - fullchange = 2; + if (!(ega->gdcreg[6] & 1)) + fullchange = 2; - switch (ega->writemode) - { - case 1: - if (writemask2 & 1) ega->vram[addr] = ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld; - break; - case 0: - if (ega->gdcreg[3] & 7) - val = ega_rotate[ega->gdcreg[3] & 7][val]; - - if (ega->gdcreg[8] == 0xff && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) - { - if (writemask2 & 1) ega->vram[addr] = val; - if (writemask2 & 2) ega->vram[addr | 0x1] = val; - if (writemask2 & 4) ega->vram[addr | 0x2] = val; - if (writemask2 & 8) ega->vram[addr | 0x3] = val; - } - else - { - if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0; - else vala = val; - if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0; - else valb = val; - if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0; - else valc = val; - if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0; - else vald = val; - switch (ega->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; - break; - } - } - break; - case 2: - if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) - { - if (writemask2 & 1) ega->vram[addr] = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); - if (writemask2 & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); - if (writemask2 & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); - if (writemask2 & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); - } - else - { - vala = ((val & 1) ? 0xff : 0); - valb = ((val & 2) ? 0xff : 0); - valc = ((val & 4) ? 0xff : 0); - vald = ((val & 8) ? 0xff : 0); - switch (ega->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; - if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; - if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; - if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; - break; - } - } - break; - } -} + switch (ega->writemode) { + case 1: + if (writemask2 & 1) ega->vram[addr] = ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld; + break; + case 0: + if (ega->gdcreg[3] & 7) + val = ega_rotate[ega->gdcreg[3] & 7][val]; - -uint8_t ega_read(uint32_t addr, void *p) -{ - ega_t *ega = (ega_t *)p; - uint8_t temp, temp2, temp3, temp4; - int readplane = ega->readplane; - - egareads++; - cycles -= video_timing_read_b; - if (addr >= 0xb0000) addr &= 0x7fff; - else addr &= 0xffff; - - if (ega->chain2_read) - { - 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->la; - temp ^= (ega->colourcompare & 1) ? 0xff : 0; - temp &= (ega->colournocare & 1) ? 0xff : 0; - temp2 = ega->lb; - temp2 ^= (ega->colourcompare & 2) ? 0xff : 0; - temp2 &= (ega->colournocare & 2) ? 0xff : 0; - temp3 = ega->lc; - temp3 ^= (ega->colourcompare & 4) ? 0xff : 0; - 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, int monitor_type, int is_mono) -{ - int c, d, e; - - ega->vram = malloc(0x40000); - ega->vrammask = 0x3ffff; - - for (c = 0; c < 256; c++) - { - e = c; - for (d = 0; d < 8; d++) - { - ega_rotate[d][c] = e; - e = (e >> 1) | ((e & 1) ? 0x80 : 0); - } - } - - for (c = 0; c < 4; c++) - { - for (d = 0; d < 4; d++) - { - edatlookup[c][d] = 0; - if (c & 1) edatlookup[c][d] |= 1; - if (d & 1) edatlookup[c][d] |= 2; - if (c & 2) edatlookup[c][d] |= 0x10; - if (d & 2) edatlookup[c][d] |= 0x20; - } - } - - if (is_mono) - { - 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; - - old_overscan_color = 0; - - ega->miscout |= 0x22; - ega->oddeven_page = 0; - - ega->seqregs[4] |= 2; - ega->extvram = 1; - - update_overscan = 0; - - ega->crtc[0] = 63; - ega->crtc[6] = 255; - -#ifdef JEGA - ega->is_jega = 0; -#endif -} - - -static void *ega_standalone_init(const device_t *info) -{ - ega_t *ega = malloc(sizeof(ega_t)); - int monitor_type; - - memset(ega, 0, sizeof(ega_t)); - - overscan_x = 16; - overscan_y = 28; - - switch(info->local) { - case EGA_IBM: - default: - rom_init(&ega->bios_rom, BIOS_IBM_PATH, - 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - break; - case EGA_COMPAQ: - rom_init(&ega->bios_rom, BIOS_CPQ_PATH, - 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - break; - case EGA_SUPEREGA: - rom_init(&ega->bios_rom, BIOS_SEGA_PATH, - 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - break; - } - - if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) - { - int c; - - for (c = 0; c < 0x2000; c++) - { - uint8_t temp = ega->bios_rom.rom[c]; - ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; - ega->bios_rom.rom[0x3fff - c] = temp; - } - } - - monitor_type = device_get_config_int("monitor_type"); - ega_init(ega, monitor_type, (monitor_type & 0xf) == 10); - - 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); - timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); - io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - return ega; -} - -#ifdef JEGA -uint16_t chrtosht(FILE *fp) -{ - uint16_t i, j; - i = (uint8_t) getc(fp); - j = (uint8_t) getc(fp) << 8; - return (i | j); -} - -unsigned int getfontx2header(FILE *fp, fontx_h *header) -{ - fread(header->id, ID_LEN, 1, fp); - if (strncmp(header->id, "FONTX2", ID_LEN) != 0) - { - return 1; - } - fread(header->name, NAME_LEN, 1, fp); - header->width = (uint8_t)getc(fp); - header->height = (uint8_t)getc(fp); - header->type = (uint8_t)getc(fp); - return 0; -} - -void readfontxtbl(fontxTbl *table, unsigned int size, FILE *fp) -{ - while (size > 0) - { - table->start = chrtosht(fp); - table->end = chrtosht(fp); - ++table; - --size; - } -} - -static void LoadFontxFile(wchar_t *fname) -{ - fontx_h head; - fontxTbl *table; - unsigned int code; - uint8_t size; - unsigned int i; - - if (!fname) return; - if(*fname=='\0') return; - FILE * mfile=romfopen(fname,L"rb"); - if (!mfile) - { - pclog("MSG: Can't open FONTX2 file: %s\n",fname); - return; - } - if (getfontx2header(mfile, &head) != 0) - { - fclose(mfile); - pclog("MSG: FONTX2 header is incorrect\n"); - return; - } - /* switch whether the font is DBCS or not */ - if (head.type == DBCS) - { - if (head.width == 16 && head.height == 16) - { - size = getc(mfile); - table = (fontxTbl *)calloc(size, sizeof(fontxTbl)); - readfontxtbl(table, size, mfile); - for (i = 0; i < size; i++) - { - for (code = table[i].start; code <= table[i].end; code++) - { - fread(&jfont_dbcs_16[(code * 32)], sizeof(uint8_t), 32, mfile); - } + if ((ega->gdcreg[8] == 0xff) && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) { + if (writemask2 & 1) ega->vram[addr] = val; + if (writemask2 & 2) ega->vram[addr | 0x1] = val; + if (writemask2 & 4) ega->vram[addr | 0x2] = val; + if (writemask2 & 8) ega->vram[addr | 0x3] = val; + } else { + if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + switch (ega->gdcreg[3] & 0x18) { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; } } - else - { - fclose(mfile); - pclog("MSG: FONTX2 DBCS font size is not correct\n"); - return; + break; + case 2: + if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) { + if (writemask2 & 1) ega->vram[addr] = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + } else { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (ega->gdcreg[3] & 0x18) { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } + } + break; + } +} + + +uint8_t +ega_read(uint32_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t temp, temp2, temp3, temp4; + int readplane = ega->readplane; + + egareads++; + sub_cycles(video_timing_read_b); + if (addr >= 0xb0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_read) { + 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->la; + temp ^= (ega->colourcompare & 1) ? 0xff : 0; + temp &= (ega->colournocare & 1) ? 0xff : 0; + temp2 = ega->lb; + temp2 ^= (ega->colourcompare & 2) ? 0xff : 0; + temp2 &= (ega->colournocare & 2) ? 0xff : 0; + temp3 = ega->lc; + temp3 ^= (ega->colourcompare & 4) ? 0xff : 0; + 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, int monitor_type, int is_mono) +{ + int c, d, e; + + ega->vram = malloc(0x40000); + ega->vrammask = 0x3ffff; + + for (c = 0; c < 256; c++) { + e = c; + for (d = 0; d < 8; d++) { + ega_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + + for (c = 0; c < 4; c++) { + for (d = 0; d < 4; d++) { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; + } + } + + if (is_mono) { + for (c = 0; c < 256; c++) { + if (((c >> 3) & 3) == 0) + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + else switch (monitor_type >> 4) { + case DISPLAY_GREEN: + switch ((c >> 3) & 3) { + case 1: + pallook64[c] = pallook16[c] = makecol32(0x08, 0xc7, 0x2c); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0x04, 0x8a, 0x20); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0x34, 0xff, 0x5d); + break; + } + break; + case DISPLAY_AMBER: + switch ((c >> 3) & 3) { + case 1: + pallook64[c] = pallook16[c] = makecol32(0xef, 0x79, 0x00); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0xb2, 0x4d, 0x00); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0xff, 0xe3, 0x34); + break; + } + break; + case DISPLAY_WHITE: default: + switch ((c >> 3) & 3) { + case 1: + pallook64[c] = pallook16[c] = makecol32(0xaf, 0xb3, 0xb0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0x7a, 0x81, 0x83); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0xff, 0xfd, 0xed); + break; + } + break; } } - else - { - if (head.width == 8 && head.height == 19) - { - fread(jfont_sbcs_19, sizeof(uint8_t), SBCS19_LEN, mfile); - } - else - { - fclose(mfile); - pclog("MSG: FONTX2 SBCS font size is not correct\n"); - return; - } + } 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); } - fclose(mfile); + } + + ega->pallook = pallook16; + + egaswitches = monitor_type & 0xf; + + ega->vram_limit = 256 * 1024; + ega->vrammask = ega->vram_limit - 1; + + old_overscan_color = 0; + + ega->miscout |= 0x22; + ega->oddeven_page = 0; + + ega->seqregs[4] |= 2; + ega->extvram = 1; + + update_overscan = 0; + + ega->crtc[0] = 63; + ega->crtc[6] = 255; + + timer_add(&ega->timer, ega_poll, ega, 1); } -void *jega_standalone_init(const device_t *info) + +static void * +ega_standalone_init(const device_t *info) { - ega_t *ega = (ega_t *)ega_standalone_init(info); + ega_t *ega = malloc(sizeof(ega_t)); + int monitor_type, c; - LoadFontxFile(L"roms/video/ega/JPNHN19X.FNT"); - LoadFontxFile(L"roms/video/ega/JPNZN16X.FNT"); + memset(ega, 0, sizeof(ega_t)); - ega->is_jega = 1; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); - return ega; + overscan_x = 16; + overscan_y = 28; + ega->x_add = 8; + ega->y_add = 14; + + switch(info->local) { + case EGA_IBM: + default: + rom_init(&ega->bios_rom, BIOS_IBM_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case EGA_COMPAQ: + rom_init(&ega->bios_rom, BIOS_CPQ_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case EGA_SUPEREGA: + rom_init(&ega->bios_rom, BIOS_SEGA_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + } + + if ((ega->bios_rom.rom[0x3ffe] == 0xaa) && (ega->bios_rom.rom[0x3fff] == 0x55)) { + for (c = 0; c < 0x2000; c++) { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + monitor_type = device_get_config_int("monitor_type"); + ega_init(ega, monitor_type, (monitor_type & 0x0F) == 0x0B); + + 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; } -#endif -static int ega_standalone_available(void) +static int +ega_standalone_available(void) { - return rom_present(BIOS_IBM_PATH); + return rom_present(BIOS_IBM_PATH); } -static int cpqega_standalone_available(void) +static int +cpqega_standalone_available(void) { - return rom_present(BIOS_CPQ_PATH); + return rom_present(BIOS_CPQ_PATH); } -static int sega_standalone_available(void) +static int +sega_standalone_available(void) { - return rom_present(BIOS_SEGA_PATH); + return rom_present(BIOS_SEGA_PATH); } -static void ega_close(void *p) +static void +ega_close(void *p) { - ega_t *ega = (ega_t *)p; + ega_t *ega = (ega_t *)p; - free(ega->vram); - free(ega); + free(ega->vram); + free(ega); } -static void ega_speed_changed(void *p) +static void +ega_speed_changed(void *p) { - ega_t *ega = (ega_t *)p; - - ega_recalctimings(ega); + ega_t *ega = (ega_t *)p; + + ega_recalctimings(ega); } +/* SW1 SW2 SW3 SW4 + OFF OFF ON OFF Monochrome (5151) 1011 0x0B + ON OFF OFF ON Color 40x25 (5153) 0110 0x06 + OFF OFF OFF ON Color 80x25 (5153) 0111 0x07 + ON ON ON OFF Enhanced Color - Normal Mode (5154) 1000 0x08 + OFF ON ON OFF Enhanced Color - Enhanced Mode (5154) 1001 0x09 + + 0 = Switch closed (ON); + 1 = Switch open (OFF). */ static const device_config_t ega_config[] = { { @@ -1207,28 +1047,32 @@ static const device_config_t ega_config[] = .selection = { { - .description = "EGA Colour, 40x25", - .value = 6 + .description = "Monochrome (5151/MDA) (white)", + .value = 0x0B | (DISPLAY_WHITE << 4) }, { - .description = "EGA Colour, 80x25", - .value = 7 + .description = "Monochrome (5151/MDA) (green)", + .value = 0x0B | (DISPLAY_GREEN << 4) }, { - .description = "EGA Colour, ECD", - .value = 9 + .description = "Monochrome (5151/MDA) (amber)", + .value = 0x0B | (DISPLAY_AMBER << 4) }, { - .description = "EGA Monochrome (white)", - .value = 10 | (DISPLAY_WHITE << 4) + .description = "Color 40x25 (5153/CGA)", + .value = 0x06 }, { - .description = "EGA Monochrome (green)", - .value = 10 | (DISPLAY_GREEN << 4) + .description = "Color 80x25 (5153/CGA)", + .value = 0x07 }, { - .description = "EGA Monochrome (amber)", - .value = 10 | (DISPLAY_AMBER << 4) + .description = "Enhanced Color - Normal Mode (5154/ECD)", + .value = 0x08 + }, + { + .description = "Enhanced Color - Enhanced Mode (5154/ECD)", + .value = 0x09 }, { .description = "" @@ -1277,17 +1121,3 @@ const device_t sega_device = NULL, ega_config }; - -#ifdef JEGA -const device_t jega_device = -{ - "AX JEGA", - DEVICE_ISA, - EGA_SUPEREGA, - ega_standalone_init, ega_close, NULL, - sega_standalone_available, - ega_speed_changed, - NULL, - ega_config -}; -#endif diff --git a/src/video/vid_ega.h b/src/video/vid_ega.h index e5590d052..f64da0a01 100644 --- a/src/video/vid_ega.h +++ b/src/video/vid_ega.h @@ -6,110 +6,64 @@ * * This file is part of the 86Box distribution. * - * Emulation of the EGA, Chips & Technologies SuperEGA, and - * AX JEGA graphics cards. + * Emulation of the EGA and Chips & Technologies SuperEGA + * graphics cards. * - * Version: @(#)vid_ega.h 1.0.7 2018/03/18 + * Version: @(#)vid_ega.h 1.0.8 2019/10/03 * * Authors: Sarah Walker, * Miran Grca, - * akm, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 akm. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #ifndef VIDEO_EGA_H # define VIDEO_EGA_H -#ifdef JEGA -# define SBCS 0 -# define DBCS 1 -# define ID_LEN 6 -# define NAME_LEN 8 -# define SBCS19_LEN 256 * 19 -# define DBCS16_LEN 65536 * 32 -#endif - - #if defined(EMU_MEM_H) && defined(EMU_ROM_H) typedef struct ega_t { mem_mapping_t mapping; rom_t bios_rom; - uint8_t crtcreg; + uint8_t crtcreg, gdcaddr, attraddr, attrff, + attr_palette_enable, seqaddr, miscout, + writemask, la, lb, lc, ld, + stat, colourcompare, colournocare, scrblank, + plane_mask, pad, pad0, pad1; uint8_t crtc[32]; uint8_t gdcreg[16]; - int gdcaddr; uint8_t attrregs[32]; - int attraddr, attrff; - int attr_palette_enable; uint8_t seqregs[64]; - int seqaddr; - - uint8_t miscout; - int vidclock; - - uint8_t la, lb, lc, ld; - - uint8_t stat; - - int fast; - uint8_t colourcompare, colournocare; - int readmode, writemode, readplane; - int chain4, chain2_read, chain2_write; - int oddeven_page, oddeven_chain; - int extvram; - uint8_t writemask; - uint32_t charseta, charsetb; - uint8_t egapal[16]; + + uint8_t *vram; + + int vidclock, fast, extvram, vres, + readmode, writemode, readplane, vrammask, + chain4, chain2_read, chain2_write, con, + oddeven_page, oddeven_chain, vc, sc, + dispon, hdisp_on, cursoron, blink, + linepos, vslines, linecountff, oddeven, + lowres, interlace, linedbl, lindebl, rowcount, + vtotal, dispend, vsyncstart, split, + hdisp, hdisp_old, htotal, hdisp_time, rowoffset, + vblankstart, scrollcache, firstline, lastline, + firstline_draw, lastline_draw, x_add, y_add, + displine, video_res_x, video_res_y, video_bpp; + + uint32_t charseta, charsetb, ma_latch, ma, + maback, ca, vram_limit, overscan_color; + uint32_t *pallook; - int vtotal, dispend, vsyncstart, split, vblankstart; - int hdisp, htotal, hdisp_time, rowoffset; - int lowres, interlace; - int linedbl, rowcount; + uint64_t dispontime, dispofftime; + pc_timer_t timer; + double clock; - uint32_t ma_latch; - - int vres; - - int64_t dispontime, dispofftime; - int64_t vidtime; - - uint8_t scrblank; - - int dispon; - int hdisp_on; - uint32_t ma, maback, ca; - int vc; - int sc; - int linepos, vslines, linecountff, oddeven; - int con, cursoron, blink; - int scrollcache; - - int firstline, lastline; - int firstline_draw, lastline_draw; - int displine; - - uint8_t *vram; - int vrammask; - - uint32_t vram_limit; - - int video_res_x, video_res_y, video_bpp; - -#ifdef JEGA - uint8_t RMOD1, RMOD2, RDAGS, RDFFB, RDFSB, RDFAP, RPESL, RPULP, RPSSC, RPSSU, RPSSL; - uint8_t RPPAJ; - uint8_t RCMOD, RCCLH, RCCLL, RCCSL, RCCEL, RCSKW, ROMSL, RSTAT; - int is_jega, font_index; - int chr_left, chr_wide; -#endif + void (*render)(struct ega_t *svga); } ega_t; #endif @@ -119,10 +73,6 @@ extern const device_t ega_device; extern const device_t cpqega_device; extern const device_t sega_device; #endif -#ifdef JEGA -extern uint8_t jfont_sbcs_19[SBCS19_LEN]; /* 256 * 19( * 8) */ -extern uint8_t jfont_dbcs_16[DBCS16_LEN]; /* 65536 * 16 * 2 (* 8) */ -#endif extern int update_overscan; diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index 06b697cc8..cf5ec7d50 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -8,13 +8,13 @@ * * EGA renderers. * - * Version: @(#)vid_ega_render.c 1.0.5 2018/01/24 + * Version: @(#)vid_ega_render.c 1.0.7 2019/11/19 * * Author: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -22,6 +22,7 @@ #include #include "../86box.h" #include "../device.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "video.h" @@ -29,522 +30,454 @@ #include "vid_ega_render.h" -int ega_display_line(ega_t *ega) +int +ega_display_line(ega_t *ega) { - int y_add = (enable_overscan) ? (overscan_y >> 1) : 0; - unsigned int dl = ega->displine; - if (ega->crtc[9] & 0x1f) - { - dl -= (ega->crtc[8] & 0x1f); + int y_add = (enable_overscan) ? (overscan_y >> 1) : 0; + unsigned int dl = ega->displine; + + if (ega->crtc[9] & 0x1f) + dl -= (ega->crtc[8] & 0x1f); + + dl += y_add; + dl &= 0x7ff; + return dl; +} + + +void +ega_render_blank(ega_t *ega) +{ + int x, xx; + + if ((ega->displine + ega->y_add) < 0) + return; + + for (x = 0; x < (ega->hdisp + ega->scrollcache); x++) { + switch (ega->seqregs[1] & 9) { + case 0: + for (xx = 0; xx < 9; xx++) buffer32->line[ega->displine + ega->y_add][ega->x_add + (x * 9) + xx] = 0; + break; + case 1: + for (xx = 0; xx < 8; xx++) buffer32->line[ega->displine + ega->y_add][ega->x_add + (x * 8) + xx] = 0; + break; + case 8: + for (xx = 0; xx < 18; xx++) buffer32->line[ega->displine + ega->y_add][ega->x_add + (x * 18) + xx] = 0; + break; + case 9: + for (xx = 0; xx < 16; xx++) buffer32->line[ega->displine + ega->y_add][ega->x_add + (x * 16) + xx] = 0; + break; } - dl += y_add; - dl &= 0x7ff; - return dl; + } } -void ega_render_blank(ega_t *ega) + +void +ega_render_overscan_left(ega_t *ega) { - int x_add = (enable_overscan) ? 8 : 0; - int dl = ega_display_line(ega); - int x, xx; + int i; - for (x = 0; x < ega->hdisp; x++) - { - switch (ega->seqregs[1] & 9) - { - case 0: - for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[dl])[(x * 9) + xx + 32 + x_add] = 0; - break; - case 1: - for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[dl])[(x * 8) + xx + 32 + x_add] = 0; - break; - case 8: - for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[dl])[(x * 18) + xx + 32 + x_add] = 0; - break; - case 9: - for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[dl])[(x * 16) + xx + 32 + x_add] = 0; - break; - } - } + if (ega->scrblank || (ega->hdisp == 0)) + return; + + for (i = 0; i < ega->x_add; i++) + buffer32->line[ega->displine + ega->y_add][i] = ega->overscan_color; } -void ega_render_text_standard(ega_t *ega, int drawcursor) + +void +ega_render_overscan_right(ega_t *ega) { - int x, xx; - int x_add = (enable_overscan) ? 8 : 0; - int dl = ega_display_line(ega); - - 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); + int i, right; - 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; - } - } + if (ega->scrblank || (ega->hdisp == 0)) + return; - 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[dl])[((x << 4) + 32 + (xx << 1) + x_add) & 2047] = - ((uint32_t *)buffer32->line[dl])[((x << 4) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + (xx << 1) + x_add) & 2047] = - ((uint32_t *)buffer32->line[dl])[((x * 18) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 16 + x_add) & 2047] = - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 17 + x_add) & 2047] = bg; - else - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 16 + x_add) & 2047] = - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 17 + x_add) & 2047] = (dat & 1) ? fg : bg; - } - } - else - { - if (ega->seqregs[1] & 1) - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[dl])[((x << 3) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) - ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + 8 + x_add) & 2047] = bg; - else - ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + 8 + x_add) & 2047] = (dat & 1) ? fg : bg; - } - } - ega->ma += 4; - ega->ma &= ega->vrammask; - } + right = (overscan_x >> 1) + ega->scrollcache; + for (i = 0; i < right; i++) + buffer32->line[ega->displine + ega->y_add][ega->x_add + ega->hdisp + i] = ega->overscan_color; } -#ifdef JEGA -static __inline int is_kanji1(uint8_t chr) -{ - return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); -} -static __inline int is_kanji2(uint8_t chr) -{ - return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); -} - -void ega_jega_render_blit_text(ega_t *ega, int x, int dl, int start, int width, uint16_t dat, int cw, uint32_t fg, uint32_t bg) -{ - int x_add = (enable_overscan) ? 8 : 0; - - int xx = 0; - int xxx = 0; - - if (ega->seqregs[1] & 8) - { - for (xx = start; xx < (start + width); xx++) - for (xxx = 0; xxx < cw; xxx++) - ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = - ((uint32_t *)buffer32->line[dl])[(((x * width) + 33 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = start; xx < (start + width); xx++) - ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + xxx + (xx * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; - } -} - -void ega_render_text_jega(ega_t *ega, int drawcursor) +void +ega_render_text_40(ega_t *ega) { - int dl = ega_display_line(ega); - uint8_t chr, attr; - uint16_t dat = 0, dat2; - int x; - uint32_t fg = 0, bg = 0; + uint32_t *p; + int x, xx; + int drawcursor, xinc; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; - /* Temporary for DBCS. */ - unsigned int chr_left = 0; - unsigned int bsattr = 0; - int chr_wide = 0; - uint32_t bg_ex = 0; - uint32_t fg_ex = 0; + if ((ega->displine + ega->y_add) < 0) + return; - int blocks = ega->hdisp; - int fline; + if (ega->firstline_draw == 2000) + ega->firstline_draw = ega->displine; + ega->lastline_draw = ega->displine; - unsigned int pad_y, exattr; + if (fullchange) { + p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; + xinc = (ega->seqregs[1] & 1) ? 16 : 18; - 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]; + for (x = 0; x < (ega->hdisp + ega->scrollcache); x += xinc) { + 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 (chr_wide == 0) - { - if (ega->RMOD2 & 0x80) - { - fg_ex = ega->pallook[ega->egapal[attr & 15]]; + if (attr & 8) charaddr = ega->charsetb + (chr * 128); + else charaddr = ega->charseta + (chr * 128); - if (attr & 0x80 && ega->attrregs[0x10] & 8) - { - bg_ex = ega->pallook[ega->egapal[(attr >> 4) & 7]]; - } - else - { - bg_ex = ega->pallook[ega->egapal[attr >> 4]]; - } - } - else - { - if (attr & 0x40) - { - /* Reversed in JEGA mode */ - bg_ex = ega->pallook[ega->egapal[attr & 15]]; - fg_ex = ega->pallook[0]; - } - else - { - /* Reversed in JEGA mode */ - fg_ex = ega->pallook[ega->egapal[attr & 15]]; - bg_ex = ega->pallook[0]; - } - } + 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 (drawcursor) - { - bg = fg_ex; - fg = bg_ex; - } - else - { - fg = fg_ex; - bg = bg_ex; - } - - if (attr & 0x80 && ega->attrregs[0x10] & 8) - { - if (ega->blink & 16) - fg = bg; - } - - /* Stay drawing if the char code is DBCS and not at last column. */ - if (is_kanji1(dat) && (blocks > 1)) - { - /* Set the present char/attr code to the next loop. */ - chr_left = chr; - chr_wide = 1; - } - else - { - /* The char code is ANK (8 dots width). */ - dat = jfont_sbcs_19[chr*19+(ega->sc)]; /* w8xh19 font */ - ega_jega_render_blit_text(ega, x, dl, 0, 8, dat, 1, fg, bg); - if (bsattr & 0x20) - { - /* Vertical line. */ - dat = 0x18; - ega_jega_render_blit_text(ega, x, fline, 0, 8, dat, 1, fg, bg); - } - if (ega->sc == 18 && bsattr & 0x10) - { - /* Underline. */ - dat = 0xff; - ega_jega_render_blit_text(ega, x, fline, 0, 8, dat, 1, fg, bg); - } - chr_wide = 0; - blocks--; - } + if (attr & 0x80 && ega->attrregs[0x10] & 8) { + bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + if (ega->blink & 16) + fg = bg; } - else - { - /* The char code may be in DBCS. */ - pad_y = ega->RPSSC; - exattr = 0; - - /* Note: The second column should be applied its basic attribute. */ - if (ega->RMOD2 & 0x40) - { - /* If JEGA Extended Attribute is enabled. */ - exattr = attr; - if ((exattr & 0x30) == 0x30) pad_y = ega->RPSSL; /* Set top padding of lower 2x character. */ - else if (exattr & 0x30) pad_y = ega->RPSSU; /* Set top padding of upper 2x character. */ - } - - if (ega->sc >= pad_y && ega->sc < 16 + pad_y) - { - /* Check the char code is in Wide charset of Shift-JIS. */ - if (is_kanji2(chr)) - { - fline = ega->sc - pad_y; - chr_left <<= 8; - /* Fix vertical position. */ - chr |= chr_left; - /* Horizontal wide font (Extended Attribute). */ - if (exattr & 0x20) - { - if (exattr & 0x10) fline = (fline >> 1) + 8; - else fline = fline >> 1; - } - /* Vertical wide font (Extended Attribute). */ - if (exattr & 0x40) - { - dat = jfont_dbcs_16[chr * 32 + fline * 2]; - if (!(exattr & 0x08)) - dat = jfont_dbcs_16[chr * 32 + fline * 2 + 1]; - /* Draw 8 dots. */ - ega_jega_render_blit_text(ega, x, dl, 0, 8, dat, 2, fg, bg); - } - else - { - /* Get the font pattern. */ - dat = jfont_dbcs_16[chr * 32 + fline * 2]; - dat <<= 8; - dat |= jfont_dbcs_16[chr * 32 + fline * 2 + 1]; - /* Bold (Extended Attribute). */ - if (exattr &= 0x80) - { - dat2 = dat; - dat2 >>= 1; - dat |= dat2; - /* Original JEGA colours the last row with the next column's attribute. */ - } - /* Draw 16 dots */ - ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); - } - } - else - { - /* Ignore wide char mode, put blank. */ - dat = 0; - ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); - } - } - else if (ega->sc == (17 + pad_y) && (bsattr & 0x10)) - { - /* Underline. */ - dat = 0xffff; - ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); - } - else - { - /* Draw blank */ - dat = 0; - ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); - } - - if (bsattr & 0x20) - { - /* Vertical line draw at last. */ - dat = 0x0180; - ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); - } - - chr_wide = 0; - blocks -= 2; /* Move by 2 columns. */ - } - - ega->ma += 4; - ega->ma &= ega->vrammask; } + + dat = ega->vram[charaddr + (ega->sc << 2)]; + if (ega->seqregs[1] & 1) { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + } else { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + p[16] = p[17] = bg; + else + p[16] = p[17] = (dat & 1) ? fg : bg; + } + ega->ma += 4; + p += xinc; } -} -#endif - -void ega_render_2bpp(ega_t *ega) -{ - int x; - int dl = ega_display_line(ega); - 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[dl])[(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[dl])[(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[dl])[(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[dl])[(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[dl])[(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[dl])[(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[dl])[(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[dl])[(x << 4) + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 1 + offset] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; - } + ega->ma &= ega->vrammask; + } } -void ega_render_4bpp_lowres(ega_t *ega) + +void +ega_render_text_80(ega_t *ega) { - int x_add = (enable_overscan) ? 8 : 0; - int dl = ega_display_line(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); + uint32_t *p; + int x, xx; + int drawcursor, xinc; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; - 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; + if ((ega->displine + ega->y_add) < 0) + return; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 4) + 14 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + if (ega->firstline_draw == 2000) + ega->firstline_draw = ega->displine; + ega->lastline_draw = ega->displine; + + if (fullchange) { + p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; + xinc = (ega->seqregs[1] & 1) ? 8 : 9; + + for (x = 0; x < (ega->hdisp + ega->scrollcache); x += xinc) { + 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] & 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 || !(ega->attrregs[0x10] & 4)) + p[8] = bg; + else + p[8] = (dat & 1) ? fg : bg; + } + ega->ma += 4; + p += xinc; } + ega->ma &= ega->vrammask; + } } -void ega_render_4bpp_highres(ega_t *ega) + +void +ega_render_2bpp_lowres(ega_t *ega) { - int x_add = (enable_overscan) ? 8 : 0; - int dl = ega_display_line(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; + int x; + uint8_t dat[2]; + uint32_t addr, *p; - 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->displine + ega->y_add) < 0) + return; - 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; + p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 3) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 3) + 6 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 3) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 3) + 4 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 3) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 3) + 2 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 3) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 3) + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + if (ega->firstline_draw == 2000) + ega->firstline_draw = ega->displine; + ega->lastline_draw = ega->displine; + + for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 16) { + 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); + + dat[0] = ega->vram[addr]; + dat[1] = ega->vram[addr | 0x1]; + if (ega->seqregs[1] & 4) + ega->ma += 2; + else + ega->ma += 4; + + ega->ma &= ega->vrammask; + + p[0] = p[1] = ega->pallook[ega->egapal[(dat[0] >> 6) & 3]]; + p[2] = p[3] = ega->pallook[ega->egapal[(dat[0] >> 4) & 3]]; + p[4] = p[5] = ega->pallook[ega->egapal[(dat[0] >> 2) & 3]]; + p[6] = p[7] = ega->pallook[ega->egapal[dat[0] & 3]]; + p[8] = p[9] = ega->pallook[ega->egapal[(dat[1] >> 6) & 3]]; + p[10] = p[11] = ega->pallook[ega->egapal[(dat[1] >> 4) & 3]]; + p[12] = p[13] = ega->pallook[ega->egapal[(dat[1] >> 2) & 3]]; + p[14] = p[15] = ega->pallook[ega->egapal[dat[1] & 3]]; + + p += 16; + } +} + + +void +ega_render_2bpp_highres(ega_t *ega) +{ + int x; + uint8_t dat[2]; + uint32_t addr, *p; + + if ((ega->displine + ega->y_add) < 0) + return; + + p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; + + if (ega->firstline_draw == 2000) + ega->firstline_draw = ega->displine; + ega->lastline_draw = ega->displine; + + for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 8) { + 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); + + dat[0] = ega->vram[addr]; + dat[1] = ega->vram[addr | 0x1]; + if (ega->seqregs[1] & 4) + ega->ma += 2; + else + ega->ma += 4; + + ega->ma &= ega->vrammask; + + p[0] = ega->pallook[ega->egapal[(dat[0] >> 6) & 3]]; + p[1] = ega->pallook[ega->egapal[(dat[0] >> 4) & 3]]; + p[2] = ega->pallook[ega->egapal[(dat[0] >> 2) & 3]]; + p[3] = ega->pallook[ega->egapal[dat[0] & 3]]; + p[4] = ega->pallook[ega->egapal[(dat[1] >> 6) & 3]]; + p[5] = ega->pallook[ega->egapal[(dat[1] >> 4) & 3]]; + p[6] = ega->pallook[ega->egapal[(dat[1] >> 2) & 3]]; + p[7] = ega->pallook[ega->egapal[dat[1] & 3]]; + + p += 8; + } +} + + +void +ega_render_4bpp_lowres(ega_t *ega) +{ + int x, oddeven; + uint8_t dat, edat[4]; + uint32_t addr, *p; + + if ((ega->displine + ega->y_add) < 0) + return; + + p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; + + if (ega->firstline_draw == 2000) + ega->firstline_draw = ega->displine; + ega->lastline_draw = ega->displine; + + for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 16) { + addr = ega->ma; + 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] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = p[1] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[2] = p[3] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[6] = p[7] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[10] = p[11] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[14] = p[15] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + + p += 16; + } +} + + +void +ega_render_4bpp_highres(ega_t *ega) +{ + int x, oddeven; + uint8_t dat, edat[4]; + uint32_t addr, *p; + + if ((ega->displine + ega->y_add) < 0) + return; + + p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; + + if (ega->firstline_draw == 2000) + ega->firstline_draw = ega->displine; + ega->lastline_draw = ega->displine; + + for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 8) { + addr = ega->ma; + 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 { + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&ega->vram[addr]); + ega->ma += 4; + } + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[1] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[3] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[5] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = ega->pallook[ega->egapal[(dat >> 4) & ega->plane_mask]]; + p[7] = ega->pallook[ega->egapal[dat & ega->plane_mask]]; + + p += 8; + } } diff --git a/src/video/vid_ega_render.h b/src/video/vid_ega_render.h index 57cb8313b..a905fc5dd 100644 --- a/src/video/vid_ega_render.h +++ b/src/video/vid_ega_render.h @@ -8,12 +8,12 @@ * * EGA renderers. * - * Version: @(#)vid_ega_render.h 1.0.2 2018/01/24 + * Version: @(#)vid_ega_render.h 1.0.3 2019/10/03 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ extern int firstline_draw, lastline_draw; @@ -28,12 +28,15 @@ extern int scrollcache; extern uint8_t edatlookup[4][4]; void ega_render_blank(ega_t *ega); -void ega_render_text_standard(ega_t *ega, int drawcursor); -#ifdef JEGA -void ega_render_text_jega(ega_t *ega, int drawcursor); -#endif -void ega_render_2bpp(ega_t *ega); +void ega_render_overscan_left(ega_t *ega); +void ega_render_overscan_right(ega_t *ega); + +void ega_render_text_40(ega_t *ega); +void ega_render_text_80(ega_t *ega); + +void ega_render_2bpp_lowres(ega_t *ega); +void ega_render_2bpp_highres(ega_t *ega); void ega_render_4bpp_lowres(ega_t *ega); void ega_render_4bpp_highres(ega_t *ega); diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 329b854dd..3702098df 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -8,13 +8,34 @@ * * Emulation of the Tseng Labs ET4000. * - * Version: @(#)vid_et4000.c 1.0.7 2018/07/19 + * Version: @(#)vid_et4000.c 1.0.20 2018/10/04 * - * Authors: Sarah Walker, + * Authors: Fred N. van Kempen, * Miran Grca, + * GreatPsycho, + * Sarah Walker, * - * Copyright 2008-2018 Sarah Walker. + * Copyright 2017,2018 Fred N. van Kempen. * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. */ #include #include @@ -27,174 +48,410 @@ #include "../mem.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" +#include "vid_svga_render.h" #include "vid_sc1502x_ramdac.h" #include "vid_et4000.h" -#define BIOS_ROM_PATH L"roms/video/et4000/et4000.bin" +#define BIOS_ROM_PATH L"roms/video/et4000/et4000.bin" +#define KOREAN_BIOS_ROM_PATH L"roms/video/et4000/tgkorvga.bin" +#define KOREAN_FONT_ROM_PATH L"roms/video/et4000/tg_ksc5601.rom" -typedef struct et4000_t -{ - svga_t svga; - sc1502x_ramdac_t ramdac; - - rom_t bios_rom; - - uint8_t banking; - - uint8_t pos_regs[8]; - - int is_mca; +typedef struct { + const char *name; + int type; + + svga_t svga; + + uint8_t pos_regs[8]; + + rom_t bios_rom; + + uint8_t banking; + uint32_t vram_size, + vram_mask; + + 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; } et4000_t; -static uint8_t crtc_mask[0x40] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +static const uint8_t crtc_mask[0x40] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -void et4000_out(uint16_t addr, uint8_t val, void *p) -{ - et4000_t *et4000 = (et4000_t *)p; - svga_t *svga = &et4000->svga; - - uint8_t old; - - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) - addr ^= 0x60; +static video_timings_t timing_et4000_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; +static video_timings_t timing_et4000_mca = {VIDEO_MCA, 4, 5, 10, 5, 5, 10}; - switch (addr) - { - case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - sc1502x_ramdac_out(addr, val, &et4000->ramdac, svga); - return; - - case 0x3CD: /*Banking*/ - svga->write_bank = (val & 0xf) * 0x10000; - svga->read_bank = ((val >> 4) & 0xf) * 0x10000; - et4000->banking = val; - return; - case 0x3D4: - svga->crtcreg = val & 0x3f; - return; - case 0x3D5: - if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) - return; - if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) - val = (svga->crtc[7] & ~0x10) | (val & 0x10); - old = svga->crtc[svga->crtcreg]; - val &= crtc_mask[svga->crtcreg]; - svga->crtc[svga->crtcreg] = val; - if (old != val) - { - if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) - { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } + +static uint8_t +et4000_in(uint16_t addr, void *priv) +{ + et4000_t *dev = (et4000_t *)priv; + svga_t *svga = &dev->svga; + + if (((addr & 0xfff0) == 0x3d0 || + (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3c2: + if (dev->type == 1) { + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + return 0; + else + return 0x10; + } + break; + + case 0x3c5: + if ((svga->seqaddr & 0xf) == 7) + return svga->seqregs[svga->seqaddr & 0xf] | 4; break; - } - svga_out(addr, val, svga); + + case 0x3c6: + case 0x3c7: + case 0x3c8: + case 0x3c9: + return sc1502x_ramdac_in(addr, svga->ramdac, svga); + + case 0x3cd: /*Banking*/ + return dev->banking; + + case 0x3d4: + return svga->crtcreg; + + case 0x3d5: + return svga->crtc[svga->crtcreg]; + } + + return svga_in(addr, svga); } -uint8_t et4000_in(uint16_t addr, void *p) + +static uint8_t +et4000k_in(uint16_t addr, void *priv) { - et4000_t *et4000 = (et4000_t *)p; - svga_t *svga = &et4000->svga; + et4000_t *dev = (et4000_t *)priv; + uint8_t val = 0xff; + + switch (addr) { + case 0x22cb: + return dev->port_22cb_val; - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) - addr ^= 0x60; + case 0x22cf: + val = 0; + switch(dev->get_korean_font_enabled) { + case 3: + if ((dev->port_32cb_val & 0x30) == 0x30) { + val = fontdatksc5601[dev->get_korean_font_base].chr[dev->get_korean_font_index++]; + dev->get_korean_font_index &= 0x1f; + } else + if ((dev->port_32cb_val & 0x30) == 0x20 && + (dev->get_korean_font_base & 0x7f) > 0x20 && + (dev->get_korean_font_base & 0x7f) < 0x7f) { + switch(dev->get_korean_font_base & 0x3f80) { + case 0x2480: + if (dev->get_korean_font_index < 16) + val = fontdatksc5601_user[(dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index]; + else + if (dev->get_korean_font_index >= 24 && dev->get_korean_font_index < 40) + val = fontdatksc5601_user[(dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index - 8]; + break; - switch (addr) - { - case 0x3c2: - if (et4000->is_mca) - { - if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) - return 0; - else - return 0x10; + case 0x3f00: + if (dev->get_korean_font_index < 16) + val = fontdatksc5601_user[96 + (dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index]; + else + if (dev->get_korean_font_index >= 24 && dev->get_korean_font_index < 40) + val = fontdatksc5601_user[96 + (dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index - 8]; + break; + + default: + break; + } + dev->get_korean_font_index++; + dev->get_korean_font_index %= 72; } break; - - case 0x3C5: - if ((svga->seqaddr & 0xf) == 7) return svga->seqregs[svga->seqaddr & 0xf] | 4; - break; - case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - return sc1502x_ramdac_in(addr, &et4000->ramdac, svga); - - case 0x3CD: /*Banking*/ - return et4000->banking; - case 0x3D4: - return svga->crtcreg; - case 0x3D5: - return svga->crtc[svga->crtcreg]; - } - return svga_in(addr, svga); + case 4: + val = 0x0f; + break; + + default: + break; + } + return val; + + case 0x32cb: + return dev->port_32cb_val; + + default: + return et4000_in(addr, priv); + } } -void et4000_recalctimings(svga_t *svga) + +static void +et4000_out(uint16_t addr, uint8_t val, void *priv) { - svga->ma_latch |= (svga->crtc[0x33]&3)<<16; - if (svga->crtc[0x35] & 1) svga->vblankstart += 0x400; - if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; - if (svga->crtc[0x35] & 4) svga->dispend += 0x400; - if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400; - if (svga->crtc[0x35] & 0x10) svga->split += 0x400; - if (!svga->rowoffset) svga->rowoffset = 0x100; - if (svga->crtc[0x3f] & 1) svga->htotal += 256; - if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + et4000_t *dev = (et4000_t *)priv; + svga_t *svga = &dev->svga; + uint8_t old; - switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) - { - case 0: case 1: break; - case 3: svga->clock = cpuclock / 40000000.0; break; - case 5: svga->clock = cpuclock / 65000000.0; break; - default: svga->clock = cpuclock / 36000000.0; break; - } - - switch (svga->bpp) - { - case 15: case 16: - svga->hdisp /= 2; - break; - case 24: - svga->hdisp /= 3; - break; - } + if (((addr & 0xfff0) == 0x3d0 || + (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3c6: + case 0x3c7: + case 0x3c8: + case 0x3c9: + sc1502x_ramdac_out(addr, val, svga->ramdac, svga); + return; + + case 0x3cd: /*Banking*/ + if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (val & 0xf) * 0x10000; + svga->read_bank = ((val >> 4) & 0xf) * 0x10000; + } + dev->banking = val; + return; + + case 0x3cf: + if ((svga->gdcaddr & 15) == 6) { + if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { + svga->write_bank = (dev->banking & 0x0f) * 0x10000; + svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000; + } else + svga->write_bank = svga->read_bank = 0; + } + break; + + case 0x3d4: + svga->crtcreg = val & 0x3f; + return; + + case 0x3d5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 0x35) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (svga->crtcreg == 0x36) { + if (!(val & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (dev->banking & 0x0f) * 0x10000; + svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000; + } else + svga->write_bank = svga->read_bank = 0; + } + + if (old != val) { + if (svga->crtcreg < 0x0e || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + + /* + * Note - Silly hack to determine video memory + * size automatically by ET4000 BIOS. + */ + if ((svga->crtcreg == 0x37) && (dev->type != 1)) { + switch (val & 0x0b) { + case 0x00: + case 0x01: + if (svga->vram_max == 64 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + + case 0x02: + if (svga->vram_max == 128 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + + case 0x03: + case 0x08: + case 0x09: + if (svga->vram_max == 256 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + + case 0x0a: + if (svga->vram_max == 512 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + + case 0x0b: + if (svga->vram_max == 1024 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + + default: + mem_mapping_enable(&svga->mapping); + break; + } + } + break; + } + + svga_out(addr, val, svga); } -void *et4000_isa_init(const device_t *info) + +static void +et4000k_out(uint16_t addr, uint8_t val, void *priv) { - et4000_t *et4000 = malloc(sizeof(et4000_t)); - memset(et4000, 0, sizeof(et4000_t)); + et4000_t *dev = (et4000_t *)priv; - et4000->is_mca = 0; - - rom_init(&et4000->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - - io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + switch (addr) { + case 0x22cb: + dev->port_22cb_val = (dev->port_22cb_val & 0xf0) | (val & 0x0f); + dev->get_korean_font_enabled = val & 7; + if (dev->get_korean_font_enabled == 3) + dev->get_korean_font_index = 0; + break; - svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ - et4000_recalctimings, - et4000_in, et4000_out, - NULL, - NULL); - - return et4000; + case 0x22cf: + switch(dev->get_korean_font_enabled) { + case 1: + dev->get_korean_font_base = ((val & 0x7f) << 7) | (dev->get_korean_font_base & 0x7f); + break; + + case 2: + dev->get_korean_font_base = (dev->get_korean_font_base & 0x3f80) | (val & 0x7f) | (((val ^ 0x80) & 0x80) << 8); + break; + + case 3: + if ((dev->port_32cb_val & 0x30) == 0x20 && + (dev->get_korean_font_base & 0x7f) > 0x20 && + (dev->get_korean_font_base & 0x7f) < 0x7f) { + switch (dev->get_korean_font_base & 0x3f80) { + case 0x2480: + if (dev->get_korean_font_index < 16) + fontdatksc5601_user[(dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index] = val; + else + if (dev->get_korean_font_index >= 24 && dev->get_korean_font_index < 40) + fontdatksc5601_user[(dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index - 8] = val; + break; + + case 0x3f00: + if (dev->get_korean_font_index < 16) + fontdatksc5601_user[96 + (dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index] = val; + else + if (dev->get_korean_font_index >= 24 && dev->get_korean_font_index < 40) + fontdatksc5601_user[96 + (dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index - 8] = val; + break; + + default: + break; + } + dev->get_korean_font_index++; + } + break; + + default: + break; + } + break; + + case 0x32cb: + dev->port_32cb_val = val; + svga_recalctimings(&dev->svga); + break; + + default: + et4000_out(addr, val, priv); + break; + } } + +static void +et4000_recalctimings(svga_t *svga) +{ + et4000_t *dev = (et4000_t *)svga->p; + + svga->ma_latch |= (svga->crtc[0x33]&3)<<16; + if (svga->crtc[0x35] & 1) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 4) svga->dispend += 0x400; + if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (!svga->rowoffset) svga->rowoffset = 0x100; + if (svga->crtc[0x3f] & 1) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + + switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) { + case 0: + case 1: + 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) { + case 15: + case 16: + svga->hdisp /= 2; + break; + + case 24: + svga->hdisp /= 3; + break; + } + + if (dev->type == 2 || dev->type == 3) { +#if NOT_YET + if ((svga->render == svga_render_text_80) && ((svga->crtc[0x37] & 0x0A) == 0x0A)) { + if ((dev->port_32cb_val & 0xB4) == ((svga->crtc[0x37] & 3) == 2 ? 0xB4 : 0xB0)) { + svga->render = svga_render_text_80_ksc5601; + } + } +#endif + } +} + + static uint8_t et4000_mca_read(int port, void *priv) { @@ -203,6 +460,7 @@ et4000_mca_read(int port, void *priv) return(et4000->pos_regs[port & 7]); } + static void et4000_mca_write(int port, uint8_t val, void *priv) { @@ -215,78 +473,192 @@ et4000_mca_write(int port, uint8_t val, void *priv) et4000->pos_regs[port & 7] = val; } -void *et4000_mca_init(const device_t *info) + +static uint8_t +et4000_mca_feedb(void *priv) { - et4000_t *et4000 = malloc(sizeof(et4000_t)); - memset(et4000, 0, sizeof(et4000_t)); - - et4000->is_mca = 1; - - /* Enable MCA. */ - et4000->pos_regs[0] = 0xF2; /* ET4000 MCA board ID */ - et4000->pos_regs[1] = 0x80; - mca_add(et4000_mca_read, et4000_mca_write, et4000); - - rom_init(&et4000->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - - svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ - et4000_recalctimings, - et4000_in, et4000_out, - NULL, - NULL); - - io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); - - return et4000; + return 1; } -static int et4000_available(void) + +static void * +et4000_init(const device_t *info) { - return rom_present(BIOS_ROM_PATH); + const wchar_t *fn; + et4000_t *dev; + + dev = (et4000_t *)malloc(sizeof(et4000_t)); + memset(dev, 0x00, sizeof(et4000_t)); + dev->name = info->name; + dev->type = info->local; + fn = BIOS_ROM_PATH; + + switch(dev->type) { + case 0: /* ISA ET4000AX */ + dev->vram_size = device_get_config_int("memory") << 10; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa); + svga_init(&dev->svga, dev, dev->vram_size, + et4000_recalctimings, et4000_in, et4000_out, + NULL, NULL); + io_sethandler(0x03c0, 32, + et4000_in,NULL,NULL, et4000_out,NULL,NULL, dev); + break; + + case 1: /* MCA ET4000AX */ + dev->vram_size = 1024 << 10; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_mca); + svga_init(&dev->svga, dev, dev->vram_size, + et4000_recalctimings, et4000_in, et4000_out, + NULL, NULL); + io_sethandler(0x03c0, 32, + et4000_in,NULL,NULL, et4000_out,NULL,NULL, dev); + dev->pos_regs[0] = 0xf2; /* ET4000 MCA board ID */ + dev->pos_regs[1] = 0x80; + mca_add(et4000_mca_read, et4000_mca_write, et4000_mca_feedb, dev); + break; + + case 2: /* Korean ET4000 */ + case 3: /* Trigem 286M ET4000 */ + dev->vram_size = device_get_config_int("memory") << 10; + dev->port_22cb_val = 0x60; + dev->port_32cb_val = 0; + dev->svga.ksc5601_sbyte_mask = 0x80; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa); + svga_init(&dev->svga, dev, dev->vram_size, + et4000_recalctimings, et4000k_in, et4000k_out, + NULL, NULL); + io_sethandler(0x03c0, 32, + et4000k_in,NULL,NULL, et4000k_out,NULL,NULL, dev); + io_sethandler(0x22cb, 1, + et4000k_in,NULL,NULL, et4000k_out,NULL,NULL, dev); + io_sethandler(0x22cf, 1, + et4000k_in,NULL,NULL, et4000k_out,NULL,NULL, dev); + io_sethandler(0x32cb, 1, + et4000k_in,NULL,NULL, et4000k_out,NULL,NULL, dev); + loadfont(KOREAN_FONT_ROM_PATH, 6); + fn = KOREAN_BIOS_ROM_PATH; + break; + } + + dev->svga.ramdac = device_add(&sc1502x_ramdac_device); + + dev->vram_mask = dev->vram_size - 1; + + rom_init(&dev->bios_rom, (wchar_t *) fn, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return(dev); } -void et4000_close(void *p) -{ - et4000_t *et4000 = (et4000_t *)p; - svga_close(&et4000->svga); - - free(et4000); +static void +et4000_close(void *priv) +{ + et4000_t *dev = (et4000_t *)priv; + + svga_close(&dev->svga); + + free(dev); } -void et4000_speed_changed(void *p) + +static void +et4000_speed_changed(void *priv) { - et4000_t *et4000 = (et4000_t *)p; - - svga_recalctimings(&et4000->svga); + et4000_t *dev = (et4000_t *)priv; + + svga_recalctimings(&dev->svga); } -void et4000_force_redraw(void *p) -{ - et4000_t *et4000 = (et4000_t *)p; - et4000->svga.fullchange = changeframecount; +static void +et4000_force_redraw(void *priv) +{ + et4000_t *dev = (et4000_t *)priv; + + dev->svga.fullchange = changeframecount; } -const device_t et4000_isa_device = + +static int +et4000_available(void) { - "Tseng Labs ET4000AX (ISA)", - DEVICE_ISA, 0, - et4000_isa_init, et4000_close, NULL, - et4000_available, - et4000_speed_changed, - et4000_force_redraw, - NULL + return rom_present(BIOS_ROM_PATH); +} + + +static int +et4000k_available(void) +{ + return rom_present(KOREAN_BIOS_ROM_PATH) && + rom_present(KOREAN_FONT_ROM_PATH); +} + + +static const device_config_t et4000_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1024, + { + { + "256 KB", 256 + }, + { + "512 KB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } }; -const device_t et4000_mca_device = -{ - "Tseng Labs ET4000AX (MCA)", - DEVICE_MCA, 0, - et4000_mca_init, et4000_close, NULL, - et4000_available, - et4000_speed_changed, - et4000_force_redraw, - NULL +const device_t et4000_isa_device = { + "Tseng Labs ET4000AX (ISA)", + DEVICE_ISA, + 0, + et4000_init, et4000_close, NULL, + et4000_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_config }; +const device_t et4000_mca_device = { + "Tseng Labs ET4000AX (MCA)", + DEVICE_MCA, + 1, + et4000_init, et4000_close, NULL, + et4000_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_config +}; + +const device_t et4000k_isa_device = { + "Trigem Korean VGA (Tseng Labs ET4000AX Korean)", + DEVICE_ISA, + 2, + et4000_init, et4000_close, NULL, + et4000k_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_config +}; + +const device_t et4000k_tg286_isa_device = { + "Trigem Korean VGA (Trigem 286M)", + DEVICE_ISA, + 3, + et4000_init, et4000_close, NULL, + et4000k_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_config +}; diff --git a/src/video/vid_et4000.h b/src/video/vid_et4000.h index bb9ba03c2..b0a566c61 100644 --- a/src/video/vid_et4000.h +++ b/src/video/vid_et4000.h @@ -8,7 +8,7 @@ * * Emulation of the Tseng Labs ET4000. * - * Version: @(#)vid_et4000.c 1.0.7 2018/07/19 + * Version: @(#)vid_et4000.c 1.0.9 2018/08/16 * * Authors: Sarah Walker, * Miran Grca, @@ -20,6 +20,8 @@ # define EMU_VID_ET4000_H extern const device_t et4000_isa_device; +extern const device_t et4000k_isa_device; +extern const device_t et4000k_tg286_isa_device; extern const device_t et4000_mca_device; #endif /*EMU_VID_ET4000_H*/ \ No newline at end of file diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 2ed8837bf..66250d248 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -10,13 +10,13 @@ * * Known bugs: Accelerator doesn't work in planar modes * - * Version: @(#)vid_et4000w32.c 1.0.11 2018/07/16 + * Version: @(#)vid_et4000w32.c 1.0.22 2019/09/28 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -26,24 +26,21 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../cpu/cpu.h" #include "../io.h" #include "../mem.h" #include "../pci.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "../plat.h" #include "video.h" #include "vid_svga.h" -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +#include "vid_svga_render.h" #include "vid_icd2061.h" -#endif #include "vid_stg_ramdac.h" -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) #define BIOS_ROM_PATH_DIAMOND L"roms/video/et4000w32/et4000w32.bin" -#endif #define BIOS_ROM_PATH_CARDEX L"roms/video/et4000w32/cardex.vbi" @@ -61,9 +58,7 @@ enum { ET4000W32_CARDEX = 0, -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) ET4000W32_DIAMOND -#endif }; enum @@ -87,15 +82,12 @@ typedef struct et4000w32p_t rom_t bios_rom; svga_t svga; - stg_ramdac_t ramdac; -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) - icd2061_t icd2061; -#endif int index; int pci; uint8_t regs[256]; uint32_t linearbase, linearbase_old; + uint32_t vram_mask; uint8_t banking, banking2; @@ -147,8 +139,12 @@ typedef struct et4000w32p_t uint64_t blitter_time; uint64_t status_time; int type; + uint8_t hcr, mcr; + uint32_t key; } et4000w32p_t; +static video_timings_t timing_et4000w32 = {VIDEO_BUS, 4, 4, 4, 10, 10, 10}; + void et4000w32p_recalcmapping(et4000w32p_t *et4000); uint8_t et4000w32p_mmu_read(uint32_t addr, void *p); @@ -160,24 +156,26 @@ void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et400 #ifdef ENABLE_ET4000W32_LOG int et4000w32_do_log = ENABLE_ET4000W32_LOG; -#endif static void -et4000w32_log(const char *format, ...) +et4000w32_log(const char *fmt, ...) { -#ifdef ENABLE_ET4000W32_LOG va_list ap; if (et4000w32_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define et4000w32_log(fmt, ...) +#endif +uint8_t et4000w32p_in(uint16_t addr, void *p); + void et4000w32p_out(uint16_t addr, uint8_t val, void *p) { et4000w32p_t *et4000 = (et4000w32p_t *)p; @@ -189,31 +187,39 @@ void et4000w32p_out(uint16_t addr, uint8_t val, void *p) switch (addr) { -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) case 0x3c2: if (et4000->type == ET4000W32_DIAMOND) - icd2061_write(&et4000->icd2061, (val >> 2) & 3); + icd2061_write(svga->clock_gen, (val >> 2) & 3); break; -#endif case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - stg_ramdac_out(addr, val, &et4000->ramdac, svga); + stg_ramdac_out(addr, val, svga->ramdac, svga); return; case 0x3CB: /*Banking extension*/ - svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20); - svga->read_bank = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16); + if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20); + svga->read_bank = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16); + } et4000->banking2 = val; return; case 0x3CD: /*Banking*/ - svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536); - svga->read_bank = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536); + if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536); + svga->read_bank = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536); + } et4000->banking = val; return; case 0x3CF: switch (svga->gdcaddr & 15) { case 6: + if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { + svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536); + svga->read_bank = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536); + } else + svga->write_bank = svga->read_bank = 0; + svga->gdcreg[svga->gdcaddr & 15] = val; et4000w32p_recalcmapping(et4000); return; @@ -225,10 +231,19 @@ void et4000w32p_out(uint16_t addr, uint8_t val, void *p) case 0x3D5: if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; + if ((svga->crtcreg == 0x35) && (svga->crtc[0x11] & 0x80)) + return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) val = (svga->crtc[7] & ~0x10) | (val & 0x10); old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; + if (svga->crtcreg == 0x36) { + if (!(val & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536); + svga->read_bank = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536); + } else + svga->write_bank = svga->read_bank = 0; + } if (old != val) { if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) @@ -290,7 +305,7 @@ uint8_t et4000w32p_in(uint16_t addr, void *p) break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - return stg_ramdac_in(addr, &et4000->ramdac, svga); + return stg_ramdac_in(addr, svga->ramdac, svga); case 0x3CB: return et4000->banking2; @@ -329,7 +344,6 @@ uint8_t et4000w32p_in(uint16_t addr, void *p) void et4000w32p_recalctimings(svga_t *svga) { - et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; if (svga->crtc[0x35] & 0x01) svga->vblankstart += 0x400; if (svga->crtc[0x35] & 0x02) svga->vtotal += 0x400; @@ -340,23 +354,8 @@ void et4000w32p_recalctimings(svga_t *svga) if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) - if (et4000->type == ET4000W32_DIAMOND) - { - switch ((svga->miscout >> 2) & 3) - { - case 0: case 1: break; - case 2: case 3: svga->clock = cpuclock / icd2061_getfreq(&et4000->icd2061, 2); break; - } - } - else - { -#endif - svga->clock = cpuclock / stg_getclock((svga->miscout >> 2) & 3, &et4000->ramdac); -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) - } -#endif - + svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + switch (svga->bpp) { case 15: case 16: @@ -366,6 +365,66 @@ void et4000w32p_recalctimings(svga_t *svga) svga->hdisp /= 3; break; } + + svga->render = svga_render_blank; + if (!svga->scrblank && svga->attr_palette_enable) { + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 8) /*40 column*/ + svga->render = svga_render_text_40; + else + svga->render = svga_render_text_80; + } else { + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: /*256+ colours*/ + switch (svga->bpp) { + case 8: + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 24: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; + } + break; + } + } + } } void et4000w32p_recalcmapping(et4000w32p_t *et4000) @@ -1077,26 +1136,22 @@ void et4000w32p_hwcursor_draw(svga_t *svga, int displine) { int x, offset; uint8_t dat; - int y_add, x_add; offset = svga->hwcursor_latch.xoff; - y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; - x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; - for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) { dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 1] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 1] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 2] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 2] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 3] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine][svga->hwcursor_latch.x + svga->x_add + x + 3] ^= 0xFFFFFF; dat >>= 2; offset += 4; } @@ -1232,33 +1287,44 @@ void *et4000w32p_init(const device_t *info) vram_size = device_get_config_int("memory"); et4000->interleaved = (vram_size == 2) ? 1 : 0; - + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32); + svga_init(&et4000->svga, et4000, vram_size << 20, et4000w32p_recalctimings, et4000w32p_in, et4000w32p_out, et4000w32p_hwcursor_draw, NULL); + et4000->svga.ramdac = device_add(&stg_ramdac_device); + + et4000->vram_mask = (vram_size << 20) - 1; + et4000->type = info->local; switch(et4000->type) { case ET4000W32_CARDEX: rom_init(&et4000->bios_rom, BIOS_ROM_PATH_CARDEX, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = stg_getclock; break; -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + case ET4000W32_DIAMOND: rom_init(&et4000->bios_rom, BIOS_ROM_PATH_DIAMOND, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + et4000->svga.clock_gen = device_add(&icd2061_device); + et4000->svga.getclock = icd2061_getclock; break; -#endif } et4000->pci = !!(info->flags & DEVICE_PCI); if (info->flags & DEVICE_PCI) mem_mapping_disable(&et4000->bios_rom.mapping); - mem_mapping_add(&et4000->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &et4000->svga); - mem_mapping_add(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, 0, et4000); + mem_mapping_add(&et4000->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &et4000->svga); + mem_mapping_add(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, et4000); et4000w32p_io_set(et4000); @@ -1287,12 +1353,10 @@ void *et4000w32p_init(const device_t *info) return et4000; } -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) int et4000w32p_available(void) { return rom_present(BIOS_ROM_PATH_DIAMOND); } -#endif int et4000w32p_cardex_available(void) { @@ -1369,7 +1433,6 @@ const device_t et4000w32p_cardex_pci_device = et4000w32p_config }; -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) const device_t et4000w32p_vlb_device = { "Tseng Labs ET4000/w32p VLB (Diamond)", @@ -1391,4 +1454,3 @@ const device_t et4000w32p_pci_device = et4000w32p_force_redraw, et4000w32p_config }; -#endif diff --git a/src/video/vid_et4000w32.h b/src/video/vid_et4000w32.h index 80a14e5d4..350933be5 100644 --- a/src/video/vid_et4000w32.h +++ b/src/video/vid_et4000w32.h @@ -1,7 +1,5 @@ -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) extern const device_t et4000w32p_vlb_device; extern const device_t et4000w32p_pci_device; -#endif extern const device_t et4000w32p_cardex_vlb_device; extern const device_t et4000w32p_cardex_pci_device; diff --git a/src/video/vid_et4000w32i.c b/src/video/vid_et4000w32i.c deleted file mode 100644 index f77055e37..000000000 --- a/src/video/vid_et4000w32i.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * The below is (with some removals) a reasonable emulation - * of the ET4000/W32i blitter. Unfortunately the Diamond - * Stealth 32 is actually an ET4000/W32p! Which has a different - * blitter. If only I'd dug out and looked at the card before - * trying to emulate it. - * - * This might be of use for an attempt at an ET4000/W32i. - * - * Version: @(#)vid_et4000w32i.c 1.0.2 2017/11/04 - * - * Author: Sarah Walker, - * - * Copyright 2008-2017 Sarah Walker. - */ -#if 0 - -#include -#include -#include -#include -#include "../86box.h" - -int et4k_b8000; - -struct -{ - struct - { - uint32_t pattern_addr,source_addr,dest_addr; - uint16_t pattern_off,source_off,dest_off; - uint8_t vbus,xy_dir; - uint8_t pattern_wrap,source_wrap; - uint16_t count_x,count_y; - uint8_t ctrl_routing,ctrl_reload; - uint8_t rop_fg,rop_bg; - uint16_t pos_x,pos_y; - } queued,internal; - uint32_t pattern_addr,source_addr,dest_addr; - uint32_t pattern_back,dest_back; - int pattern_x,source_x; - int pattern_x_back; - int pattern_y,source_y; - uint8_t status; - uint32_t cpu_input; - int cpu_input_num; -} acl; - -#define ACL_WRST 1 -#define ACL_RDST 2 -#define ACL_XYST 4 -#define ACL_SSO 8 - -struct -{ - uint32_t base[3]; - uint8_t ctrl; -} mmu; - -void et4000w32_reset() -{ - acl.status=0; - acl.cpu_input_num=0; -} - -void et4000w32_blit_start(); -void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input); - -int et4000w32_vbus[4]={1,2,4,4}; - -void et4000w32_mmu_write(uint32_t addr, uint8_t val) -{ - int bank; - pclog("ET4K write %08X %02X %i %02X %02X %04X(%08X):%08X %04X %04X %02X %08X\n",addr,val,acl.cpu_input_num,acl.status,acl.internal.ctrl_routing,CS,cs,pc,CS,DI,mmu.ctrl,mmu.base[2]); - switch (addr&0x6000) - { - case 0x0000: /*MMU 0*/ - case 0x2000: /*MMU 1*/ - case 0x4000: /*MMU 2*/ - bank=(addr>>13)&3; - if (mmu.ctrl&(1<>12]=changeframecount; - } - break; - case 0x6000: - switch (addr&0x7FFF) - { - case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break; - case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break; - case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break; - case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break; - case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break; - case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break; - case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break; - case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break; - case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break; - case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break; - case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break; - case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break; - case 0x7F13: mmu.ctrl=val; break; - - case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break; - case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break; - case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break; - case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break; - case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break; - case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break; - case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break; - case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break; - case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break; - case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break; - case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break; - case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break; - case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break; - case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break; - case 0x7F8E: acl.queued.vbus=val; break; - case 0x7F8F: acl.queued.xy_dir=val; break; - case 0x7F90: acl.queued.pattern_wrap=val; break; - case 0x7F92: acl.queued.source_wrap=val; break; - case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break; - case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break; - case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break; - case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break; - case 0x7F9C: acl.queued.ctrl_routing=val; break; - case 0x7F9D: acl.queued.ctrl_reload =val; break; - case 0x7F9E: acl.queued.rop_bg =val; break; - case 0x7F9F: acl.queued.rop_fg =val; break; - case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break; - case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break; - case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break; - case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24); - acl.internal=acl.queued; - et4000w32_blit_start(); - acl.cpu_input_num=0; - if (!(acl.queued.ctrl_routing&0x37)) - { - et4000w32_blit(0xFFFFFF, ~0, 0, 0); - } - break; - } - break; - } -} - -uint8_t et4000w32_mmu_read(uint32_t addr) -{ - int bank; - pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); - switch (addr&0x6000) - { - case 0x0000: /*MMU 0*/ - case 0x2000: /*MMU 1*/ - case 0x4000: /*MMU 2*/ - bank=(addr>>13)&3; - if (mmu.ctrl&(1<>8; - case 0x7F02: return mmu.base[0]>>16; - case 0x7F03: return mmu.base[0]>>24; - case 0x7F04: return mmu.base[1]; - case 0x7F05: return mmu.base[1]>>8; - case 0x7F06: return mmu.base[1]>>16; - case 0x7F07: return mmu.base[1]>>24; - case 0x7F08: return mmu.base[2]; - case 0x7F09: return mmu.base[2]>>8; - case 0x7F0A: return mmu.base[2]>>16; - case 0x7F0B: return mmu.base[2]>>24; - case 0x7F13: return mmu.ctrl; - - case 0x7F36: -// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST; - return acl.status & ~(ACL_XYST | ACL_SSO); - case 0x7F80: return acl.internal.pattern_addr; - case 0x7F81: return acl.internal.pattern_addr>>8; - case 0x7F82: return acl.internal.pattern_addr>>16; - case 0x7F83: return acl.internal.pattern_addr>>24; - case 0x7F84: return acl.internal.source_addr; - case 0x7F85: return acl.internal.source_addr>>8; - case 0x7F86: return acl.internal.source_addr>>16; - case 0x7F87: return acl.internal.source_addr>>24; - case 0x7F88: return acl.internal.pattern_off; - case 0x7F89: return acl.internal.pattern_off>>8; - case 0x7F8A: return acl.internal.source_off; - case 0x7F8B: return acl.internal.source_off>>8; - case 0x7F8C: return acl.internal.dest_off; - case 0x7F8D: return acl.internal.dest_off>>8; - case 0x7F8E: return acl.internal.vbus; - case 0x7F8F: return acl.internal.xy_dir; - case 0x7F90: return acl.internal.pattern_wrap; - case 0x7F92: return acl.internal.source_wrap; - case 0x7F98: return acl.internal.count_x; - case 0x7F99: return acl.internal.count_x>>8; - case 0x7F9A: return acl.internal.count_y; - case 0x7F9B: return acl.internal.count_y>>8; - case 0x7F9C: return acl.internal.ctrl_routing; - case 0x7F9D: return acl.internal.ctrl_reload; - case 0x7F9E: return acl.internal.rop_bg; - case 0x7F9F: return acl.internal.rop_fg; - case 0x7FA0: return acl.internal.dest_addr; - case 0x7FA1: return acl.internal.dest_addr>>8; - case 0x7FA2: return acl.internal.dest_addr>>16; - case 0x7FA3: return acl.internal.dest_addr>>24; - } - return 0xFF; - } -} - -int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; -int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; - -void et4000w32_blit_start() -{ - pclog("Blit - %08X %08X %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.internal.pattern_addr,acl.internal.source_addr,acl.internal.dest_addr,acl.internal.dest_addr%640,acl.internal.dest_addr/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing); - acl.pattern_addr=acl.internal.pattern_addr; - acl.source_addr =acl.internal.source_addr; - acl.dest_addr =acl.internal.dest_addr; - acl.dest_back =acl.dest_addr; - acl.internal.pos_x=acl.internal.pos_y=0; - acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0; - acl.status = ACL_XYST; - if (!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) acl.status |= ACL_SSO; - if (et4000w32_wrap_x[acl.internal.pattern_wrap&7]) - { - acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7]; - acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7]; - } - if (!(acl.internal.pattern_wrap&0x80)) - { - acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1); - acl.pattern_addr&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1); - } - acl.pattern_x_back=acl.pattern_x; - acl.pattern_back=acl.pattern_addr; -} - -void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input) -{ - int c,d; - uint8_t pattern,source,dest,out; - uint8_t rop; - -// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr); -// pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y); - while (count--) - { - pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y); - if (acl.internal.xy_dir&1) - { - pattern=vram[(acl.pattern_addr-acl.pattern_x)&0x1FFFFF]; - source =vram[(acl.source_addr -acl.source_x) &0x1FFFFF]; - pclog("%06X %06X ",(acl.pattern_addr-acl.pattern_x)&0x1FFFFF,(acl.source_addr -acl.source_x) &0x1FFFFF); - } - else - { - pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF]; - source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF]; - pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF); - } - if (cpu_input==2) - { - source=sdat&0xFF; - sdat>>=8; - } - dest=vram[acl.dest_addr &0x1FFFFF]; - out=0; - pclog("%06X %i %08X ",acl.dest_addr,mix&1,mix); - rop = (mix & 1) ? acl.internal.rop_fg:acl.internal.rop_bg; - mix>>=1; mix|=0x80000000; - for (c=0;c<8;c++) - { - d=(dest & (1<>12]=changeframecount; - - acl.pattern_x++; - acl.pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; - acl.source_x++; - acl.source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; - if (acl.internal.xy_dir&1) acl.dest_addr--; - else acl.dest_addr++; - - acl.internal.pos_x++; - if (acl.internal.pos_x>acl.internal.count_x) - { - if (acl.internal.xy_dir&2) - { - acl.pattern_addr-=(acl.internal.pattern_off+1); - acl.source_addr -=(acl.internal.source_off +1); - acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1); - } - else - { - acl.pattern_addr+=acl.internal.pattern_off+1; - acl.source_addr +=acl.internal.source_off +1; - acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1; - } - acl.pattern_x = acl.pattern_x_back; - acl.source_x = 0; - acl.pattern_y++; - if (acl.pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) - { - acl.pattern_y=0; - acl.pattern_addr=acl.pattern_back; - } - acl.source_y++; - if (acl.source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) - { - acl.source_y=0; - acl.source_addr=acl.internal.source_addr; - } - - acl.internal.pos_y++; - if (acl.internal.pos_y>acl.internal.count_y) - { - acl.status = 0; - return; - } - acl.internal.pos_x=0; - if (cpu_input) return; - } - } -} - -/* for (y=0;y<=acl.internal.count_y;y++) - { - dest_back=acl.dest_addr; - for (x=0;x<=acl.internal.count_x;x++) - { - if (acl.internal.xy_dir&1) - { - pattern=vram[(acl.pattern_addr-pattern_x)&0x1FFFFF]; - source =vram[(acl.source_addr -source_x) &0x1FFFFF]; - } - else - { - pattern=vram[(acl.pattern_addr+pattern_x)&0x1FFFFF]; - source =vram[(acl.source_addr +source_x) &0x1FFFFF]; - } - dest=vram[acl.dest_addr &0x1FFFFF]; - out=0; - for (c=0;c<8;c++) - { - d=(dest&(1<>12]=changeframecount; - - pattern_x++; - pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; - source_x++; - source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; - if (acl.internal.xy_dir&1) acl.dest_addr--; - else acl.dest_addr++; - } - acl.pattern_addr+=acl.internal.pattern_off+1; - acl.source_addr +=acl.internal.source_off+1; - acl.dest_addr=dest_back+acl.internal.dest_off+1; - pattern_y++; - if (pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) - { - pattern_y=0; - acl.pattern_addr=acl.internal.pattern_addr; - } - source_y++; - if (source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) - { - source_y=0; - acl.source_addr=acl.internal.source_addr; - } - }*/ - -#endif diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index 91d1bce61..89f40da8c 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -8,13 +8,13 @@ * * MDSI Genius VHR emulation. * - * Version: @(#)vid_genius.c 1.0.10 2018/05/20 + * Version: @(#)vid_genius.c 1.0.12 2019/03/17 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -22,11 +22,12 @@ #include #include #include "../86box.h" +#include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "../plat.h" #include "video.h" @@ -40,7 +41,9 @@ #define GENIUS_YSIZE 1008 -extern uint8_t fontdat8x12[256][16]; +extern uint8_t fontdat8x12[256][16]; + +static video_timings_t timing_genius = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; /* I'm at something of a disadvantage writing this emulation: I don't have an @@ -101,6 +104,8 @@ typedef struct genius_t uint8_t mda_crtc[32]; /* The 'CRTC' as the host PC sees it */ int mda_crtcreg; /* Current CRTC register */ + uint8_t cga_crtc[32]; /* The 'CRTC' as the host PC sees it */ + int cga_crtcreg; /* Current CRTC register */ uint8_t genius_control; /* Native control register * I think bit 0 enables the full * framebuffer. @@ -124,525 +129,669 @@ typedef struct genius_t int enabled; /* Display enabled, 0 or 1 */ int detach; /* Detach cursor, 0 or 1 */ - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int linepos, displine; int vc; int dispon, blink; - int64_t vsynctime; + int vsynctime; uint8_t *vram; } genius_t; -static uint32_t genius_pal[4]; +static uint8_t genius_pal[4]; /* Mapping of attributes to colours, in MDA emulation mode */ -static int mdacols[256][2][2]; +static uint8_t mdaattr[256][2][2]; void genius_recalctimings(genius_t *genius); void genius_write(uint32_t addr, uint8_t val, void *p); uint8_t genius_read(uint32_t addr, void *p); -void genius_out(uint16_t addr, uint8_t val, void *p) +void +genius_out(uint16_t addr, uint8_t val, void *p) { - genius_t *genius = (genius_t *)p; + genius_t *genius = (genius_t *)p; - switch (addr) - { - case 0x3b0: /* Command / control register */ + switch (addr) { + case 0x3b0: /* Command / control register */ genius->genius_control = val; if (val & 1) - { mem_mapping_set_addr(&genius->mapping, 0xa0000, 0x28000); - } else - { mem_mapping_set_addr(&genius->mapping, 0xb0000, 0x10000); - } - break; - case 0x3b1: + case 0x3b1: genius->genius_charh = val; break; - /* Emulated CRTC, register select */ - case 0x3b2: case 0x3b4: case 0x3b6: - case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: - genius->mda_crtcreg = val & 31; - break; + /* Emulated CRTC, register select */ + case 0x3b2: case 0x3b4: case 0x3b6: + genius->mda_crtcreg = val & 31; + break; - /* Emulated CRTC, value */ - case 0x3b3: case 0x3b5: case 0x3b7: - case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: - genius->mda_crtc[genius->mda_crtcreg] = val; - genius_recalctimings(genius); - return; + /* Emulated CRTC, value */ + case 0x3b3: case 0x3b5: case 0x3b7: + genius->mda_crtc[genius->mda_crtcreg] = val; + genius_recalctimings(genius); + return; - /* Emulated MDA control register */ - case 0x3b8: - genius->mda_ctrl = val; - return; - /* Emulated CGA control register */ - case 0x3D8: - genius->cga_ctrl = val; - return; - /* Emulated CGA colour register */ - case 0x3D9: - genius->cga_colour = val; - return; - } + /* Emulated MDA control register */ + case 0x3b8: + genius->mda_ctrl = val; + return; + + /* Emulated CRTC, register select */ + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + genius->cga_crtcreg = val & 31; + break; + + /* Emulated CRTC, value */ + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + genius->cga_crtc[genius->cga_crtcreg] = val; + genius_recalctimings(genius); + return; + + /* Emulated CGA control register */ + case 0x3d8: + genius->cga_ctrl = val; + return; + /* Emulated CGA colour register */ + case 0x3d9: + genius->cga_colour = val; + return; + } } -uint8_t genius_in(uint16_t addr, void *p) + +uint8_t +genius_in(uint16_t addr, void *p) { - genius_t *genius = (genius_t *)p; - - switch (addr) - { - case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: - case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: - return genius->mda_crtcreg; - case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: - case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: - return genius->mda_crtc[genius->mda_crtcreg]; - case 0x3b8: - return genius->mda_ctrl; - case 0x3d9: - return genius->cga_colour; - case 0x3ba: - return genius->mda_stat; - case 0x3d8: - return genius->cga_ctrl; - case 0x3da: - return genius->cga_stat; - } - return 0xff; + genius_t *genius = (genius_t *)p; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + ret = genius->mda_crtcreg; + break; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + ret = genius->mda_crtc[genius->mda_crtcreg]; + break; + case 0x3b8: + ret = genius->mda_ctrl; + break; + case 0x3ba: + ret = genius->mda_stat; + break; + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + ret = genius->cga_crtcreg; + break; + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + ret = genius->cga_crtc[genius->cga_crtcreg]; + break; + case 0x3d8: + ret = genius->cga_ctrl; + break; + case 0x3d9: + ret = genius->cga_colour; + break; + case 0x3da: + ret = genius->cga_stat; + break; + } + + return ret; } -void genius_write(uint32_t addr, uint8_t val, void *p) + +static void +genius_waitstates(void) { - genius_t *genius = (genius_t *)p; - egawrites++; - - if (genius->genius_control & 1) - { - addr = addr % 0x28000; - } + int ws_array[16] = {3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8}; + int ws; + + ws = ws_array[cycles & 0xf]; + sub_cycles(ws); +} + + +void +genius_write(uint32_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + egawrites++; + genius_waitstates(); + + if (genius->genius_control & 1) { + if ((addr >= 0xa0000) && (addr < 0xb0000)) + addr = (addr - 0xa0000) & 0xffff; + else if ((addr >= 0xb0000) && (addr < 0xb8000)) + addr = ((addr - 0xb0000) & 0x7fff) + 0x10000; else + addr = ((addr - 0xb8000) & 0xffff) + 0x18000; + } else { /* If hi-res memory is disabled, only visible in the B000 segment */ - { - addr = (addr & 0xFFFF) + 0x10000; - } - genius->vram[addr] = val; -} - - - -uint8_t genius_read(uint32_t addr, void *p) -{ - genius_t *genius = (genius_t *)p; - egareads++; - - if (genius->genius_control & 1) - { - addr = addr % 0x28000; - } + if (addr >= 0xb8000) + addr = (addr & 0x3FFF) + 0x18000; else - /* If hi-res memory is disabled, only visible in the B000 segment */ - { - addr = (addr & 0xFFFF) + 0x10000; - } - return genius->vram[addr]; + addr = (addr & 0x7FFF) + 0x10000; + } + + genius->vram[addr] = val; } -void genius_recalctimings(genius_t *genius) -{ - double disptime; - double _dispontime, _dispofftime; - disptime = 0x31; - _dispontime = 0x28; - _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; - genius->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - genius->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +uint8_t +genius_read(uint32_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + uint8_t ret; + egareads++; + genius_waitstates(); + + if (genius->genius_control & 1) { + if ((addr >= 0xa0000) && (addr < 0xb0000)) + addr = (addr - 0xa0000) & 0xffff; + else if ((addr >= 0xb0000) && (addr < 0xb8000)) + addr = ((addr - 0xb0000) & 0x7fff) + 0x10000; + else + addr = ((addr - 0xb8000) & 0xffff) + 0x18000; + } else { + /* If hi-res memory is disabled, only visible in the B000 segment */ + if (addr >= 0xb8000) + addr = (addr & 0x3FFF) + 0x18000; + else + addr = (addr & 0x7FFF) + 0x10000; + } + + ret = genius->vram[addr]; + return ret; +} + + +void +genius_recalctimings(genius_t *genius) +{ + double disptime; + double _dispontime, _dispofftime; + + disptime = 0x31; + _dispontime = 0x28; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + genius->dispontime = (uint64_t)(_dispontime); + genius->dispofftime = (uint64_t)(_dispofftime); +} + + +static int +genius_lines(genius_t *genius) +{ + int ret = 350; + + switch (genius->genius_charh & 0x13) { + case 0x00: + ret = 990; /* 80x66 */ + break; + case 0x01: + ret = 980; /* 80x70 */ + break; + case 0x02: + ret = 988; /* Guess: 80x76 */ + break; + case 0x03: + ret = 984; /* 80x82 */ + break; + case 0x10: + ret = 375; /* Logic says 80x33 but it appears to be 80x25 */ + break; + case 0x11: + ret = 490; /* Guess: 80x35, fits the logic as well, half of 80x70 */ + break; + case 0x12: + ret = 494; /* Guess: 80x38 */ + break; + case 0x13: + ret = 492; /* 80x41 */ + break; + } + + return ret; } /* Draw a single line of the screen in either text mode */ -void genius_textline(genius_t *genius, uint8_t background) +static void +genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) { - int x; - int w = 80; /* 80 characters across */ - int cw = 9; /* Each character is 9 pixels wide */ - uint8_t chr, attr; - uint8_t bitmap[2]; - int blink, c, row; - int drawcursor, cursorline; - uint16_t addr; - uint8_t sc; - int charh; - 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; - uint32_t col; + int w = 80; /* 80 characters across */ + int cw = 9; /* Each character is 9 pixels wide */ + uint8_t chr, attr, sc, ctrl; + uint8_t *crtc, bitmap[2]; + int x, blink, c, row, charh; + int drawcursor, cursorline; + uint16_t addr; + 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; + uint32_t col, dl = genius->displine; - /* Character height is 12-15 */ + /* Character height is 12-15 */ + if (mda) { + if (genius->displine >= genius_lines(genius)) + return; + + crtc = genius->mda_crtc; + ctrl = genius->mda_ctrl; charh = 15 - (genius->genius_charh & 3); - if (genius->genius_charh & 0x10) - { - row = ((genius->displine >> 1) / charh); - sc = ((genius->displine >> 1) % charh); - } - else - { - row = (genius->displine / charh); - sc = (genius->displine % charh); - } - addr = ((ma & ~1) + row * w) * 2; - ma += (row * w); - - if ((genius->mda_crtc[10] & 0x60) == 0x20) - { - cursorline = 0; +#if 0 + if (genius->genius_charh & 0x10) { + row = ((dl >> 1) / charh); + sc = ((dl >> 1) % charh); + } else { + row = (dl / charh); + sc = (dl % charh); } - else - { - cursorline = ((genius->mda_crtc[10] & 0x1F) <= sc) && - ((genius->mda_crtc[11] & 0x1F) >= sc); +#else + row = (dl / charh); + sc = (dl % charh); +#endif + } else { + if ((genius->displine < 512) || (genius->displine >= 912)) + return; + + crtc = genius->cga_crtc; + ctrl = genius->cga_ctrl; + framebuf += 0x08000; + + dl -= 512; + w = crtc[1]; + cw = 8; + charh = crtc[9] + 1; + + row = ((dl >> 1) / charh); + sc = ((dl >> 1) % charh); + } + + ma = (crtc[13] | (crtc[12] << 8)) & 0x3fff; + ca = (crtc[15] | (crtc[14] << 8)) & 0x3fff; + + addr = ((ma & ~1) + row * w) * 2; + + if (!mda) + dl += 512; + + ma += (row * w); + + if ((crtc[10] & 0x60) == 0x20) + cursorline = 0; + else + cursorline = ((crtc[10] & 0x1F) <= sc) && ((crtc[11] & 0x1F) >= sc); + + for (x = 0; x < w; x++) { +#if 0 + if ((genius->genius_charh & 0x10) && ((addr + 2 * x) > 0x0FFF)) + chr = 0x00; + if ((genius->genius_charh & 0x10) && ((addr + 2 * x + 1) > 0x0FFF)) + attr = 0x00; +#endif + chr = framebuf[(addr + 2 * x) & 0x3FFF]; + attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; + + drawcursor = ((ma == ca) && cursorline && genius->enabled && (ctrl & 8)); + + switch (crtc[10] & 0x60) { + case 0x00: drawcursor = drawcursor && (genius->blink & 16); break; + case 0x60: drawcursor = drawcursor && (genius->blink & 32); break; } - for (x = 0; x < w; x++) - { - chr = framebuf[(addr + 2 * x) & 0x3FFF]; - attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && genius->enabled && - (genius->mda_ctrl & 8)); + blink = ((genius->blink & 16) && (ctrl & 0x20) && (attr & 0x80) && !drawcursor); - switch (genius->mda_crtc[10] & 0x60) - { - case 0x00: drawcursor = drawcursor && (genius->blink & 16); break; - case 0x60: drawcursor = drawcursor && (genius->blink & 32); break; + if (ctrl & 0x20) attr &= 0x7F; + + /* MDA underline */ + if (mda && (sc == charh) && ((attr & 7) == 1)) { + col = mdaattr[attr][blink][1]; + + if (genius->genius_control & 0x20) + col ^= 15; + + for (c = 0; c < cw; c++) { + if (col != background) { + if (cols80) + buffer32->line[dl][(x * cw) + c] = col; + else { + buffer32->line[dl][((x * cw) << 1) + (c << 1)] = + buffer32->line[dl][((x * cw) << 1) + (c << 1) + 1] = col; + } + } } - blink = ((genius->blink & 16) && - (genius->mda_ctrl & 0x20) && - (attr & 0x80) && !drawcursor); + } else { /* Draw 8 pixels of character */ + if (mda) + bitmap[0] = fontdat8x12[chr][sc]; + else + bitmap[0] = fontdat[chr][sc]; - if (genius->mda_ctrl & 0x20) attr &= 0x7F; - /* MDA underline */ - if (sc == charh && ((attr & 7) == 1)) - { - col = mdacols[attr][blink][1]; + for (c = 0; c < 8; c++) { + col = mdaattr[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + if (!(genius->enabled) || !(ctrl & 8)) + col = mdaattr[0][0][0]; if (genius->genius_control & 0x20) - { - col ^= 0xffffff; - } + col ^= 15; - for (c = 0; c < cw; c++) - { - if (col != background) - ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; + if (col != background) { + if (cols80) + buffer32->line[dl][(x * cw) + c] = col; + else { + buffer32->line[dl][((x * cw) << 1) + (c << 1)] = + buffer32->line[dl][((x * cw) << 1) + (c << 1) + 1] = col; + } } } - else /* Draw 8 pixels of character */ - { - bitmap[0] = fontdat8x12[chr][sc]; - for (c = 0; c < 8; c++) - { - col = mdacols[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; - if (!(genius->enabled) || !(genius->mda_ctrl & 8)) - col = mdacols[0][0][0]; - - if (genius->genius_control & 0x20) - { - col ^= 0xffffff; - } - if (col != background) - { - ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; - } - } + + if (cw == 9) { /* The ninth pixel column... */ - if ((chr & ~0x1f) == 0xc0) - { + if ((chr & ~0x1f) == 0xc0) { /* Echo column 8 for the graphics chars */ - 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 ^= 0xffffff; + if (cols80) { + col = buffer32->line[dl][(x * cw) + 7]; + if (col != background) + buffer32->line[dl][(x * cw) + 8] = col; + } else { + col = buffer32->line[dl][((x * cw) << 1) + 14]; + if (col != background) { + buffer32->line[dl][((x * cw) << 1) + 16] = + buffer32->line[dl][((x * cw) << 1) + 17] = col; + } + } + } else { /* Otherwise fill with background */ + col = mdaattr[attr][blink][0]; + if (genius->genius_control & 0x20) + col ^= 15; + if (col != background) { + if (cols80) + buffer32->line[dl][(x * cw) + 8] = col; + else { + buffer32->line[dl][((x * cw) << 1) + 16] = + buffer32->line[dl][((x * cw) << 1) + 17] = col; + } } - if (col != background) - ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 8] = col; } - if (drawcursor) - { - for (c = 0; c < cw; c++) - ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] ^= mdacols[attr][0][1]; - } - ++ma; } + + if (drawcursor) { + for (c = 0; c < cw; c++) { + if (cols80) + buffer32->line[dl][(x * cw) + c] ^= mdaattr[attr][0][1]; + else { + buffer32->line[dl][((x * cw) << 1) + (c << 1)] ^= mdaattr[attr][0][1]; + buffer32->line[dl][((x * cw) << 1) + (c << 1) + 1] ^= mdaattr[attr][0][1]; + } + } + } + ++ma; } + } } + /* Draw a line in the CGA 640x200 mode */ -void genius_cgaline(genius_t *genius) +void +genius_cgaline(genius_t *genius) { - int x, c; - uint32_t dat; - uint32_t ink; - uint32_t addr; + int x, c; + uint32_t dat, addr; + uint8_t ink_f, ink_b; - ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; - /* We draw the CGA at row 600 */ - if (genius->displine < 600) - { - return; - } - addr = 0x18000 + 80 * ((genius->displine - 600) >> 2); - if ((genius->displine - 600) & 2) - { - addr += 0x2000; - } + ink_f = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; + ink_b = (genius->genius_control & 0x20) ? genius_pal[3] : genius_pal[0]; - for (x = 0; x < 80; x++) - { - dat = genius->vram[addr]; - addr++; + /* We draw the CGA at row 512 */ + if ((genius->displine < 512) || (genius->displine >= 912)) + return; - for (c = 0; c < 8; c++) - { - if (dat & 0x80) - { - ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; - } - dat = dat << 1; - } + addr = 0x18000 + 80 * ((genius->displine - 512) >> 2); + if ((genius->displine - 512) & 2) + addr += 0x2000; + + for (x = 0; x < 80; x++) { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) { + if (dat & 0x80) + buffer32->line[genius->displine][(x << 3) + c] = ink_f; + else + buffer32->line[genius->displine][(x << 3) + c] = ink_b; + + dat = dat << 1; } + } } + /* Draw a line in the native high-resolution mode */ -void genius_hiresline(genius_t *genius) +void +genius_hiresline(genius_t *genius) { - int x, c; - uint32_t dat; - uint32_t ink; - uint32_t addr; - - ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; - /* The first 512 lines live at A0000 */ - if (genius->displine < 512) - { - addr = 128 * genius->displine; - } - else /* The second 496 live at B8000 */ - { - addr = 0x18000 + 128 * (genius->displine - 512); - } + int x, c; + uint32_t dat, addr; + uint8_t ink_f, ink_b; - for (x = 0; x < 91; x++) - { - dat = genius->vram[addr]; - addr++; + ink_f = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; + ink_b = (genius->genius_control & 0x20) ? genius_pal[3] : genius_pal[0]; - for (c = 0; c < 8; c++) - { - if (dat & 0x80) - { - ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; - } - dat = dat << 1; - } + /* The first 512 lines live at A0000 */ + if (genius->displine < 512) + addr = 128 * genius->displine; + else /* The second 496 live at B8000 */ + addr = 0x18000 + (128 * (genius->displine - 512)); + + for (x = 0; x < 91; x++) { + dat = genius->vram[addr + x]; + + for (c = 0; c < 8; c++) { + if (dat & 0x80) + buffer32->line[genius->displine][(x << 3) + c] = ink_f; + else + buffer32->line[genius->displine][(x << 3) + c] = ink_b; + + dat = dat << 1; } + } } -void genius_poll(void *p) -{ - genius_t *genius = (genius_t *)p; - int x; - uint8_t background; - if (!genius->linepos) - { - genius->vidtime += genius->dispofftime; - genius->cga_stat |= 1; - genius->mda_stat |= 1; - genius->linepos = 1; - if (genius->dispon) - { - if (genius->genius_control & 0x20) - { - background = genius_pal[3]; - } - else - { - background = genius_pal[0]; - } - if (genius->displine == 0) - { - video_wait_for_buffer(); - } - /* Start off with a blank line */ - for (x = 0; x < GENIUS_XSIZE; x++) - { - ((uint32_t *)buffer32->line[genius->displine])[x] = background; - } - /* If graphics display enabled, draw graphics on top - * of the blanked line */ - if (genius->cga_ctrl & 8) - { - if (genius->genius_control & 8) - { +void +genius_poll(void *p) +{ + genius_t *genius = (genius_t *)p; + int x; + uint8_t background; + + if (!genius->linepos) { + timer_advance_u64(&genius->timer, genius->dispofftime); + genius->cga_stat |= 1; + genius->mda_stat |= 1; + genius->linepos = 1; + + if (genius->dispon) { + if (genius->genius_control & 0x20) + background = genius_pal[3]; + else + background = genius_pal[0]; + + if (genius->displine == 0) + video_wait_for_buffer(); + + /* Start off with a blank line */ + for (x = 0; x < GENIUS_XSIZE; x++) + buffer32->line[genius->displine][x] = background; + + /* If graphics display enabled, draw graphics on top + * of the blanked line */ + if (genius->cga_ctrl & 8) { + if (((genius->genius_control & 0x11) == 0x00) || (genius->genius_control & 0x08)) + genius_cgaline(genius); + else if ((genius->genius_control & 0x11) == 0x01) + genius_hiresline(genius); + else { + if (genius->cga_ctrl & 2) genius_cgaline(genius); - } - else - { - genius_hiresline(genius); + else { + if (genius->cga_ctrl & 1) + genius_textline(genius, background, 0, 1); + else + genius_textline(genius, background, 0, 0); } } - /* If MDA display is enabled, draw MDA text on top - * of the lot */ - if (genius->mda_ctrl & 8) - { - genius_textline(genius, background); - } - } - genius->displine++; - /* Hardcode a fixed refresh rate and VSYNC timing */ - if (genius->displine == 1008) /* Start of VSYNC */ - { - genius->cga_stat |= 8; - genius->dispon = 0; - } - if (genius->displine == 1040) /* End of VSYNC */ - { - genius->displine = 0; - genius->cga_stat &= ~8; - genius->dispon = 1; } - } - else - { - if (genius->dispon) - { - genius->cga_stat &= ~1; - genius->mda_stat &= ~1; - } - genius->vidtime += genius->dispontime; - genius->linepos = 0; - if (genius->displine == 1008) - { + /* If MDA display is enabled, draw MDA text on top + * of the lot */ + if (genius->mda_ctrl & 8) + genius_textline(genius, background, 1, 1); + } + genius->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (genius->displine == 1008) { /* Start of VSYNC */ + genius->cga_stat |= 8; + genius->mda_stat |= 8; + genius->dispon = 0; + } + if (genius->displine == 1040) { /* End of VSYNC */ + genius->displine = 0; + genius->cga_stat &= ~8; + genius->mda_stat &= ~8; + genius->dispon = 1; + } + } else { + if (genius->dispon) { + genius->cga_stat &= ~1; + genius->mda_stat &= ~1; + } + timer_advance_u64(&genius->timer, genius->dispontime); + genius->linepos = 0; + + if (genius->displine == 1008) { /* Hardcode GENIUS_XSIZE * GENIUS_YSIZE window size */ - if (GENIUS_XSIZE != xsize || GENIUS_YSIZE != ysize) - { - xsize = GENIUS_XSIZE; - ysize = GENIUS_YSIZE; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, ysize); + if (GENIUS_XSIZE != xsize || GENIUS_YSIZE != ysize) { + xsize = GENIUS_XSIZE; + ysize = GENIUS_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); - if (video_force_resize_get()) - video_force_resize_set(0); - } - video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + if (video_force_resize_get()) + video_force_resize_set(0); + } - frames++; - /* Fixed 728x1008 resolution */ - video_res_x = GENIUS_XSIZE; - video_res_y = GENIUS_YSIZE; - video_bpp = 1; - genius->blink++; - } - } + video_blit_memtoscreen_8(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 728x1008 resolution */ + video_res_x = GENIUS_XSIZE; + video_res_y = GENIUS_YSIZE; + video_bpp = 1; + genius->blink++; + } + } } -void *genius_init(const device_t *info) + +void +*genius_init(const device_t *info) { - int c; - genius_t *genius = malloc(sizeof(genius_t)); - memset(genius, 0, sizeof(genius_t)); + int c; + genius_t *genius = malloc(sizeof(genius_t)); - /* 160k video RAM */ - genius->vram = malloc(0x28000); + memset(genius, 0, sizeof(genius_t)); - loadfont(BIOS_ROM_PATH, 4); + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_genius); - timer_add(genius_poll, &genius->vidtime, TIMER_ALWAYS_ENABLED, genius); + /* 160k video RAM */ + genius->vram = malloc(0x28000); - /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in - * high-resolution modes) */ - mem_mapping_add(&genius->mapping, 0xb0000, 0x10000, genius_read, NULL, NULL, genius_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, genius); - /* Respond to both MDA and CGA I/O ports */ - 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); + loadfont(BIOS_ROM_PATH, 4); - 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); + timer_add(&genius->timer, genius_poll, genius, 1); - /* 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] = 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] = 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]; + /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in + * high-resolution modes) */ + mem_mapping_add(&genius->mapping, 0xb0000, 0x10000, genius_read, NULL, NULL, genius_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, genius); + + /* Respond to both MDA and CGA I/O ports */ + 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] = 0 + 16; /* 0 */ + genius_pal[1] = 8 + 16; /* 8 */ + genius_pal[2] = 7 + 16; /* 7 */ + genius_pal[3] = 15 + 16; /* F */ + + /* 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++) { + mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = genius_pal[0]; + if (c & 8) mdaattr[c][0][1] = genius_pal[3]; + else mdaattr[c][0][1] = genius_pal[2]; + } + mdaattr[0x70][0][1] = genius_pal[0]; + mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = genius_pal[3]; + mdaattr[0xF0][0][1] = genius_pal[0]; + mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = genius_pal[3]; + mdaattr[0x78][0][1] = genius_pal[2]; + mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = genius_pal[3]; + mdaattr[0xF8][0][1] = genius_pal[2]; + mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = genius_pal[3]; + mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = genius_pal[0]; + mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = genius_pal[0]; + mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = genius_pal[0]; + mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = genius_pal[0]; /* Start off in 80x25 text mode */ - genius->cga_stat = 0xF4; - genius->genius_mode = 2; - genius->enabled = 1; - genius->genius_charh = 0x90; /* Native character height register */ - return genius; + genius->cga_stat = 0xF4; + genius->genius_mode = 2; + genius->enabled = 1; + genius->genius_charh = 0x90; /* Native character height register */ + genius->genius_control |= 0x10; + return genius; } -void genius_close(void *p) + +void +genius_close(void *p) { - genius_t *genius = (genius_t *)p; + genius_t *genius = (genius_t *)p; - free(genius->vram); - free(genius); + free(genius->vram); + free(genius); } -static int genius_available() + +static int +genius_available() { - return rom_present(BIOS_ROM_PATH); + return rom_present(BIOS_ROM_PATH); } -void genius_speed_changed(void *p) + +void +genius_speed_changed(void *p) { - genius_t *genius = (genius_t *)p; - - genius_recalctimings(genius); + genius_t *genius = (genius_t *)p; + + genius_recalctimings(genius); } + const device_t genius_device = { "Genius VHR", diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 0724fb433..fd3c85284 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -8,420 +8,556 @@ * * Hercules emulation. * - * Version: @(#)vid_hercules.c 1.0.11 2018/04/29 + * Version: @(#)vid_hercules.c 1.0.17 2019/02/07 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include -#include #include +#include #include #include "../86box.h" +#include "../cpu/cpu.h" #include "../mem.h" #include "../rom.h" #include "../io.h" +#include "../timer.h" #include "../lpt.h" #include "../pit.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_hercules.h" -typedef struct hercules_t -{ - mem_mapping_t mapping; - - uint8_t crtc[32]; - int crtcreg; +typedef struct { + mem_mapping_t mapping; - uint8_t ctrl, ctrl2, stat; + uint8_t crtc[32]; + int crtcreg; - int64_t dispontime, dispofftime; - int64_t vidtime; - - int firstline, lastline; + uint8_t ctrl, + ctrl2, + stat; - int linepos, displine; - int vc, sc; - uint16_t ma, maback; - int con, coff, cursoron; - int dispon, blink; - int64_t vsynctime; - int vadj; + uint64_t dispontime, + dispofftime; + pc_timer_t timer; - uint8_t *vram; + int firstline, + lastline; + + int linepos, + displine; + int vc, + sc; + uint16_t ma, + maback; + int con, coff, + cursoron; + int dispon, + blink; + int vsynctime; + int vadj; + + int cols[256][2][2]; + + uint8_t *vram; } hercules_t; -static int mdacols[256][2][2]; - -void hercules_recalctimings(hercules_t *hercules); -void hercules_write(uint32_t addr, uint8_t val, void *p); -uint8_t hercules_read(uint32_t addr, void *p); +static video_timings_t timing_hercules = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; -void hercules_out(uint16_t addr, uint8_t val, void *p) +static void +recalc_timings(hercules_t *dev) { - hercules_t *hercules = (hercules_t *)p; - switch (addr) - { - case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: - hercules->crtcreg = val & 31; - return; - case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: - hercules->crtc[hercules->crtcreg] = val; - if (hercules->crtc[10] == 6 && hercules->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ - { - hercules->crtc[10] = 0xb; - hercules->crtc[11] = 0xc; - } - hercules_recalctimings(hercules); - return; - case 0x3b8: - hercules->ctrl = val; - return; - case 0x3bf: - hercules->ctrl2 = val; - if (val & 2) - mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x10000); - else - mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x08000); - return; - } -} + double disptime; + double _dispontime, _dispofftime; -uint8_t hercules_in(uint16_t addr, void *p) -{ - hercules_t *hercules = (hercules_t *)p; - switch (addr) - { - case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: - return hercules->crtcreg; - case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: - return hercules->crtc[hercules->crtcreg]; - case 0x3ba: - return (hercules->stat & 0xf) | ((hercules->stat & 8) << 4); - } - return 0xff; -} + disptime = dev->crtc[0] + 1; + _dispontime = dev->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= HERCCONST; + _dispofftime *= HERCCONST; -void hercules_write(uint32_t addr, uint8_t val, void *p) -{ - hercules_t *hercules = (hercules_t *)p; - egawrites++; - hercules->vram[addr & 0xffff] = val; -} - -uint8_t hercules_read(uint32_t addr, void *p) -{ - hercules_t *hercules = (hercules_t *)p; - egareads++; - return hercules->vram[addr & 0xffff]; -} - -void hercules_recalctimings(hercules_t *hercules) -{ - double disptime; - double _dispontime, _dispofftime; - disptime = hercules->crtc[0] + 1; - _dispontime = hercules->crtc[1]; - _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; - hercules->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - hercules->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); -} - -void hercules_poll(void *p) -{ - hercules_t *hercules = (hercules_t *)p; - uint16_t ca = (hercules->crtc[15] | (hercules->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x, c; - int oldvc; - uint8_t chr, attr; - uint16_t dat; - int oldsc; - int blink; - if (!hercules->linepos) - { - hercules->vidtime += hercules->dispofftime; - hercules->stat |= 1; - hercules->linepos = 1; - oldsc = hercules->sc; - if ((hercules->crtc[8] & 3) == 3) - hercules->sc = (hercules->sc << 1) & 7; - if (hercules->dispon) - { - if (hercules->displine < hercules->firstline) - { - hercules->firstline = hercules->displine; - video_wait_for_buffer(); - } - hercules->lastline = hercules->displine; - if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) - { - ca = (hercules->sc & 3) * 0x2000; - if ((hercules->ctrl & 0x80) && (hercules->ctrl2 & 2)) - ca += 0x8000; -// printf("Draw herc %04X\n",ca); - for (x = 0; x < hercules->crtc[1]; x++) - { - dat = (hercules->vram[((hercules->ma << 1) & 0x1fff) + ca] << 8) | hercules->vram[((hercules->ma << 1) & 0x1fff) + ca + 1]; - hercules->ma++; - for (c = 0; c < 16; c++) - buffer->line[hercules->displine][(x << 4) + c] = (dat & (32768 >> c)) ? 7 : 0; - } - } - else - { - for (x = 0; x < hercules->crtc[1]; x++) - { - chr = hercules->vram[(hercules->ma << 1) & 0xfff]; - attr = hercules->vram[((hercules->ma << 1) + 1) & 0xfff]; - drawcursor = ((hercules->ma == ca) && hercules->con && hercules->cursoron); - blink = ((hercules->blink & 16) && (hercules->ctrl & 0x20) && (attr & 0x80) && !drawcursor); - if (hercules->sc == 12 && ((attr & 7) == 1)) - { - for (c = 0; c < 9; c++) - buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][1]; - } - else - { - for (c = 0; c < 8; c++) - buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][hercules->sc] & (1 << (c ^ 7))) ? 1 : 0]; - if ((chr & ~0x1f) == 0xc0) buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][hercules->sc] & 1]; - else buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][0]; - } - hercules->ma++; - if (drawcursor) - { - for (c = 0; c < 9; c++) - buffer->line[hercules->displine][(x * 9) + c] ^= mdacols[attr][0][1]; - } - } - } - } - hercules->sc = oldsc; - if (hercules->vc == hercules->crtc[7] && !hercules->sc) - { - hercules->stat |= 8; -// printf("VSYNC on %i %i\n",vc,sc); - } - hercules->displine++; - if (hercules->displine >= 500) - hercules->displine = 0; - } - else - { - hercules->vidtime += hercules->dispontime; - if (hercules->dispon) - hercules->stat &= ~1; - hercules->linepos = 0; - if (hercules->vsynctime) - { - hercules->vsynctime--; - if (!hercules->vsynctime) - { - hercules->stat &= ~8; -// printf("VSYNC off %i %i\n",vc,sc); - } - } - if (hercules->sc == (hercules->crtc[11] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[11] & 31) >> 1))) - { - hercules->con = 0; - hercules->coff = 1; - } - if (hercules->vadj) - { - hercules->sc++; - hercules->sc &= 31; - hercules->ma = hercules->maback; - hercules->vadj--; - if (!hercules->vadj) - { - hercules->dispon = 1; - hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; - hercules->sc = 0; - } - } - else if (hercules->sc == hercules->crtc[9] || ((hercules->crtc[8] & 3) == 3 && hercules->sc == (hercules->crtc[9] >> 1))) - { - hercules->maback = hercules->ma; - hercules->sc = 0; - oldvc = hercules->vc; - hercules->vc++; - hercules->vc &= 127; - if (hercules->vc == hercules->crtc[6]) - hercules->dispon = 0; - if (oldvc == hercules->crtc[4]) - { -// printf("Display over at %i\n",displine); - hercules->vc = 0; - hercules->vadj = hercules->crtc[5]; - if (!hercules->vadj) hercules->dispon=1; - if (!hercules->vadj) hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; - if ((hercules->crtc[10] & 0x60) == 0x20) hercules->cursoron = 0; - else hercules->cursoron = hercules->blink & 16; - } - if (hercules->vc == hercules->crtc[7]) - { - hercules->dispon = 0; - hercules->displine = 0; - hercules->vsynctime = 16;//(crtcm[3]>>4)+1; - if (hercules->crtc[7]) - { -// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); - if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) x = hercules->crtc[1] << 4; - else x = hercules->crtc[1] * 9; - hercules->lastline++; - if ((x != xsize) || ((hercules->lastline - hercules->firstline) != ysize) || video_force_resize_get()) - { - xsize = x; - ysize = hercules->lastline - hercules->firstline; -// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, ysize); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - video_blit_memtoscreen_8(0, hercules->firstline, 0, ysize, xsize, ysize); - frames++; - if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) - { - video_res_x = hercules->crtc[1] * 16; - video_res_y = hercules->crtc[6] * 4; - video_bpp = 1; - } - else - { - video_res_x = hercules->crtc[1]; - video_res_y = hercules->crtc[6]; - video_bpp = 0; - } - } - hercules->firstline = 1000; - hercules->lastline = 0; - hercules->blink++; - } - } - else - { - hercules->sc++; - hercules->sc &= 31; - hercules->ma = hercules->maback; - } - if ((hercules->sc == (hercules->crtc[10] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[10] & 31) >> 1)))) - { - hercules->con = 1; -// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); - } - } + dev->dispontime = (uint64_t)(_dispontime); + dev->dispofftime = (uint64_t)(_dispofftime); } -void *hercules_init(const device_t *info) +static uint8_t crtcmask[32] = { - int c; - hercules_t *hercules = malloc(sizeof(hercules_t)); - memset(hercules, 0, sizeof(hercules_t)); + 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 +}; - hercules->vram = malloc(0x10000); +static void +hercules_out(uint16_t addr, uint8_t val, void *priv) +{ + hercules_t *dev = (hercules_t *)priv; + uint8_t old; - 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, MEM_MAPPING_EXTERNAL, hercules); - io_sethandler(0x03b0, 0x0010, hercules_in, NULL, NULL, hercules_out, NULL, NULL, hercules); + switch (addr) { + case 0x03b0: + case 0x03b2: + case 0x03b4: + case 0x03b6: + dev->crtcreg = val & 31; + break; - for (c = 0; c < 256; c++) - { - mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; - if (c & 8) mdacols[c][0][1] = 15 + 16; - else mdacols[c][0][1] = 7 + 16; - } - mdacols[0x70][0][1] = 16; - mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; - mdacols[0xF0][0][1] = 16; - mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; - mdacols[0x78][0][1] = 16 + 7; - mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; - mdacols[0xF8][0][1] = 16 + 7; - mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; - mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; - mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; - mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; - mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + case 0x03b1: + case 0x03b3: + case 0x03b5: + case 0x03b7: + old = dev->crtc[dev->crtcreg]; + dev->crtc[dev->crtcreg] = val & crtcmask[dev->crtcreg]; - overscan_x = overscan_y = 0; + /* + * Fix for Generic Turbo XT BIOS, which + * sets up cursor registers wrong. + */ + if (dev->crtc[10] == 6 && dev->crtc[11] == 7) { + dev->crtc[10] = 0xb; + dev->crtc[11] = 0xc; + } +#if 0 + if (old ^ val) + recalc_timings(dev); +#else + if (old != val) { + if ((dev->crtcreg < 0xe) || (dev->crtcreg > 0x10)) { + fullchange = changeframecount; + recalc_timings(dev); + } + } +#endif + break; - cga_palette = device_get_config_int("rgb_type") << 1; - if (cga_palette > 6) - { - cga_palette = 0; + case 0x03b8: + old = dev->ctrl; + if (!(dev->ctrl2 & 0x01) && !(val & 0x02)) + val = (val & 0xfd) | (dev->ctrl & 0x02); + if (!(dev->ctrl2 & 0x02) && !(val & 0x80)) + val = (val & 0x7f) | (dev->ctrl & 0x80); + dev->ctrl = val; + if (old ^ val) + recalc_timings(dev); + break; + + case 0x03bf: + dev->ctrl2 = val; + if (val & 0x02) + mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x08000); + break; + + default: + break; + } +} + + +static uint8_t +hercules_in(uint16_t addr, void *priv) +{ + hercules_t *dev = (hercules_t *)priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x03b0: + case 0x03b2: + case 0x03b4: + case 0x03b6: + ret = dev->crtcreg; + break; + + case 0x03b1: + case 0x03b3: + case 0x03b5: + case 0x03b7: + ret = dev->crtc[dev->crtcreg]; + break; + + case 0x03ba: + ret = 0x72; /* Hercules ident */ +#if 0 + if (dev->stat & 0x08) + ret |= 0x88; +#else + if (dev->stat & 0x08) + ret |= 0x80; +#endif + if ((dev->stat & 0x09) == 0x01) + ret |= (dev->stat & 0x01); + if ((ret & 0x81) == 0x80) + ret |= 0x08; + break; + + default: + break; + } + + return(ret); +} + + +static void +hercules_waitstates(void *p) +{ + int ws_array[16] = {3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8}; + int ws; + + ws = ws_array[cycles & 0xf]; + sub_cycles(ws); +} + + +static void +hercules_write(uint32_t addr, uint8_t val, void *priv) +{ + hercules_t *dev = (hercules_t *)priv; + + if (dev->ctrl2 & 0x01) + dev->vram[addr & 0xffff] = val; + else + dev->vram[addr & 0x0fff] = val; + + hercules_waitstates(dev); +} + + +static uint8_t +hercules_read(uint32_t addr, void *priv) +{ + hercules_t *dev = (hercules_t *)priv; + + if (dev->ctrl2 & 0x01) + return(dev->vram[addr & 0xffff]); + else + return(dev->vram[addr & 0x0fff]); + + hercules_waitstates(dev); +} + + +static void +hercules_poll(void *priv) +{ + hercules_t *dev = (hercules_t *)priv; + uint8_t chr, attr; + uint16_t ca, dat; + int oldsc, blink; + int x, c, oldvc; + int drawcursor; + + ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; + + if (! dev->linepos) { + timer_advance_u64(&dev->timer, dev->dispofftime); + dev->stat |= 1; + dev->linepos = 1; + oldsc = dev->sc; + + if ((dev->crtc[8] & 3) == 3) + dev->sc = (dev->sc << 1) & 7; + + if (dev->dispon) { + if (dev->displine < dev->firstline) { + dev->firstline = dev->displine; + video_wait_for_buffer(); + } + dev->lastline = dev->displine; + + // if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) { + if (dev->ctrl & 2) { + ca = (dev->sc & 3) * 0x2000; + // if ((dev->ctrl & 0x80) && (dev->ctrl2 & 2)) + if (dev->ctrl & 0x80) + ca += 0x8000; + + for (x = 0; x < dev->crtc[1]; x++) { + if (dev->ctrl & 8) + // dat = (dev->vram[((dev->ma << 1) & 0x1fff) + ca] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 1]; + dat = (dev->vram[((dev->ma << 1) & 0x1fff) + ca] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 1]; + else + dat = 0; + dev->ma++; + for (c = 0; c < 16; c++) + buffer32->line[dev->displine][(x << 4) + c] = (dat & (32768 >> c)) ? 7 : 0; + for (c = 0; c < 16; c += 8) + video_blend((x << 4) + c, dev->displine); + } + } else { + for (x = 0; x < dev->crtc[1]; x++) { + if (dev->ctrl & 8) { + chr = dev->vram[(dev->ma << 1) & 0xfff]; + attr = dev->vram[((dev->ma << 1) + 1) & 0xfff]; + } else + chr = attr = 0; + drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + blink = ((dev->blink & 16) && (dev->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + + if (dev->sc == 12 && ((attr & 7) == 1)) { + for (c = 0; c < 9; c++) + buffer32->line[dev->displine][(x * 9) + c] = dev->cols[attr][blink][1]; + } else { + for (c = 0; c < 8; c++) + buffer32->line[dev->displine][(x * 9) + c] = dev->cols[attr][blink][(fontdatm[chr][dev->sc] & (1 << (c ^ 7))) ? 1 : 0]; + + if ((chr & ~0x1f) == 0xc0) + buffer32->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][fontdatm[chr][dev->sc] & 1]; + else + buffer32->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][0]; + } + dev->ma++; + + if (drawcursor) { + for (c = 0; c < 9; c++) + buffer32->line[dev->displine][(x * 9) + c] ^= dev->cols[attr][0][1]; + } + } + } } - cgapal_rebuild(); + dev->sc = oldsc; - lpt3_init(0x3BC); + if (dev->vc == dev->crtc[7] && !dev->sc) + dev->stat |= 8; + dev->displine++; + if (dev->displine >= 500) + dev->displine = 0; + } else { + timer_advance_u64(&dev->timer, dev->dispontime); - return hercules; + dev->linepos = 0; + if (dev->vsynctime) { + dev->vsynctime--; + if (! dev->vsynctime) + dev->stat &= ~8; + } + + if (dev->sc == (dev->crtc[11] & 31) || + ((dev->crtc[8] & 3)==3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { + dev->con = 0; + dev->coff = 1; + } + + if (dev->vadj) { + dev->sc++; + dev->sc &= 31; + dev->ma = dev->maback; + + dev->vadj--; + if (! dev->vadj) { + dev->dispon = 1; + dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->sc = 0; + } + } else if (dev->sc == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) { + dev->maback = dev->ma; + dev->sc = 0; + oldvc = dev->vc; + dev->vc++; + dev->vc &= 127; + if (dev->vc == dev->crtc[6]) + dev->dispon = 0; + + if (oldvc == dev->crtc[4]) { + dev->vc = 0; + dev->vadj = dev->crtc[5]; + if (! dev->vadj) + dev->dispon = 1; + if (! dev->vadj) + dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + if ((dev->crtc[10] & 0x60) == 0x20) + dev->cursoron = 0; + else + dev->cursoron = dev->blink & 16; + } + + if (dev->vc == dev->crtc[7]) { + dev->dispon = 0; + dev->displine = 0; + dev->vsynctime = 16;//(crtcm[3]>>4)+1; + if (dev->crtc[7]) { + // if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) + if (dev->ctrl & 2) + x = dev->crtc[1] << 4; + else + x = dev->crtc[1] * 9; + + dev->lastline++; + if ((dev->ctrl & 8) && x && (dev->lastline - dev->firstline) && + ((x != xsize) || ((dev->lastline - dev->firstline) != ysize) || video_force_resize_get())) { + xsize = x; + ysize = dev->lastline - dev->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + video_blit_memtoscreen_8(0, dev->firstline, 0, ysize, xsize, ysize); + frames++; + if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) { + video_res_x = dev->crtc[1] * 16; + video_res_y = dev->crtc[6] * 4; + video_bpp = 1; + } else { + video_res_x = dev->crtc[1]; + video_res_y = dev->crtc[6]; + video_bpp = 0; + } + } + dev->firstline = 1000; + dev->lastline = 0; + dev->blink++; + } + } else { + dev->sc++; + dev->sc &= 31; + dev->ma = dev->maback; + } + + if (dev->dispon) + dev->stat &= ~1; + + if ((dev->sc == (dev->crtc[10] & 31) || + ((dev->crtc[8] & 3)==3 && dev->sc == ((dev->crtc[10] & 31) >> 1)))) + dev->con = 1; + } } -void hercules_close(void *p) -{ - hercules_t *hercules = (hercules_t *)p; - free(hercules->vram); - free(hercules); +static void * +hercules_init(const device_t *info) +{ + hercules_t *dev; + int c; + + dev = (hercules_t *)malloc(sizeof(hercules_t)); + memset(dev, 0x00, sizeof(hercules_t)); + + dev->vram = (uint8_t *)malloc(0x10000); + + timer_add(&dev->timer, hercules_poll, dev, 1); + + mem_mapping_add(&dev->mapping, 0xb0000, 0x10000, + hercules_read,NULL,NULL, hercules_write,NULL,NULL, + dev->vram, MEM_MAPPING_EXTERNAL, dev); + + io_sethandler(0x03b0, 16, + hercules_in,NULL,NULL, hercules_out,NULL,NULL, dev); + + for (c = 0; c < 256; c++) { + dev->cols[c][0][0] = dev->cols[c][1][0] = dev->cols[c][1][1] = 16; + + if (c & 0x08) + dev->cols[c][0][1] = 15 + 16; + else + dev->cols[c][0][1] = 7 + 16; + } + dev->cols[0x70][0][1] = 16; + dev->cols[0x70][0][0] = dev->cols[0x70][1][0] = + dev->cols[0x70][1][1] = 16 + 15; + dev->cols[0xF0][0][1] = 16; + dev->cols[0xF0][0][0] = dev->cols[0xF0][1][0] = + dev->cols[0xF0][1][1] = 16 + 15; + dev->cols[0x78][0][1] = 16 + 7; + dev->cols[0x78][0][0] = dev->cols[0x78][1][0] = + dev->cols[0x78][1][1] = 16 + 15; + dev->cols[0xF8][0][1] = 16 + 7; + dev->cols[0xF8][0][0] = dev->cols[0xF8][1][0] = + dev->cols[0xF8][1][1] = 16 + 15; + dev->cols[0x00][0][1] = dev->cols[0x00][1][1] = 16; + dev->cols[0x08][0][1] = dev->cols[0x08][1][1] = 16; + dev->cols[0x80][0][1] = dev->cols[0x80][1][1] = 16; + dev->cols[0x88][0][1] = dev->cols[0x88][1][1] = 16; + + overscan_x = overscan_y = 0; + + cga_palette = device_get_config_int("rgb_type") << 1; + if (cga_palette > 6) + cga_palette = 0; + cgapal_rebuild(); + + herc_blend = device_get_config_int("blend"); + + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_hercules); + + /* Force the LPT3 port to be enabled. */ + lpt3_init(0x3BC); + + return(dev); } -void hercules_speed_changed(void *p) + +static void +hercules_close(void *priv) { - hercules_t *hercules = (hercules_t *)p; - - hercules_recalctimings(hercules); + hercules_t *dev = (hercules_t *)priv; + + if (!dev) + return; + + if (dev->vram) + free(dev->vram); + + free(dev); } -static const device_config_t hercules_config[] = + +static void +speed_changed(void *priv) { - { - "rgb_type", "Display type", CONFIG_SELECTION, "", 0, - { - { - "Default", 0 - }, - { - "Green", 1 - }, - { - "Amber", 2 - }, - { - "Gray", 3 - }, - { - "" - } - } - }, - { - "", "", -1 - } + hercules_t *dev = (hercules_t *)priv; + + recalc_timings(dev); +} + + +static const device_config_t hercules_config[] = { + { + "rgb_type", "Display type", CONFIG_SELECTION, "", 0, + { + { + "Default", 0 + }, + { + "Green", 1 + }, + { + "Amber", 2 + }, + { + "Gray", 3 + }, + { + "" + } + } + }, + { + "blend", "Blend", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } }; - -const device_t hercules_device = -{ - "Hercules", - DEVICE_ISA, 0, - hercules_init, hercules_close, NULL, - NULL, - hercules_speed_changed, - NULL, - hercules_config +const device_t hercules_device = { + "Hercules", + DEVICE_ISA, + 0, + hercules_init, hercules_close, NULL, + NULL, + speed_changed, + NULL, + hercules_config }; diff --git a/src/video/vid_herculesplus.c b/src/video/vid_herculesplus.c index 1bf4118fc..2a4497bce 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_herculesplus.c @@ -6,9 +6,9 @@ * * This file is part of the 86Box distribution. * - * Hercules InColor emulation. + * Hercules Plus emulation. * - * Version: @(#)vid_herculesplus.c 1.0.9 2018/04/29 + * Version: @(#)vid_herculesplus.c 1.0.15 2019/02/07 * * Authors: Sarah Walker, * Miran Grca, @@ -18,29 +18,28 @@ */ #include #include -#include #include +#include #include #include "../86box.h" #include "../io.h" #include "../lpt.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_herculesplus.h" /* extended CRTC registers */ - #define HERCULESPLUS_CRTC_XMODE 20 /* xMode register */ #define HERCULESPLUS_CRTC_UNDER 21 /* Underline */ #define HERCULESPLUS_CRTC_OVER 22 /* Overstrike */ /* character width */ -#define HERCULESPLUS_CW ((herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) ? 8 : 9) +#define HERCULESPLUS_CW ((dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) ? 8 : 9) /* mode control register */ #define HERCULESPLUS_CTRL_GRAPH 0x02 @@ -63,677 +62,675 @@ #define HERCULESPLUS_XMODE_RAMFONT 0x01 #define HERCULESPLUS_XMODE_90COL 0x02 -typedef struct herculesplus_t -{ - mem_mapping_t mapping; - - uint8_t crtc[32]; - int crtcreg; - uint8_t ctrl, ctrl2, stat; +typedef struct { + mem_mapping_t mapping; - int64_t dispontime, dispofftime; - int64_t vidtime; - - int firstline, lastline; + uint8_t crtc[32]; + int crtcreg; - int linepos, displine; - int vc, sc; - uint16_t ma, maback; - int con, coff, cursoron; - int dispon, blink; - int64_t vsynctime; - int vadj; + uint8_t ctrl, ctrl2, stat; - uint8_t *vram; + 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; + int vadj; + + int cols[256][2][2]; + + uint8_t *vram; } herculesplus_t; -void herculesplus_recalctimings(herculesplus_t *herculesplus); -void herculesplus_write(uint32_t addr, uint8_t val, void *p); -uint8_t herculesplus_read(uint32_t addr, void *p); +static video_timings_t timing_herculesplus = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; -static int mdacols[256][2][2]; -void herculesplus_out(uint16_t addr, uint8_t val, void *p) +static void +recalc_timings(herculesplus_t *dev) { - herculesplus_t *herculesplus = (herculesplus_t *)p; - switch (addr) - { - case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: - herculesplus->crtcreg = val & 31; - return; - case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: - if (herculesplus->crtcreg > 22) return; - herculesplus->crtc[herculesplus->crtcreg] = val; - if (herculesplus->crtc[10] == 6 && herculesplus->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ - { - herculesplus->crtc[10] = 0xb; - herculesplus->crtc[11] = 0xc; - } - herculesplus_recalctimings(herculesplus); - return; - case 0x3b8: - herculesplus->ctrl = val; - return; - case 0x3bf: - herculesplus->ctrl2 = val; - if (val & 2) - mem_mapping_set_addr(&herculesplus->mapping, 0xb0000, 0x10000); - else - mem_mapping_set_addr(&herculesplus->mapping, 0xb0000, 0x08000); - return; - } -} + double disptime; + double _dispontime, _dispofftime; -uint8_t herculesplus_in(uint16_t addr, void *p) -{ - herculesplus_t *herculesplus = (herculesplus_t *)p; - switch (addr) - { - case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: - return herculesplus->crtcreg; - case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: - if (herculesplus->crtcreg > 22) return 0xff; - return herculesplus->crtc[herculesplus->crtcreg]; - case 0x3ba: - /* 0x50: InColor card identity */ - return (herculesplus->stat & 0xf) | ((herculesplus->stat & 8) << 4) | 0x10; - } - return 0xff; -} + disptime = dev->crtc[0] + 1; + _dispontime = dev->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= HERCCONST; + _dispofftime *= HERCCONST; -void herculesplus_write(uint32_t addr, uint8_t val, void *p) -{ - herculesplus_t *herculesplus = (herculesplus_t *)p; - - egawrites++; - - addr &= 0xFFFF; - - herculesplus->vram[addr] = val; -} - -uint8_t herculesplus_read(uint32_t addr, void *p) -{ - herculesplus_t *herculesplus = (herculesplus_t *)p; - - egareads++; - - addr &= 0xFFFF; - return herculesplus->vram[addr]; + dev->dispontime = (uint64_t)(_dispontime); + dev->dispofftime = (uint64_t)(_dispofftime); } - -void herculesplus_recalctimings(herculesplus_t *herculesplus) +static void +herculesplus_out(uint16_t port, uint8_t val, void *priv) { - double disptime; - double _dispontime, _dispofftime; - disptime = herculesplus->crtc[0] + 1; - _dispontime = herculesplus->crtc[1]; - _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; - herculesplus->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - herculesplus->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); -} + herculesplus_t *dev = (herculesplus_t *)priv; + uint8_t old; + switch (port) { + case 0x3b0: + case 0x3b2: + case 0x3b4: + case 0x3b6: + dev->crtcreg = val & 31; + return; -static void herculesplus_draw_char_rom(herculesplus_t *herculesplus, int x, uint8_t chr, uint8_t attr) -{ - unsigned i; - int elg, blk; - unsigned ull; - unsigned val; - unsigned ifg, ibg; - const unsigned char *fnt; - int cw = HERCULESPLUS_CW; - - blk = 0; - if (herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK) - { - if (attr & 0x80) - { - blk = (herculesplus->blink & 16); + case 0x3b1: + case 0x3b3: + case 0x3b5: + case 0x3b7: + if (dev->crtcreg > 22) return; + old = dev->crtc[dev->crtcreg]; + dev->crtc[dev->crtcreg] = val; + if (dev->crtc[10] == 6 && dev->crtc[11] == 7) { + /*Fix for Generic Turbo XT BIOS, + *which sets up cursor registers wrong*/ + dev->crtc[10] = 0xb; + dev->crtc[11] = 0xc; } - attr &= 0x7f; - } + if (old ^ val) + recalc_timings(dev); + return; - /* MDA-compatible attributes */ - ibg = 0; - ifg = 7; - if ((attr & 0x77) == 0x70) /* Invert */ - { - ifg = 0; - ibg = 7; - } - if (attr & 8) - { - ifg |= 8; /* High intensity FG */ - } - if (attr & 0x80) - { - ibg |= 8; /* High intensity BG */ - } - if ((attr & 0x77) == 0) /* Blank */ - { - ifg = ibg; - } - ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + case 0x3b8: + old = dev->ctrl; + dev->ctrl = val; + if (old ^ val) + recalc_timings(dev); + return; - if (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) - { - elg = 0; - } - else - { - elg = ((chr >= 0xc0) && (chr <= 0xdf)); - } - - fnt = &(fontdatm[chr][herculesplus->sc]); - - if (blk) - { - val = 0x000; /* Blinking, draw all background */ - } - else if (herculesplus->sc == ull) - { - val = 0x1ff; /* Underscore, draw all foreground */ - } - else - { - val = fnt[0] << 1; - - if (elg) - { - val |= (val >> 1) & 1; - } - } - for (i = 0; i < cw; i++) - { - buffer->line[herculesplus->displine][x * cw + i] = (val & 0x100) ? ifg : ibg; - val = val << 1; - } -} - - -static void herculesplus_draw_char_ram4(herculesplus_t *herculesplus, int x, uint8_t chr, uint8_t attr) -{ - unsigned i; - int elg, blk; - unsigned ull; - unsigned val; - unsigned ifg, ibg, cfg; - const unsigned char *fnt; - int cw = HERCULESPLUS_CW; - int blink = herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK; - - blk = 0; - if (blink) - { - if (attr & 0x80) - { - blk = (herculesplus->blink & 16); - } - attr &= 0x7f; - } - - /* MDA-compatible attributes */ - ibg = 0; - ifg = 7; - if ((attr & 0x77) == 0x70) /* Invert */ - { - ifg = 0; - ibg = 7; - } - if (attr & 8) - { - ifg |= 8; /* High intensity FG */ - } - if (attr & 0x80) - { - ibg |= 8; /* High intensity BG */ - } - if ((attr & 0x77) == 0) /* Blank */ - { - ifg = ibg; - } - ull = ((attr & 0x07) == 1) ? 13 : 0xffff; - if (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) - { - elg = 0; - } - else - { - elg = ((chr >= 0xc0) && (chr <= 0xdf)); - } - fnt = herculesplus->vram + 0x4000 + 16 * chr + herculesplus->sc; - - if (blk) - { - /* Blinking, draw all background */ - val = 0x000; - } - else if (herculesplus->sc == ull) - { - /* Underscore, draw all foreground */ - val = 0x1ff; - } - else - { - val = fnt[0x00000] << 1; - - if (elg) - { - val |= (val >> 1) & 1; - } - } - for (i = 0; i < cw; i++) - { - /* Generate pixel colour */ - cfg = 0; - /* cfg = colour of foreground pixels */ - if ((attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ - - buffer->line[herculesplus->displine][x * cw + i] = mdacols[attr][blink][cfg]; - val = val << 1; - } -} - - -static void herculesplus_draw_char_ram48(herculesplus_t *herculesplus, int x, uint8_t chr, uint8_t attr) -{ - unsigned i; - int elg, blk, ul, ol, bld; - unsigned ull, oll, ulc = 0, olc = 0; - unsigned val; - unsigned ibg, cfg; - const unsigned char *fnt; - int cw = HERCULESPLUS_CW; - int blink = herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK; - int font = (attr & 0x0F); - - if (font >= 12) font &= 7; - - blk = 0; - if (blink) - { - if (attr & 0x40) - { - blk = (herculesplus->blink & 16); - } - attr &= 0x7f; - } - /* MDA-compatible attributes */ - if (blink) - { - ibg = (attr & 0x80) ? 8 : 0; - bld = 0; - ol = (attr & 0x20) ? 1 : 0; - ul = (attr & 0x10) ? 1 : 0; - } - else - { - bld = (attr & 0x80) ? 1 : 0; - ibg = (attr & 0x40) ? 0x0F : 0; - ol = (attr & 0x20) ? 1 : 0; - ul = (attr & 0x10) ? 1 : 0; - } - if (ul) - { - ull = herculesplus->crtc[HERCULESPLUS_CRTC_UNDER] & 0x0F; - ulc = (herculesplus->crtc[HERCULESPLUS_CRTC_UNDER] >> 4) & 0x0F; - if (ulc == 0) ulc = 7; - } - else - { - ull = 0xFFFF; - } - if (ol) - { - oll = herculesplus->crtc[HERCULESPLUS_CRTC_OVER] & 0x0F; - olc = (herculesplus->crtc[HERCULESPLUS_CRTC_OVER] >> 4) & 0x0F; - if (olc == 0) olc = 7; - } - else - { - oll = 0xFFFF; - } - - if (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) - { - elg = 0; - } - else - { - elg = ((chr >= 0xc0) && (chr <= 0xdf)); - } - fnt = herculesplus->vram + 0x4000 + 16 * chr + 4096 * font + herculesplus->sc; - - if (blk) - { - /* Blinking, draw all background */ - val = 0x000; - } - else if (herculesplus->sc == ull) - { - /* Underscore, draw all foreground */ - val = 0x1ff; - } - else - { - val = fnt[0x00000] << 1; - - if (elg) - { - val |= (val >> 1) & 1; - } - if (bld) - { - val |= (val >> 1); - } - } - for (i = 0; i < cw; i++) - { - /* Generate pixel colour */ - cfg = val & 0x100; - if (herculesplus->sc == oll) - { - cfg = olc ^ ibg; /* Strikethrough */ - } - else if (herculesplus->sc == ull) - { - cfg = ulc ^ ibg; /* Underline */ - } + case 0x3bf: + dev->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x10000); else - { - cfg |= ibg; - } + mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x08000); + return; + } +} + + +static uint8_t +herculesplus_in(uint16_t port, void *priv) +{ + herculesplus_t *dev = (herculesplus_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x3b0: + case 0x3b2: + case 0x3b4: + case 0x3b6: + ret = dev->crtcreg; + break; + + case 0x3b1: + case 0x3b3: + case 0x3b5: + case 0x3b7: + if (dev->crtcreg <= 22) + ret = dev->crtc[dev->crtcreg]; + break; + + case 0x3ba: + /* 0x50: InColor card identity */ + ret = (dev->stat & 0xf) | ((dev->stat & 8) << 4) | 0x10; + break; + } + + return ret; +} + + +static void +herculesplus_write(uint32_t addr, uint8_t val, void *priv) +{ + herculesplus_t *dev = (herculesplus_t *)priv; + + dev->vram[addr & 0xffff] = val; +} + + +static uint8_t +herculesplus_read(uint32_t addr, void *priv) +{ + herculesplus_t *dev = (herculesplus_t *)priv; + + return dev->vram[addr & 0xffff]; +} + + +static void +draw_char_rom(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) +{ + unsigned ull, val, ifg, ibg; + const uint8_t *fnt; + int i, elg, blk; + int cw = HERCULESPLUS_CW; + + blk = 0; + if (dev->ctrl & HERCULESPLUS_CTRL_BLINK) { + if (attr & 0x80) + blk = (dev->blink & 16); + attr &= 0x7f; + } + + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) { /* Invert */ + ifg = 0; + ibg = 7; + } + if (attr & 8) + ifg |= 8; /* High intensity FG */ + if (attr & 0x80) + ibg |= 8; /* High intensity BG */ + if ((attr & 0x77) == 0) /* Blank */ + ifg = ibg; + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + + if (dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + elg = 0; + else + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + + fnt = &(fontdatm[chr][dev->sc]); + + if (blk) { + val = 0x000; /* Blinking, draw all background */ + } else if (dev->sc == ull) { + val = 0x1ff; /* Underscore, draw all foreground */ + } else { + val = fnt[0] << 1; + + if (elg) + val |= (val >> 1) & 1; + } + + for (i = 0; i < cw; i++) { + buffer32->line[dev->displine][x * cw + i] = (val & 0x100) ? ifg : ibg; + val = val << 1; + } +} + + +static void +draw_char_ram4(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) +{ + unsigned ull, val, ifg, ibg, cfg; + const uint8_t *fnt; + int i, elg, blk; + int cw = HERCULESPLUS_CW; + int blink = dev->ctrl & HERCULESPLUS_CTRL_BLINK; + + blk = 0; + if (blink) { + if (attr & 0x80) + blk = (dev->blink & 16); + attr &= 0x7f; + } + + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) { /* Invert */ + ifg = 0; + ibg = 7; + } + if (attr & 8) + ifg |= 8; /* High intensity FG */ + if (attr & 0x80) + ibg |= 8; /* High intensity BG */ + if ((attr & 0x77) == 0) /* Blank */ + ifg = ibg; + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + if (dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + elg = 0; + else + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + fnt = dev->vram + 0x4000 + 16 * chr + dev->sc; + + if (blk) { + /* Blinking, draw all background */ + val = 0x000; + } else if (dev->sc == ull) { + /* Underscore, draw all foreground */ + val = 0x1ff; + } else { + val = fnt[0x00000] << 1; + + if (elg) + val |= (val >> 1) & 1; + } + + for (i = 0; i < cw; i++) { + /* Generate pixel colour */ + cfg = 0; + + /* cfg = colour of foreground pixels */ + if ((attr & 0x77) == 0) + cfg = ibg; /* 'blank' attribute */ + + buffer32->line[dev->displine][x * cw + i] = dev->cols[attr][blink][cfg]; + val = val << 1; + } +} + + +static void +draw_char_ram48(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) +{ + int i, elg, blk, ul, ol, bld; + unsigned ull, oll, ulc = 0, olc = 0; + unsigned val, ibg, cfg; + const unsigned char *fnt; + int cw = HERCULESPLUS_CW; + int blink = dev->ctrl & HERCULESPLUS_CTRL_BLINK; + int font = (attr & 0x0F); + + if (font >= 12) font &= 7; + + blk = 0; + if (blink) { + if (attr & 0x40) + blk = (dev->blink & 16); + attr &= 0x7f; + } + + /* MDA-compatible attributes */ + if (blink) { + ibg = (attr & 0x80) ? 8 : 0; + bld = 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } else { + bld = (attr & 0x80) ? 1 : 0; + ibg = (attr & 0x40) ? 0x0F : 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + + if (ul) { + ull = dev->crtc[HERCULESPLUS_CRTC_UNDER] & 0x0F; + ulc = (dev->crtc[HERCULESPLUS_CRTC_UNDER] >> 4) & 0x0F; + if (ulc == 0) ulc = 7; + } else { + ull = 0xFFFF; + } + + if (ol) { + oll = dev->crtc[HERCULESPLUS_CRTC_OVER] & 0x0F; + olc = (dev->crtc[HERCULESPLUS_CRTC_OVER] >> 4) & 0x0F; + if (olc == 0) olc = 7; + } else { + oll = 0xFFFF; + } + + if (dev->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + elg = 0; + else + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + fnt = dev->vram + 0x4000 + 16 * chr + 4096 * font + dev->sc; + + if (blk) { /* Blinking, draw all background */ + val = 0x000; + } else if (dev->sc == ull) { + /* Underscore, draw all foreground */ + val = 0x1ff; + } else { + val = fnt[0x00000] << 1; + + if (elg) + val |= (val >> 1) & 1; + if (bld) + val |= (val >> 1); + } + + for (i = 0; i < cw; i++) { + /* Generate pixel colour */ + cfg = val & 0x100; + if (dev->sc == oll) + cfg = olc ^ ibg; /* Strikethrough */ + else if (dev->sc == ull) + cfg = ulc ^ ibg; /* Underline */ + else + cfg |= ibg; - buffer->line[herculesplus->displine][(x * cw) + i] = mdacols[attr][blink][cfg]; - val = val << 1; - } + buffer32->line[dev->displine][(x * cw) + i] = dev->cols[attr][blink][cfg]; + val = val << 1; + } } -static void herculesplus_text_line(herculesplus_t *herculesplus, uint16_t ca) + +static void +text_line(herculesplus_t *dev, uint16_t ca) { - int drawcursor; - int x, c; - uint8_t chr, attr; - uint32_t col; + int drawcursor; + int x, c; + uint8_t chr, attr; + uint32_t col; - for (x = 0; x < herculesplus->crtc[1]; x++) - { - chr = herculesplus->vram[(herculesplus->ma << 1) & 0xfff]; - attr = herculesplus->vram[((herculesplus->ma << 1) + 1) & 0xfff]; + for (x = 0; x < dev->crtc[1]; x++) { + if (dev->ctrl & 8) { + chr = dev->vram[(dev->ma << 1) & 0xfff]; + attr = dev->vram[((dev->ma << 1) + 1) & 0xfff]; + } else + chr = attr = 0; - drawcursor = ((herculesplus->ma == ca) && herculesplus->con && herculesplus->cursoron); + drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); - switch (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & 5) - { - case 0: - case 4: /* ROM font */ - herculesplus_draw_char_rom(herculesplus, x, chr, attr); - break; - case 1: /* 4k RAMfont */ - herculesplus_draw_char_ram4(herculesplus, x, chr, attr); - break; - case 5: /* 48k RAMfont */ - herculesplus_draw_char_ram48(herculesplus, x, chr, attr); - break; + switch (dev->crtc[HERCULESPLUS_CRTC_XMODE] & 5) { + case 0: + case 4: /* ROM font */ + draw_char_rom(dev, x, chr, attr); + break; + case 1: /* 4k RAMfont */ + draw_char_ram4(dev, x, chr, attr); + break; + + case 5: /* 48k RAMfont */ + draw_char_ram48(dev, x, chr, attr); + break; + } + ++dev->ma; + + if (drawcursor) { + int cw = HERCULESPLUS_CW; + + col = dev->cols[attr][0][1]; + for (c = 0; c < cw; c++) + buffer32->line[dev->displine][x * cw + c] = col; + } + } +} + + +static void +graphics_line(herculesplus_t *dev) +{ + uint16_t ca; + int x, c, plane = 0; + uint16_t val; + + /* Graphics mode. */ + ca = (dev->sc & 3) * 0x2000; + if ((dev->ctrl & HERCULESPLUS_CTRL_PAGE1) && (dev->ctrl2 & HERCULESPLUS_CTRL2_PAGE1)) + ca += 0x8000; + + for (x = 0; x < dev->crtc[1]; x++) { + if (dev->ctrl & 8) + val = (dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) + | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + else + val = 0; + + dev->ma++; + for (c = 0; c < 16; c++) { + val >>= 1; + + buffer32->line[dev->displine][(x << 4) + c] = (val & 1) ? 7 : 0; + } + + for (c = 0; c < 16; c += 8) + video_blend((x << 4) + c, dev->displine); + } +} + + +static void +herculesplus_poll(void *priv) +{ + herculesplus_t *dev = (herculesplus_t *)priv; + uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; + int x, oldvc, oldsc; + + if (! dev->linepos) { + timer_advance_u64(&dev->timer, dev->dispofftime); + dev->stat |= 1; + dev->linepos = 1; + oldsc = dev->sc; + if ((dev->crtc[8] & 3) == 3) + dev->sc = (dev->sc << 1) & 7; + if (dev->dispon) { + if (dev->displine < dev->firstline) { + dev->firstline = dev->displine; + video_wait_for_buffer(); } - ++herculesplus->ma; - if (drawcursor) - { - int cw = HERCULESPLUS_CW; + dev->lastline = dev->displine; + if ((dev->ctrl & HERCULESPLUS_CTRL_GRAPH) && (dev->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) + graphics_line(dev); + else + text_line(dev, ca); + } + dev->sc = oldsc; + if (dev->vc == dev->crtc[7] && !dev->sc) + dev->stat |= 8; + dev->displine++; + if (dev->displine >= 500) + dev->displine = 0; + } else { + timer_advance_u64(&dev->timer, dev->dispontime); + if (dev->dispon) + dev->stat &= ~1; + dev->linepos = 0; + if (dev->vsynctime) { + dev->vsynctime--; + if (! dev->vsynctime) + dev->stat &= ~8; + } - col = mdacols[attr][0][1]; - for (c = 0; c < cw; c++) - { - ((uint32_t *)buffer32->line[herculesplus->displine])[x * cw + c] = col; + if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { + dev->con = 0; + dev->coff = 1; + } + if (dev->vadj) { + dev->sc++; + dev->sc &= 31; + dev->ma = dev->maback; + dev->vadj--; + if (! dev->vadj) { + dev->dispon = 1; + dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->sc = 0; + } + } else if (dev->sc == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) { + dev->maback = dev->ma; + dev->sc = 0; + oldvc = dev->vc; + dev->vc++; + dev->vc &= 127; + if (dev->vc == dev->crtc[6]) + dev->dispon = 0; + if (oldvc == dev->crtc[4]) { + dev->vc = 0; + dev->vadj = dev->crtc[5]; + if (!dev->vadj) dev->dispon=1; + if (!dev->vadj) dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + if ((dev->crtc[10] & 0x60) == 0x20) + dev->cursoron = 0; + else + dev->cursoron = dev->blink & 16; + } + if (dev->vc == dev->crtc[7]) { + dev->dispon = 0; + dev->displine = 0; + dev->vsynctime = 16; + if (dev->crtc[7]) { + if ((dev->ctrl & HERCULESPLUS_CTRL_GRAPH) && (dev->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) + x = dev->crtc[1] << 4; + else + x = dev->crtc[1] * 9; + dev->lastline++; + if ((dev->ctrl & 8) && + ((x != xsize) || ((dev->lastline - dev->firstline) != ysize) || video_force_resize_get())) { + xsize = x; + ysize = dev->lastline - dev->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen_8(0, dev->firstline, 0, dev->lastline - dev->firstline, xsize, dev->lastline - dev->firstline); + frames++; + if ((dev->ctrl & HERCULESPLUS_CTRL_GRAPH) && (dev->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) { + video_res_x = dev->crtc[1] * 16; + video_res_y = dev->crtc[6] * 4; + video_bpp = 1; + } else { + video_res_x = dev->crtc[1]; + video_res_y = dev->crtc[6]; + video_bpp = 0; + } } + dev->firstline = 1000; + dev->lastline = 0; + dev->blink++; } + } else { + dev->sc++; + dev->sc &= 31; + dev->ma = dev->maback; } + + if ((dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1)))) + dev->con = 1; + } } -static void herculesplus_graphics_line(herculesplus_t *herculesplus) +static void * +herculesplus_init(const device_t *info) { - uint16_t ca; - int x, c, plane = 0; - uint16_t val; + herculesplus_t *dev; + int c; - /* Graphics mode. */ - ca = (herculesplus->sc & 3) * 0x2000; - if ((herculesplus->ctrl & HERCULESPLUS_CTRL_PAGE1) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_PAGE1)) - ca += 0x8000; + dev = (herculesplus_t *)malloc(sizeof(herculesplus_t)); + memset(dev, 0, sizeof(herculesplus_t)); - for (x = 0; x < herculesplus->crtc[1]; x++) + dev->vram = (uint8_t *)malloc(0x10000); /* 64k VRAM */ + + timer_add(&dev->timer, herculesplus_poll, dev, 1); + + mem_mapping_add(&dev->mapping, 0xb0000, 0x10000, + herculesplus_read,NULL,NULL, + herculesplus_write,NULL,NULL, + dev->vram, MEM_MAPPING_EXTERNAL, dev); + + io_sethandler(0x03b0, 16, + herculesplus_in,NULL, NULL, herculesplus_out,NULL,NULL, dev); + + for (c = 0; c < 256; c++) { + dev->cols[c][0][0] = dev->cols[c][1][0] = dev->cols[c][1][1] = 16; + if (c & 8) + dev->cols[c][0][1] = 15 + 16; + else + dev->cols[c][0][1] = 7 + 16; + } + dev->cols[0x70][0][1] = 16; + dev->cols[0x70][0][0] = dev->cols[0x70][1][0] = + dev->cols[0x70][1][1] = 16 + 15; + dev->cols[0xF0][0][1] = 16; + dev->cols[0xF0][0][0] = dev->cols[0xF0][1][0] = + dev->cols[0xF0][1][1] = 16 + 15; + dev->cols[0x78][0][1] = 16 + 7; + dev->cols[0x78][0][0] = dev->cols[0x78][1][0] = + dev->cols[0x78][1][1] = 16 + 15; + dev->cols[0xF8][0][1] = 16 + 7; + dev->cols[0xF8][0][0] = dev->cols[0xF8][1][0] = + dev->cols[0xF8][1][1] = 16 + 15; + dev->cols[0x00][0][1] = dev->cols[0x00][1][1] = 16; + dev->cols[0x08][0][1] = dev->cols[0x08][1][1] = 16; + dev->cols[0x80][0][1] = dev->cols[0x80][1][1] = 16; + dev->cols[0x88][0][1] = dev->cols[0x88][1][1] = 16; + + herc_blend = device_get_config_int("blend"); + + cga_palette = device_get_config_int("rgb_type") << 1; + if (cga_palette > 6) + cga_palette = 0; + cgapal_rebuild(); + + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_herculesplus); + + /* Force the LPT3 port to be enabled. */ + lpt3_init(0x3BC); + + return dev; +} + + +static void +herculesplus_close(void *priv) +{ + herculesplus_t *dev = (herculesplus_t *)priv; + + if (!dev) + return; + + if (dev->vram) + free(dev->vram); + + free(dev); +} + + +static void +speed_changed(void *priv) +{ + herculesplus_t *dev = (herculesplus_t *)priv; + + recalc_timings(dev); +} + + +static const device_config_t herculesplus_config[] = { + { + "rgb_type", "Display type", CONFIG_SELECTION, "", 0, { - val = (herculesplus->vram[((herculesplus->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) - | herculesplus->vram[((herculesplus->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; - - herculesplus->ma++; - for (c = 0; c < 16; c++) { - val >>= 1; - - ((uint32_t *)buffer32->line[herculesplus->displine])[(x << 4) + c] = (val & 1) ? 7 : 0; + "Default", 0 + }, + { + "Green", 1 + }, + { + "Amber", 2 + }, + { + "Gray", 3 + }, + { + "" } } -} - -void herculesplus_poll(void *p) -{ - herculesplus_t *herculesplus = (herculesplus_t *)p; - uint16_t ca = (herculesplus->crtc[15] | (herculesplus->crtc[14] << 8)) & 0x3fff; - int x; - int oldvc; - int oldsc; - - if (!herculesplus->linepos) - { - herculesplus->vidtime += herculesplus->dispofftime; - herculesplus->stat |= 1; - herculesplus->linepos = 1; - oldsc = herculesplus->sc; - if ((herculesplus->crtc[8] & 3) == 3) - herculesplus->sc = (herculesplus->sc << 1) & 7; - if (herculesplus->dispon) - { - if (herculesplus->displine < herculesplus->firstline) - { - herculesplus->firstline = herculesplus->displine; - video_wait_for_buffer(); - } - herculesplus->lastline = herculesplus->displine; - if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) - { - herculesplus_graphics_line(herculesplus); - } - else - { - herculesplus_text_line(herculesplus, ca); - } - } - herculesplus->sc = oldsc; - if (herculesplus->vc == herculesplus->crtc[7] && !herculesplus->sc) - { - herculesplus->stat |= 8; - } - herculesplus->displine++; - if (herculesplus->displine >= 500) - herculesplus->displine = 0; - } - else - { - herculesplus->vidtime += herculesplus->dispontime; - if (herculesplus->dispon) - herculesplus->stat &= ~1; - herculesplus->linepos = 0; - if (herculesplus->vsynctime) - { - herculesplus->vsynctime--; - if (!herculesplus->vsynctime) - { - herculesplus->stat &= ~8; - } - } - if (herculesplus->sc == (herculesplus->crtc[11] & 31) || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == ((herculesplus->crtc[11] & 31) >> 1))) - { - herculesplus->con = 0; - herculesplus->coff = 1; - } - if (herculesplus->vadj) - { - herculesplus->sc++; - herculesplus->sc &= 31; - herculesplus->ma = herculesplus->maback; - herculesplus->vadj--; - if (!herculesplus->vadj) - { - herculesplus->dispon = 1; - herculesplus->ma = herculesplus->maback = (herculesplus->crtc[13] | (herculesplus->crtc[12] << 8)) & 0x3fff; - herculesplus->sc = 0; - } - } - else if (herculesplus->sc == herculesplus->crtc[9] || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == (herculesplus->crtc[9] >> 1))) - { - herculesplus->maback = herculesplus->ma; - herculesplus->sc = 0; - oldvc = herculesplus->vc; - herculesplus->vc++; - herculesplus->vc &= 127; - if (herculesplus->vc == herculesplus->crtc[6]) - herculesplus->dispon = 0; - if (oldvc == herculesplus->crtc[4]) - { - herculesplus->vc = 0; - herculesplus->vadj = herculesplus->crtc[5]; - if (!herculesplus->vadj) herculesplus->dispon=1; - if (!herculesplus->vadj) herculesplus->ma = herculesplus->maback = (herculesplus->crtc[13] | (herculesplus->crtc[12] << 8)) & 0x3fff; - if ((herculesplus->crtc[10] & 0x60) == 0x20) herculesplus->cursoron = 0; - else herculesplus->cursoron = herculesplus->blink & 16; - } - if (herculesplus->vc == herculesplus->crtc[7]) - { - herculesplus->dispon = 0; - herculesplus->displine = 0; - herculesplus->vsynctime = 16; - if (herculesplus->crtc[7]) - { - if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) - { - x = herculesplus->crtc[1] << 4; - } - else - { - x = herculesplus->crtc[1] * 9; - } - herculesplus->lastline++; - if ((x != xsize) || ((herculesplus->lastline - herculesplus->firstline) != ysize) || video_force_resize_get()) - { - xsize = x; - ysize = herculesplus->lastline - herculesplus->firstline; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, ysize); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - video_blit_memtoscreen(0, herculesplus->firstline, 0, herculesplus->lastline - herculesplus->firstline, xsize, herculesplus->lastline - herculesplus->firstline); - frames++; - if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) - { - video_res_x = herculesplus->crtc[1] * 16; - video_res_y = herculesplus->crtc[6] * 4; - video_bpp = 1; - } - else - { - video_res_x = herculesplus->crtc[1]; - video_res_y = herculesplus->crtc[6]; - video_bpp = 0; - } - } - herculesplus->firstline = 1000; - herculesplus->lastline = 0; - herculesplus->blink++; - } - } - else - { - herculesplus->sc++; - herculesplus->sc &= 31; - herculesplus->ma = herculesplus->maback; - } - if ((herculesplus->sc == (herculesplus->crtc[10] & 31) || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == ((herculesplus->crtc[10] & 31) >> 1)))) - { - herculesplus->con = 1; - } - } -} - -void *herculesplus_init(const device_t *info) -{ - int c; - herculesplus_t *herculesplus = malloc(sizeof(herculesplus_t)); - memset(herculesplus, 0, sizeof(herculesplus_t)); - - herculesplus->vram = malloc(0x10000); /* 64k VRAM */ - - timer_add(herculesplus_poll, &herculesplus->vidtime, TIMER_ALWAYS_ENABLED, herculesplus); - mem_mapping_add(&herculesplus->mapping, 0xb0000, 0x10000, herculesplus_read, NULL, NULL, herculesplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, herculesplus); - io_sethandler(0x03b0, 0x0010, herculesplus_in, NULL, NULL, herculesplus_out, NULL, NULL, herculesplus); - - for (c = 0; c < 256; c++) - { - mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; - if (c & 8) mdacols[c][0][1] = 15 + 16; - else mdacols[c][0][1] = 7 + 16; - } - mdacols[0x70][0][1] = 16; - mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; - mdacols[0xF0][0][1] = 16; - mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; - mdacols[0x78][0][1] = 16 + 7; - mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; - mdacols[0xF8][0][1] = 16 + 7; - mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; - mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; - mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; - mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; - mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; - - lpt3_init(0x3BC); - - return herculesplus; -} - -void herculesplus_close(void *p) -{ - herculesplus_t *herculesplus = (herculesplus_t *)p; - - free(herculesplus->vram); - free(herculesplus); -} - -void herculesplus_speed_changed(void *p) -{ - herculesplus_t *herculesplus = (herculesplus_t *)p; - - herculesplus_recalctimings(herculesplus); -} - -const device_t herculesplus_device = -{ - "Hercules Plus", - DEVICE_ISA, 0, - herculesplus_init, herculesplus_close, NULL, - NULL, - herculesplus_speed_changed, - NULL, - NULL + }, + { + "blend", "Blend", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +const device_t herculesplus_device = { + "Hercules Plus", + DEVICE_ISA, + 0, + herculesplus_init, herculesplus_close, NULL, + NULL, + speed_changed, + NULL, + herculesplus_config }; diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c new file mode 100644 index 000000000..a0479a696 --- /dev/null +++ b/src/video/vid_ht216.c @@ -0,0 +1,1192 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Video 7 VGA 1024i emulation. + * + * Version: @(#)vid_ht216.c 1.0.3 2019/12/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Sarah Walker. + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../pic.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_ht216.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, pad; + uint16_t id; + + 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); + + +#define BIOS_G2_GC205_PATH L"roms/video/video7/BIOS.BIN" +#define BIOS_VIDEO7_VGA_1024I_PATH L"roms/video/video7/Video Seven VGA 1024i - BIOS - v2.19 - 435-0062-05 - U17 - 27C256.BIN" + +static video_timings_t timing_v7vga = {VIDEO_ISA, 5, 5, 9, 20, 20, 30}; + + +#ifdef ENABLE_HT216_LOG +int ht216_do_log = ENABLE_HT216_LOG; + + +static void +ht216_log(const char *fmt, ...) +{ + va_list ap; + + if (ht216_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ht216_log(fmt, ...) +#endif + + +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; + + ht216_log("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) { + old = ht216->ht_regs[svga->seqaddr & 0xff]; + ht216->ht_regs[svga->seqaddr & 0xff] = val; + 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; + 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->latch.b[0] = val; + break; + case 0xa1: + svga->latch.b[1] = val; + break; + case 0xa2: + svga->latch.b[2] = val; + break; + case 0xa3: + svga->latch.b[3] = 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 0xc8: + if ((old ^ val) & 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + 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 0xff: + svga->hwcursor.addr = ((ht216->ht_regs[0x94] << 6) | (3 << 14) | ((val & 0x60) << 11)) << 2; + 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); + + 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 & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c2: + break; + + case 0x3c5: + if (svga->seqaddr == 6) + return ht216->ext_reg_enable; + if (svga->seqaddr >= 0x80) { + if (ht216->ext_reg_enable) { + switch (svga->seqaddr & 0xff) { + case 0x83: + if (svga->attrff) + return svga->attraddr | 0x80; + return svga->attraddr; + + case 0x8e: return ht216->id & 0xff; + case 0x8f: return (ht216->id >> 8) & 0xff; + + case 0xa0: + return svga->latch.b[0]; + case 0xa1: + return svga->latch.b[1]; + case 0xa2: + return svga->latch.b[2]; + case 0xa3: + return svga->latch.b[3]; + } + 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); + + 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; + } + } +} + + +void +ht216_recalctimings(svga_t *svga) +{ + ht216_t *ht216 = (ht216_t *)svga->p; + + 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) +{ + int x; + uint32_t dat[2]; + int offset = svga->hwcursor_latch.x + svga->x_add; + + 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; +} + + +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 || svga->fb_only) { + writemask2=1<<(addr&3); + 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->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = svga->latch.b[3]; + 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->latch.b[0] & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->latch.b[1] & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->latch.b[2] & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->latch.b[3] & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->latch.b[3]; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->latch.b[3]; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->latch.b[3]; + break; + } + } + 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->latch.b[0] & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (((cpu_dat & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->latch.b[1] & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (((cpu_dat & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->latch.b[2] & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (((cpu_dat & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->latch.b[3] & ~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->latch.b[0] & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->latch.b[1] & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->latch.b[2] & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->latch.b[3] & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->latch.b[3]; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->latch.b[3]; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->latch.b[3]; + 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->latch.b[0] & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->latch.b[1] & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->latch.b[2] & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->latch.b[3] & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->latch.b[3]; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->latch.b[3]; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->latch.b[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->latch.b[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->latch.b[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->latch.b[3]; + 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; + + if (ht216->ht_regs[0xcd] & HT_REG_CD_RMWMDE) /*RMW*/ + input_b = svga->vram[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); + output = (fg & rop_select) | (bg & ~rop_select); + svga->vram[addr] = (svga->vram[addr] & ~bit_mask) | (output & bit_mask); + svga->changedvram[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; + uint8_t bit_mask = 0, rop_select = 0; + + sub_cycles(video_timing_write_b); + + egawrites++; + + addr &= 0xfffff; + + val = svga_rotate[svga->gdcreg[3] & 7][val]; + + if (ht216->ht_regs[0xcd] & HT_REG_CD_EXALU) { + /*Extended ALU*/ + 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; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; + + 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, or; + int readplane = svga->readplane; + int offset; + uint32_t latch_addr; + + if (ht216->ht_regs[0xc8] & HT_REG_C8_MOVSB) + addr <<= 3; + + addr &= 0xfffff; + + sub_cycles(video_timing_read_b); + + egareads++; + + if (svga->chain4 || svga->fb_only) { + 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[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]; + + return svga->vram[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) { + 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]; + } + or = addr & 4; + svga->latch.d[0] = ht216->bg_latch[0 | or] | (ht216->bg_latch[1 | or] << 8) | + (ht216->bg_latch[2 | or] << 16) | (ht216->bg_latch[3 | or] << 24); + if (svga->readmode) { + temp = svga->latch.b[0]; + temp ^= (svga->colourcompare & 1) ? 0xff : 0; + temp &= (svga->colournocare & 1) ? 0xff : 0; + temp2 = svga->latch.b[1]; + temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; + temp2 &= (svga->colournocare & 2) ? 0xff : 0; + temp3 = svga->latch.b[2]; + temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; + temp3 &= (svga->colournocare & 4) ? 0xff : 0; + temp4 = svga->latch.b[3]; + temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + temp4 &= (svga->colournocare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } + + return svga->vram[addr | readplane]; +} + + +static uint8_t +ht216_read(uint32_t addr, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->read_bank[(addr >> 15) & 1]; + + return ht216_read_common(ht216, addr); +} + + +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(const device_t *info, uint32_t mem_size, int has_rom) +{ + ht216_t *ht216 = malloc(sizeof(ht216_t)); + svga_t *svga; + + memset(ht216, 0, sizeof(ht216_t)); + svga = &ht216->svga; + + 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); + + if (has_rom == 1) + rom_init(&ht216->bios_rom, BIOS_VIDEO7_VGA_1024I_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + else if (has_rom == 2) + rom_init(&ht216->bios_rom, BIOS_G2_GC205_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_v7vga); + + svga_init(&ht216->svga, ht216, mem_size, + ht216_recalctimings, + ht216_in, ht216_out, + ht216_hwcursor_draw, + NULL); + svga->hwcursor.ysize = 32; + ht216->vram_mask = mem_size - 1; + svga->decode_mask = mem_size - 1; + + mem_mapping_set_handler(&ht216->svga.mapping, ht216_read, NULL, 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, MEM_MAPPING_EXTERNAL, &ht216->svga); + + svga->bpp = 8; + svga->miscout = 1; + + ht216->ht_regs[0xb4] = 0x08; /*32-bit DRAM bus*/ + ht216->id = info->local; + + return ht216; +} + + +static void * +g2_gc205_init(const device_t *info) +{ + ht216_t *ht216 = ht216_init(info, 1 << 19, 2); + + return ht216; +} + + +static void * +v7_vga_1024i_init(const device_t *info) +{ + ht216_t *ht216 = ht216_init(info, device_get_config_int("memory") << 10, 1); + + return ht216; +} + + +static void * +ht216_pb410a_init(const device_t *info) +{ + ht216_t *ht216 = ht216_init(info, 1 << 20, 0); + + return ht216; +} + + +static int +g2_gc205_available(void) +{ + return rom_present(BIOS_G2_GC205_PATH); +} + + +static int +v7_vga_1024i_available(void) +{ + return rom_present(BIOS_VIDEO7_VGA_1024I_PATH); +} + + +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; +} + + +static const device_config_t v7_vga_1024i_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t g2_gc205_device = +{ + "G2 GC205", + DEVICE_ISA, + 0x7070, + g2_gc205_init, + ht216_close, + NULL, + g2_gc205_available, + ht216_speed_changed, + ht216_force_redraw +}; + +const device_t v7_vga_1024i_device = +{ + "Video 7 VGA 1024i", + DEVICE_ISA, + 0x7140, + v7_vga_1024i_init, + ht216_close, + NULL, + v7_vga_1024i_available, + ht216_speed_changed, + ht216_force_redraw, + v7_vga_1024i_config +}; + +const device_t ht216_32_pb410a_device = +{ + "Headland HT216-32 (Packard Bell PB410A)", + DEVICE_ISA, + 0x7861, /*HT216-32*/ + ht216_pb410a_init, + ht216_close, + NULL, + NULL, + ht216_speed_changed, + ht216_force_redraw +}; diff --git a/src/video/vid_ht216.h b/src/video/vid_ht216.h new file mode 100644 index 000000000..abb15bba9 --- /dev/null +++ b/src/video/vid_ht216.h @@ -0,0 +1,21 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Video 7 VGA 1024i emulation header. + * + * Version: @(#)vid_ht216.h 1.0.1 2019/10/01 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Sarah Walker. + * Copyright 2019 Miran Grca. + */ +extern const device_t g2_gc205_device; +extern const device_t v7_vga_1024i_device; +extern const device_t ht216_32_pb410a_device; diff --git a/src/video/vid_icd2061.c b/src/video/vid_icd2061.c index e8aaf05cb..1c1746df5 100644 --- a/src/video/vid_icd2061.c +++ b/src/video/vid_icd2061.c @@ -7,74 +7,167 @@ * This file is part of the 86Box distribution. * * ICD2061 clock generator emulation. + * Also emulates the ICS9161 which is the same as the ICD2016, + * but without the need for tuning (which is irrelevant in + * emulation anyway). * - * Used by ET4000w32/p (Diamond Stealth 32) + * Used by ET4000w32/p (Diamond Stealth 32) and the S3 + * Vision964 family. * - * Version: @(#)vid_icd2061.c 1.0.2 2017/11/04 + * Version: @(#)vid_icd2061.c 1.0.8 2018/10/04 * - * Authors: Sarah Walker, - * Miran Grca, + * Authors: Miran Grca, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "../86box.h" +#include "../device.h" #include "vid_icd2061.h" -void icd2061_write(icd2061_t *icd2061, int val) +#ifdef ENABLE_ICD2061_LOG +int icd2061_do_log = ENABLE_ICD2061_LOG; + + +static void +icd2061_log(const char *fmt, ...) { - int q, p, m, a; - if ((val & 1) && !(icd2061->state & 1)) - { - if (!icd2061->status) - { - if (val & 2) - icd2061->unlock++; - else - { - if (icd2061->unlock >= 5) - { - icd2061->status = 1; - icd2061->pos = 0; - } - else - icd2061->unlock = 0; - } - } - else if (val & 1) - { - icd2061->data = (icd2061->data >> 1) | (((val & 2) ? 1 : 0) << 24); - icd2061->pos++; - if (icd2061->pos == 26) - { - a = (icd2061->data >> 21) & 0x7; - if (!(a & 4)) - { - q = (icd2061->data & 0x7f) - 2; - m = 1 << ((icd2061->data >> 7) & 0x7); - p = ((icd2061->data >> 10) & 0x7f) - 3; - if (icd2061->ctrl & (1 << a)) - p <<= 1; - icd2061->freq[a] = ((double)p / (double)q) * 2.0 * 14318184.0 / (double)m; - } - else if (a == 6) - { - icd2061->ctrl = val; - } - icd2061->unlock = icd2061->data = 0; - icd2061->status = 0; - } - } - } - icd2061->state = val; + va_list ap; + + if (icd2061_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define icd2061_log(fmt, ...) +#endif + + +void +icd2061_write(icd2061_t *icd2061, int val) +{ + int nd, oc, nc; + int a, qa, q, pa, p, m, ps; + + nd = (val & 2) >> 1; /* Old data. */ + oc = icd2061->state & 1; /* Old clock. */ + nc = val & 1; /* New clock. */ + + icd2061->state = val; + + if (nc && !oc) { /* Low-to-high transition of CLK. */ + if (!icd2061->unlocked) { + if (nd) { /* DATA high. */ + icd2061->count++; + icd2061_log("Low-to-high transition of CLK with DATA high, %i total\n", icd2061->count); + } else { /* DATA low. */ + if (icd2061->count >= 5) { + icd2061->unlocked = 1; + icd2061->bit_count = icd2061->data = 0; +#ifdef ENABLE_ICD2061_LOG + icd2061_log("ICD2061 unlocked\n"); +#endif + } else { + icd2061->count = 0; +#ifdef ENABLE_ICD2061_LOG + icd2061_log("ICD2061 locked\n"); +#endif + } + } + } else if (nc) { + icd2061->data |= (nd << icd2061->bit_count); + icd2061->bit_count++; + + if (icd2061->bit_count == 26) { + icd2061_log("26 bits received, data = %08X\n", icd2061->data); + + a = ((icd2061->data >> 22) & 0x07); /* A */ + icd2061_log("A = %01X\n", a); + + if (a < 3) { + pa = ((icd2061->data >> 11) & 0x7f); /* P' (ICD2061) / N' (ICS9161) */ + m = ((icd2061->data >> 8) & 0x07); /* M (ICD2061) / R (ICS9161) */ + qa = ((icd2061->data >> 1) & 0x7f); /* Q' (ICD2061) / M' (ICS9161) */ + + p = pa + 3; /* P (ICD2061) / N (ICS9161) */ + m = 1 << m; + q = qa + 2; /* Q (ICD2061) / M (ICS9161) */ + ps = (icd2061->ctrl & (1 << a)) ? 4 : 2; /* Prescale */ + + icd2061->freq[a] = ((float)(p * ps) / (float)(q * m)) * 14318184.0f; + + icd2061_log("P = %02X, M = %01X, Q = %02X, freq[%i] = %f\n", p, m, q, a, icd2061->freq[a]); + } else if (a == 6) { + icd2061->ctrl = ((icd2061->data >> 13) & 0xff); + icd2061_log("ctrl = %02X\n", icd2061->ctrl); + } + icd2061->count = icd2061->bit_count = icd2061->data = 0; + icd2061->unlocked = 0; +#ifdef ENABLE_ICD2061_LOG + icd2061_log("ICD2061 locked\n"); +#endif + } + } + } } -double icd2061_getfreq(icd2061_t *icd2061, int i) + +float +icd2061_getclock(int clock, void *p) { - return icd2061->freq[i]; + icd2061_t *icd2061 = (icd2061_t *) p; + + if (clock > 2) + clock = 2; + + return icd2061->freq[clock]; } + + +static void * +icd2061_init(const device_t *info) +{ + icd2061_t *icd2061 = (icd2061_t *) malloc(sizeof(icd2061_t)); + memset(icd2061, 0, sizeof(icd2061_t)); + + icd2061->freq[0] = 25175000.0; + icd2061->freq[1] = 28322000.0; + icd2061->freq[2] = 28322000.0; + + return icd2061; +} + + +static void +icd2061_close(void *priv) +{ + icd2061_t *icd2061 = (icd2061_t *) priv; + + if (icd2061) + free(icd2061); +} + + +const device_t icd2061_device = +{ + "ICD2061 Clock Generator", + 0, 0, + icd2061_init, icd2061_close, + NULL, NULL, NULL, NULL +}; + + +const device_t ics9161_device = +{ + "ICS9161 Clock Generator", + 0, 0, + icd2061_init, icd2061_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_icd2061.h b/src/video/vid_icd2061.h index acb6821cf..5b1c853e3 100644 --- a/src/video/vid_icd2061.h +++ b/src/video/vid_icd2061.h @@ -1,17 +1,40 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * ICD2061 clock generator emulation header. + * Also emulates the ICS9161 which is the same as the ICD2016, + * but without the need for tuning (which is irrelevant in + * emulation anyway). + * + * Used by ET4000w32/p (Diamond Stealth 32) and the S3 + * Vision964 family. + * + * Version: @(#)vid_icd2061.h 1.0.3 2018/10/04 + * + * Authors: Miran Grca, + * + * Copyright 2018 Miran Grca. + */ typedef struct icd2061_t { - int state; - int status; - int pos; - int unlock; - uint32_t data; + float freq[3]; - double freq[4]; - uint32_t ctrl; + int count, bit_count; + int unlocked, state; + uint32_t data, ctrl; } icd2061_t; void icd2061_write(icd2061_t *icd2061, int val); -double icd2061_getfreq(icd2061_t *icd2061, int i); +float icd2061_getclock(int clock, void *p); + +extern const device_t icd2061_device; +extern const device_t ics9161_device; + +/* The code is the same, the #define's are so that the correct name can be used. */ +#define ics9161_write icd2061_write +#define ics9161_getclock icd2061_getclock diff --git a/src/video/vid_ics2595.c b/src/video/vid_ics2595.c index 029999de9..711fb4641 100644 --- a/src/video/vid_ics2595.c +++ b/src/video/vid_ics2595.c @@ -8,19 +8,21 @@ * * ICS2595 clock chip emulation. Used by ATI Mach64. * - * Version: @(#)vid_ics2595.c 1.0.2 2017/11/04 + * Version: @(#)vid_ics2595.c 1.0.3 2018/10/04 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "../86box.h" +#include "../device.h" #include "vid_ics2595.h" @@ -35,39 +37,67 @@ enum static int ics2595_div[4] = {8, 4, 2, 1}; -void ics2595_write(ics2595_t *ics2595, int strobe, int dat) +void +ics2595_write(ics2595_t *ics2595, int strobe, int dat) { - if (strobe) - { - if ((dat & 8) && !ics2595->oldfs3) /*Data clock*/ - { - switch (ics2595->state) - { - case ICS2595_IDLE: - ics2595->state = (dat & 4) ? ICS2595_WRITE : ICS2595_IDLE; - ics2595->pos = 0; - break; - case ICS2595_WRITE: - ics2595->dat = (ics2595->dat >> 1); - if (dat & 4) - ics2595->dat |= (1 << 19); - ics2595->pos++; - if (ics2595->pos == 20) - { - int d, n, l; - l = (ics2595->dat >> 2) & 0xf; - n = ((ics2595->dat >> 7) & 255) + 257; - d = ics2595_div[(ics2595->dat >> 16) & 3]; + int d, n, l; - ics2595->clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d; - ics2595->state = ICS2595_IDLE; - } - break; - } - } - - ics2595->oldfs2 = dat & 4; - ics2595->oldfs3 = dat & 8; - } - ics2595->output_clock = ics2595->clocks[dat]; + if (strobe) { + if ((dat & 8) && !ics2595->oldfs3) { /*Data clock*/ + switch (ics2595->state) { + case ICS2595_IDLE: + ics2595->state = (dat & 4) ? ICS2595_WRITE : ICS2595_IDLE; + ics2595->pos = 0; + break; + case ICS2595_WRITE: + ics2595->dat = (ics2595->dat >> 1); + if (dat & 4) + ics2595->dat |= (1 << 19); + ics2595->pos++; + if (ics2595->pos == 20) { + l = (ics2595->dat >> 2) & 0xf; + n = ((ics2595->dat >> 7) & 255) + 257; + d = ics2595_div[(ics2595->dat >> 16) & 3]; + + ics2595->clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d; + ics2595->state = ICS2595_IDLE; + } + break; + } + } + + ics2595->oldfs2 = dat & 4; + ics2595->oldfs3 = dat & 8; + } + + ics2595->output_clock = ics2595->clocks[dat]; } + + +static void * +ics2595_init(const device_t *info) +{ + ics2595_t *ics2595 = (ics2595_t *) malloc(sizeof(ics2595_t)); + memset(ics2595, 0, sizeof(ics2595_t)); + + return ics2595; +} + + +static void +ics2595_close(void *priv) +{ + ics2595_t *ics2595 = (ics2595_t *) priv; + + if (ics2595) + free(ics2595); +} + + +const device_t ics2595_device = +{ + "ICS2595 clock chip", + 0, 0, + ics2595_init, ics2595_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_ics2595.h b/src/video/vid_ics2595.h index 5e5f1842d..1453a38ba 100644 --- a/src/video/vid_ics2595.h +++ b/src/video/vid_ics2595.h @@ -1,15 +1,31 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * ICS2595 clock chip emulation header. Used by ATI Mach64. + * + * Version: @(#)vid_ics2595.h 1.0.0 2018/10/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ typedef struct ics2595_t { - int oldfs3, oldfs2; - int dat; - int pos; - int state; + int oldfs3, oldfs2; + int dat; + int pos, state; - double clocks[16]; - double output_clock; + double clocks[16]; + double output_clock; } ics2595_t; -void ics2595_write(ics2595_t *ics2595, int strobe, int dat); +extern void ics2595_write(ics2595_t *ics2595, int strobe, int dat); + +extern const device_t ics2595_device; diff --git a/src/video/vid_im1024.c b/src/video/vid_im1024.c new file mode 100644 index 000000000..0a8ca6e6c --- /dev/null +++ b/src/video/vid_im1024.c @@ -0,0 +1,1019 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the ImageManager 1024 video controller. + * + * Just enough of the Vermont Microsystems IM-1024 is implemented + * to support the Windows 1.03 driver. Functions are partially + * implemented or hardwired to the behavior 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. + * + * It is unknown what triggers this, so for now it's always on. + * + * 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 can be determined, at least one byte is always + * written; there is no provision to pause if the queue is full. + * + * This is implemented by holding a FIFO of unlimited depth in + * the IM1024 to receive the data. + * + * Version: @(#)vid_im1024.c 1.0.4 2019/11/04 + * + * Authors: Fred N. van Kempen, + * John Elliott, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 2019 John Elliott. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../pit.h" +#include "../plat.h" +#include "video.h" +#include "vid_pgc.h" +#include "vid_im1024.h" + + +#define BIOS_ROM_PATH L"roms/video/im1024/im1024font.bin" + + +typedef struct { + pgc_t pgc; + + uint8_t fontx[256]; + uint8_t fonty[256]; + uint8_t font[256][128]; + + uint8_t *fifo; + unsigned fifo_len, + fifo_wrptr, + fifo_rdptr; +} im1024_t; + + +static video_timings_t timing_im1024 = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + + +#ifdef ENABLE_IM1024_LOG +int im1024_do_log = ENABLE_IM1024_LOG; + + +static void +im1024_log(const char *fmt, ...) +{ + va_list ap; + + if (im1024_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define im1024_log(fmt, ...) +#endif + + +static void +fifo_write(im1024_t *dev, uint8_t val) +{ + im1024_log("IM1024: fifo_write: %02x [rd=%04x wr=%04x]\n", + val, dev->fifo_rdptr, dev->fifo_wrptr); + + if (((dev->fifo_wrptr + 1) % dev->fifo_len) == dev->fifo_rdptr) { + /* FIFO is full. Double its size. */ + uint8_t *buf; + + im1024_log("IM1024: fifo_resize: %i to %i\n", + dev->fifo_len, 2 * dev->fifo_len); + + buf = realloc(dev->fifo, 2 * dev->fifo_len); + if (buf == NULL) return; + + /* Move the [0..wrptr] range to the newly-allocated area [len..len+wrptr] */ + memmove(buf + dev->fifo_len, buf, dev->fifo_wrptr); + dev->fifo = buf; + dev->fifo_wrptr += dev->fifo_len; + dev->fifo_len *= 2; + } + + /* Append to the queue. */ + dev->fifo[dev->fifo_wrptr++] = val; + + /* Wrap if end of buffer reached. */ + if (dev->fifo_wrptr >= dev->fifo_len) + dev->fifo_wrptr = 0; +} + + +static int +fifo_read(im1024_t *dev) +{ + uint8_t ret; + + if (dev->fifo_wrptr == dev->fifo_rdptr) + return -1; /* FIFO empty */ + + ret = dev->fifo[dev->fifo_rdptr++]; + if (dev->fifo_rdptr >= dev->fifo_len) + dev->fifo_rdptr = 0; + + im1024_log("IM1024: fifo_read: %02x\n", ret); + + return(ret); +} + + +/* + * Where a normal PGC would just read from the ring buffer at 0xC6300, + * the IM-1024 can read from either this or from its internal FIFO. + * + * The internal FIFO has priority. + */ +static int +input_byte(pgc_t *pgc, uint8_t *result) +{ + im1024_t *dev = (im1024_t *)pgc; + + /* If input buffer empty, wait for it to fill. */ + while (!pgc->stopped && (dev->fifo_wrptr == dev->fifo_rdptr) && + (pgc->mapram[0x300] == pgc->mapram[0x301])) { + pgc->waiting_input_fifo = 1; + pgc_sleep(pgc); + } + + if (pgc->stopped) + return(0); + + if (pgc->mapram[0x3ff]) { + /* Reset triggered. */ + pgc_reset(pgc); + return(0); + } + + if (dev->fifo_wrptr == dev->fifo_rdptr) { + *result = pgc->mapram[pgc->mapram[0x301]]; + pgc->mapram[0x301]++; + } else + *result = fifo_read(dev); + + 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. */ +static uint8_t +im1024_read(uint32_t addr, void *priv) +{ + im1024_t *dev = (im1024_t *)priv; + + if (addr == 0xc6331 && dev->pgc.mapram[0x330] == 1) { + /* Hardcode that there are 128 bytes free. */ + return(0x80); + } + + return(pgc_read(addr, &dev->pgc)); +} + + +/* Override memory write to handle writes to the FIFO. */ +static void +im1024_write(uint32_t addr, uint8_t val, void *priv) +{ + im1024_t *dev = (im1024_t *)priv; + + /* + * If we are in 'fast' input mode, send all + * writes to the internal FIFO. + */ + if (addr >= 0xc6000 && addr < 0xc6100 && dev->pgc.mapram[0x330] == 1) { + fifo_write(dev, val); + + im1024_log("IM1024: write(%02x)\n", val); + + if (dev->pgc.waiting_input_fifo) { + dev->pgc.waiting_input_fifo = 0; + pgc_wake(&dev->pgc); + } + return; + } + + pgc_write(addr, val, &dev->pgc); +} + + +/* + * I don't know what the IMGSIZ command does, only that the + * Windows driver issues it. So just parse and ignore it. + */ +static void +hndl_imgsiz(pgc_t *pgc) +{ +#if 0 + im1024_t *dev = (im1024_t *)pgc; +#endif + int16_t w, h; + uint8_t a, b; + + 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; + + im1024_log("IM1024: IMGSIZ %i,%i,%i,%i\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. + */ +static void +hndl_iprec(pgc_t *pgc) +{ +#if 0 + im1024_t *dev = (im1024_t *)pgc; +#endif + uint8_t param; + + if (! pgc_param_byte(pgc, ¶m)) return; + + im1024_log("IM1024: IPREC %i\n", param); +} + + +/* + * Set drawing mode. + * + * 0 => Draw + * 1 => Invert + * 2 => XOR (IM-1024) + * 3 => AND (IM-1024) + */ +static void +hndl_linfun(pgc_t *pgc) +{ + uint8_t param; + + if (! pgc_param_byte(pgc, ¶m)) return; + + if (param < 4) { + pgc->draw_mode = param; + im1024_log("IM1024: LINFUN(%i)\n", param); + } else + pgc_error(pgc, PGC_ERROR_RANGE); +} + + +/* + * I think PAN controls which part of the 1024x1024 framebuffer + * is displayed in the 1024x800 visible screen. + */ +static void +hndl_pan(pgc_t *pgc) +{ + int16_t x, y; + + if (! pgc_param_word(pgc, &x)) return; + if (! pgc_param_word(pgc, &y)) return; + + im1024_log("IM1024: PAN %i,%i\n", x, y); + + pgc->pan_x = x; + pgc->pan_y = y; +} + + +/* PLINE draws a non-filled polyline at a fixed position. */ +static void +hndl_pline(pgc_t *pgc) +{ + int16_t x[257], y[257]; + uint16_t linemask = pgc->line_pattern; + uint8_t count; + unsigned n; + + if (! pgc_param_byte(pgc, &count)) return; + + im1024_log("IM1024: PLINE (%i) ", count); + for (n = 0; n < count; n++) { + if (! pgc_param_word(pgc, &x[n])) return; + if (! pgc_param_word(pgc, &y[n])) return; + im1024_log(" (%i,%i)\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. + */ +static void +blkmov_row(pgc_t *pgc, int16_t x0, int16_t x1, int16_t x2, int16_t sy, int16_t ty) +{ + uint8_t src[1024]; + uint8_t dst[1024]; + int16_t x; + + 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. + * + * Clipping is disabled. + */ +static void +hndl_blkmov(pgc_t *pgc) +{ + int16_t x0, y0; + int16_t x1, y1; + int16_t x2, y2; + int16_t y; + + 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; + + im1024_log("IM1024: BLKMOV %i,%i,%i,%i,%i,%i\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 +} + + +/* + * Override the PGC ELIPSE command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_ellipse(pgc_t *pgc) +{ + int16_t x, y; + + if (! pgc_param_word(pgc, &x)) return; + if (! pgc_param_word(pgc, &y)) return; + + im1024_log("IM1024: ELLIPSE %i,%i @ %i,%i\n", + x, y, pgc->x >> 16, pgc->y >> 16); + + pgc_draw_ellipse(pgc, x << 16, y << 16); +} + + +/* + * Override the PGC MOVE command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_move(pgc_t *pgc) +{ + int16_t x, y; + + if (! pgc_param_word(pgc, &x)) return; + if (! pgc_param_word(pgc, &y)) return; + + im1024_log("IM1024: MOVE %i,%i\n", x, y); + + pgc->x = x << 16; + pgc->y = y << 16; +} + + +/* + * Override the PGC DRAW command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_draw(pgc_t *pgc) +{ + int16_t x, y; + + if (! pgc_param_word(pgc, &x)) return; + if (! pgc_param_word(pgc, &y)) return; + + im1024_log("IM1024: DRAW %i,%i to %i,%i\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; +} + + +/* + * Override the PGC POLY command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_poly(pgc_t *pgc) +{ + int32_t *x, *y, *nx, *ny; + int16_t xw, yw, mask; + unsigned realcount = 0; + unsigned n, as = 256; + int parsing = 1; + uint8_t count; + + x = (int32_t *)malloc(as * sizeof(int32_t)); + y = (int32_t *)malloc(as * sizeof(int32_t)); + if (!x || !y) { +#ifdef ENABLE_IM1024_LOG + im1024_log("IM1024: POLY: out of memory\n"); +#endif + return; + } + + while (parsing) { + if (! pgc_param_byte(pgc, &count)) return; + + if (count + realcount >= as) { + nx = (int32_t *)realloc(x, 2 * as * sizeof(int32_t)); + ny = (int32_t *)realloc(y, 2 * as * sizeof(int32_t)); + if (!x || !y) { +#ifdef ENABLE_IM1024_LOG + im1024_log("IM1024: poly: realloc failed\n"); +#endif + 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 are 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) { +#ifdef ENABLE_IM1024_LOG + im1024_log("IM1024: POLY continues!\n"); +#endif + parsing = 1; + + /* Swallow the POLY. */ + pgc->clcur->rdptr++; + } + }; + + im1024_log("IM1024: POLY (%i) fill_mode=%i\n", realcount, pgc->fill_mode); +#ifdef ENABLE_IM1024_LOG + for (n = 0; n < realcount; n++) { + im1024_log(" (%i,%i)\n", x[n] >> 16, y[n] >> 16); + } +#endif + + 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_t *pgc, pgc_cl_t *cl, int c) +{ + uint8_t count; + +#ifdef ENABLE_IM1024_LOG + im1024_log("IM1024: parse_poly\n"); +#endif + + if (! pgc_param_byte(pgc, &count)) return 0; + + im1024_log("IM1024: parse_poly: count=%02x\n", count); + if (! pgc_cl_append(cl, count)) { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + return 0; + } + + im1024_log("IM1024: parse_poly: parse %i words\n", 2 * count); + + return pgc_parse_words(pgc, cl, count * 2); +} + + +/* + * Override the PGC RECT command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_rect(pgc_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; } + im1024_log("IM1024: RECT (%i,%i) -> (%i,%i)\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); + } +} + + +/* + * FIXME: + * Define a font character. + * + * Text drawing should probably be implemented in + * vid_pgc.c rather than here.. + */ +static void +hndl_tdefin(pgc_t *pgc) +{ + im1024_t *dev = (im1024_t *)pgc; + uint8_t ch, bt; + uint8_t rows, cols; + unsigned len, n; + + if (! pgc_param_byte(pgc, &ch)) return; + if (! pgc_param_byte(pgc, &cols)) return; + if (! pgc_param_byte(pgc, &rows)) return; + + im1024_log("IM1024: TDEFIN (%i,%i,%i) 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++) { + if (! pgc_param_byte(pgc, &bt)) return; + + if (n < sizeof(dev->font[ch])) + dev->font[ch][n] = bt; + } + + dev->fontx[ch] = cols; + dev->fonty[ch] = rows; +} + + +static void +hndl_tsize(pgc_t *pgc) +{ + int16_t size; + + if (!pgc_param_word(pgc, &size)) return; + im1024_log("IM1024: TSIZE(%i)\n", size); + + pgc->tsize = size << 16; +} + + +static void +hndl_twrite(pgc_t *pgc) +{ + uint8_t buf[256]; + im1024_t *dev = (im1024_t *)pgc; + uint8_t count, mask, *row; + int x, y, wb, n; + int16_t x0 = pgc->x >> 16; + int16_t y0 = pgc->y >> 16; + + if (! pgc_param_byte(pgc, &count)) return; + + for (n = 0; n < count; n++) + if (! pgc_param_byte(pgc, &buf[n])) return; + buf[count] = 0; + + pgc_sto_raster(pgc, &x0, &y0); + + im1024_log("IM1024: TWRITE (%i) x0=%i y0=%i\n", count, x0, y0); + + for (n = 0; n < count; n++) { + wb = (dev->fontx[buf[n]] + 7) / 8; + im1024_log("IM1024: ch=0x%02x w=%i h=%i wb=%i\n", + buf[n], dev->fontx[buf[n]], dev->fonty[buf[n]], wb); + + for (y = 0; y < dev->fonty[buf[n]]; y++) { + mask = 0x80; + row = &dev->font[buf[n]][y * wb]; + for (x = 0; x < dev->fontx[buf[n]]; x++) { + if (row[0] & mask) + pgc_plot(pgc, x + x0, y0 - y); + mask = mask >> 1; + if (mask == 0) { + mask = 0x80; + row++; + } + } + } + + x0 += dev->fontx[buf[n]]; + } +} + + +static void +hndl_txt88(pgc_t *pgc) +{ + uint8_t buf[256]; + uint8_t count, mask, *row; + int16_t x0 = pgc->x >> 16; + int16_t y0 = pgc->y >> 16; + unsigned n; + int x, y; + + if (! pgc_param_byte(pgc, &count)) return; + + for (n = 0; n < count; n++) + if (! pgc_param_byte(pgc, &buf[n])) return; + buf[count] = 0; + + pgc_sto_raster(pgc, &x0, &y0); + + im1024_log("IM204: TXT88 (%i) x0=%i y0=%i\n", count, x0, y0); + + for (n = 0; n < count; n++) { + im1024_log("ch=0x%02x w=12 h=18\n", buf[n]); + + for (y = 0; y < 18; y++) { + mask = 0x80; + row = &fontdat12x18[buf[n]][y * 2]; + for (x = 0; x < 12; x++) { + if (row[0] & mask) pgc_plot(pgc, x + x0, y0 - y); + mask = mask >> 1; + if (mask == 0) { + mask = 0x80; + row++; + } + } + } + + x0 += 12; + } +} + + +static void +hndl_imagew(pgc_t *pgc) +{ + int16_t vp_x1, vp_y1, vp_x2, vp_y2; + int16_t row1, col1, col2; + uint8_t v1, v2; + + if (! pgc_param_word(pgc, &row1)) return; + if (! pgc_param_word(pgc, &col1)) return; + if (! pgc_param_word(pgc, &col2)) return; + + /* Already using raster coordinates, no need to convert. */ + im1024_log("IM1024: IMAGEW (row=%i,col1=%i,col2=%i)\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++; + } + } 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_t *pgc) +{ + int16_t x = pgc->x >> 16, + y = pgc->y >> 16; + + pgc_sto_raster(pgc, &x, &y); + + im1024_log("IM1024: DOT @ %i,%i ink=%i mode=%i\n", + x, y, pgc->color, 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_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; + + /* Already using raster coordinates, no need to convert. */ + im1024_log("IM1024: IMAGEX (%i,%i,%i,%i)\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_cmd_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, NULL, 0 }, + { "ELIPSE", 0x39, hndl_ellipse, pgc_parse_words, 2 }, + { "EL", 0x39, hndl_ellipse, pgc_parse_words, 2 }, + { "IMAGEW", 0xd9, hndl_imagew, NULL, 0 }, + { "IMAGEX", 0xda, hndl_imagex, NULL, 0 }, + { "IMGSIZ", 0x4e, hndl_imgsiz, NULL, 0 }, + { "IPREC", 0xe4, hndl_iprec, NULL, 0 }, + { "IW", 0xd9, hndl_imagew, NULL, 0 }, + { "L8", 0xe6, pgc_hndl_lut8, NULL, 0 }, + { "LF", 0xeb, hndl_linfun, pgc_parse_bytes, 1 }, + { "LINFUN", 0xeb, hndl_linfun, pgc_parse_bytes, 1 }, + { "LUT8", 0xe6, pgc_hndl_lut8, NULL, 0 }, + { "LUT8RD", 0x53, pgc_hndl_lut8rd,NULL, 0 }, + { "L8RD", 0x53, pgc_hndl_lut8rd,NULL, 0 }, + { "TDEFIN", 0x84, hndl_tdefin, NULL, 0 }, + { "TD", 0x84, hndl_tdefin, NULL, 0 }, + { "TSIZE", 0x81, hndl_tsize, NULL, 0 }, + { "TS", 0x81, hndl_tsize, NULL, 0 }, + { "TWRITE", 0x8b, hndl_twrite, NULL, 0 }, + { "TXT88", 0x88, hndl_txt88, NULL, 0 }, + { "PAN", 0xb7, hndl_pan, NULL, 0 }, + { "POLY", 0x30, hndl_poly, parse_poly, 0 }, + { "P", 0x30, hndl_poly, parse_poly, 0 }, + { "PLINE", 0x36, hndl_pline, NULL, 0 }, + { "PL", 0x37, hndl_pline, NULL, 0 }, + { "MOVE", 0x10, hndl_move, pgc_parse_words, 2 }, + { "M", 0x10, hndl_move, pgc_parse_words, 2 }, + { "RECT", 0x34, hndl_rect, NULL, 0 }, + { "R", 0x34, hndl_rect, NULL, 0 }, + { "******", 0x00, NULL, NULL, 0 } +}; + + +static void * +im1024_init(const device_t *info) +{ + im1024_t *dev; + + dev = (im1024_t *)malloc(sizeof(im1024_t)); + memset(dev, 0x00, sizeof(im1024_t)); + + loadfont(BIOS_ROM_PATH, 9); + + dev->fifo_len = 4096; + dev->fifo = (uint8_t *)malloc(dev->fifo_len); + dev->fifo_wrptr = 0; + dev->fifo_rdptr = 0; + + /* Create a 1024x1024 framebuffer with 1024x800 visible. */ + pgc_init(&dev->pgc, 1024, 1024, 1024, 800, input_byte, 65000000.0); + + dev->pgc.commands = im1024_commands; + + mem_mapping_set_handler(&dev->pgc.mapping, + im1024_read,NULL,NULL, im1024_write,NULL,NULL); + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_im1024); + + return(dev); +} + + +static void +im1024_close(void *priv) +{ + im1024_t *dev = (im1024_t *)priv; + + pgc_close(&dev->pgc); + + free(dev); +} + + +static int +im1024_available() +{ + return rom_present(BIOS_ROM_PATH); +} + + +static void +im1024_speed_changed(void *priv) +{ + im1024_t *dev = (im1024_t *)priv; + + pgc_speed_changed(&dev->pgc); +} + + +const device_t im1024_device = { + "ImageManager 1024", + DEVICE_ISA, 0, + im1024_init, im1024_close, NULL, + im1024_available, + im1024_speed_changed, + NULL, + NULL +}; diff --git a/src/video/vid_im1024.h b/src/video/vid_im1024.h new file mode 100644 index 000000000..bf716b1d3 --- /dev/null +++ b/src/video/vid_im1024.h @@ -0,0 +1,18 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header of the emulation of the ImageManager 1024 video + * controller. + * + * Version: @(#)vid_im1024.h 1.0.0 2019/03/03 + * + * Authors: John Elliott, + * + * Copyright 2019 John Elliott. + */ +extern const device_t im1024_device; diff --git a/src/video/vid_incolor.c b/src/video/vid_incolor.c index f1cf1c1a1..bd0d6e36f 100644 --- a/src/video/vid_incolor.c +++ b/src/video/vid_incolor.c @@ -8,7 +8,7 @@ * * Hercules InColor emulation. * - * Version: @(#)vid_incolor.c 1.0.10 2018/04/29 + * Version: @(#)vid_incolor.c 1.0.14 2019/02/08 * * Authors: Sarah Walker, * Miran Grca, @@ -18,16 +18,16 @@ */ #include #include -#include #include +#include #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../lpt.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_incolor.h" @@ -45,7 +45,7 @@ #define INCOLOR_CRTC_PALETTE 28 /* Palette */ /* character width */ -#define INCOLOR_CW ((incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) ? 8 : 9) +#define INCOLOR_CW ((dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) ? 8 : 9) /* mode control register */ #define INCOLOR_CTRL_GRAPH 0x02 @@ -81,334 +81,358 @@ /* Default palette */ -static unsigned char defpal[16] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F +static const uint8_t defpal[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F }; -static uint32_t incolor_rgb[64]; - /* Mapping of inks to RGB */ -static unsigned char init_rgb[64][3] = -{ +static const uint8_t init_rgb[64][3] = { /* rgbRGB */ - { 0x00, 0x00, 0x00 }, /* 000000 */ - { 0x00, 0x00, 0xaa }, /* 000001 */ - { 0x00, 0xaa, 0x00 }, /* 000010 */ - { 0x00, 0xaa, 0xaa }, /* 000011 */ - { 0xaa, 0x00, 0x00 }, /* 000100 */ - { 0xaa, 0x00, 0xaa }, /* 000101 */ - { 0xaa, 0xaa, 0x00 }, /* 000110 */ - { 0xaa, 0xaa, 0xaa }, /* 000111 */ - { 0x00, 0x00, 0x55 }, /* 001000 */ - { 0x00, 0x00, 0xff }, /* 001001 */ - { 0x00, 0xaa, 0x55 }, /* 001010 */ - { 0x00, 0xaa, 0xff }, /* 001011 */ - { 0xaa, 0x00, 0x55 }, /* 001100 */ - { 0xaa, 0x00, 0xff }, /* 001101 */ - { 0xaa, 0xaa, 0x55 }, /* 001110 */ - { 0xaa, 0xaa, 0xff }, /* 001111 */ - { 0x00, 0x55, 0x00 }, /* 010000 */ - { 0x00, 0x55, 0xaa }, /* 010001 */ - { 0x00, 0xff, 0x00 }, /* 010010 */ - { 0x00, 0xff, 0xaa }, /* 010011 */ - { 0xaa, 0x55, 0x00 }, /* 010100 */ - { 0xaa, 0x55, 0xaa }, /* 010101 */ - { 0xaa, 0xff, 0x00 }, /* 010110 */ - { 0xaa, 0xff, 0xaa }, /* 010111 */ - { 0x00, 0x55, 0x55 }, /* 011000 */ - { 0x00, 0x55, 0xff }, /* 011001 */ - { 0x00, 0xff, 0x55 }, /* 011010 */ - { 0x00, 0xff, 0xff }, /* 011011 */ - { 0xaa, 0x55, 0x55 }, /* 011100 */ - { 0xaa, 0x55, 0xff }, /* 011101 */ - { 0xaa, 0xff, 0x55 }, /* 011110 */ - { 0xaa, 0xff, 0xff }, /* 011111 */ - { 0x55, 0x00, 0x00 }, /* 100000 */ - { 0x55, 0x00, 0xaa }, /* 100001 */ - { 0x55, 0xaa, 0x00 }, /* 100010 */ - { 0x55, 0xaa, 0xaa }, /* 100011 */ - { 0xff, 0x00, 0x00 }, /* 100100 */ - { 0xff, 0x00, 0xaa }, /* 100101 */ - { 0xff, 0xaa, 0x00 }, /* 100110 */ - { 0xff, 0xaa, 0xaa }, /* 100111 */ - { 0x55, 0x00, 0x55 }, /* 101000 */ - { 0x55, 0x00, 0xff }, /* 101001 */ - { 0x55, 0xaa, 0x55 }, /* 101010 */ - { 0x55, 0xaa, 0xff }, /* 101011 */ - { 0xff, 0x00, 0x55 }, /* 101100 */ - { 0xff, 0x00, 0xff }, /* 101101 */ - { 0xff, 0xaa, 0x55 }, /* 101110 */ - { 0xff, 0xaa, 0xff }, /* 101111 */ - { 0x55, 0x55, 0x00 }, /* 110000 */ - { 0x55, 0x55, 0xaa }, /* 110001 */ - { 0x55, 0xff, 0x00 }, /* 110010 */ - { 0x55, 0xff, 0xaa }, /* 110011 */ - { 0xff, 0x55, 0x00 }, /* 110100 */ - { 0xff, 0x55, 0xaa }, /* 110101 */ - { 0xff, 0xff, 0x00 }, /* 110110 */ - { 0xff, 0xff, 0xaa }, /* 110111 */ - { 0x55, 0x55, 0x55 }, /* 111000 */ - { 0x55, 0x55, 0xff }, /* 111001 */ - { 0x55, 0xff, 0x55 }, /* 111010 */ - { 0x55, 0xff, 0xff }, /* 111011 */ - { 0xff, 0x55, 0x55 }, /* 111100 */ - { 0xff, 0x55, 0xff }, /* 111101 */ - { 0xff, 0xff, 0x55 }, /* 111110 */ - { 0xff, 0xff, 0xff }, /* 111111 */ + { 0x00, 0x00, 0x00 }, /* 000000 */ + { 0x00, 0x00, 0xaa }, /* 000001 */ + { 0x00, 0xaa, 0x00 }, /* 000010 */ + { 0x00, 0xaa, 0xaa }, /* 000011 */ + { 0xaa, 0x00, 0x00 }, /* 000100 */ + { 0xaa, 0x00, 0xaa }, /* 000101 */ + { 0xaa, 0xaa, 0x00 }, /* 000110 */ + { 0xaa, 0xaa, 0xaa }, /* 000111 */ + { 0x00, 0x00, 0x55 }, /* 001000 */ + { 0x00, 0x00, 0xff }, /* 001001 */ + { 0x00, 0xaa, 0x55 }, /* 001010 */ + { 0x00, 0xaa, 0xff }, /* 001011 */ + { 0xaa, 0x00, 0x55 }, /* 001100 */ + { 0xaa, 0x00, 0xff }, /* 001101 */ + { 0xaa, 0xaa, 0x55 }, /* 001110 */ + { 0xaa, 0xaa, 0xff }, /* 001111 */ + { 0x00, 0x55, 0x00 }, /* 010000 */ + { 0x00, 0x55, 0xaa }, /* 010001 */ + { 0x00, 0xff, 0x00 }, /* 010010 */ + { 0x00, 0xff, 0xaa }, /* 010011 */ + { 0xaa, 0x55, 0x00 }, /* 010100 */ + { 0xaa, 0x55, 0xaa }, /* 010101 */ + { 0xaa, 0xff, 0x00 }, /* 010110 */ + { 0xaa, 0xff, 0xaa }, /* 010111 */ + { 0x00, 0x55, 0x55 }, /* 011000 */ + { 0x00, 0x55, 0xff }, /* 011001 */ + { 0x00, 0xff, 0x55 }, /* 011010 */ + { 0x00, 0xff, 0xff }, /* 011011 */ + { 0xaa, 0x55, 0x55 }, /* 011100 */ + { 0xaa, 0x55, 0xff }, /* 011101 */ + { 0xaa, 0xff, 0x55 }, /* 011110 */ + { 0xaa, 0xff, 0xff }, /* 011111 */ + { 0x55, 0x00, 0x00 }, /* 100000 */ + { 0x55, 0x00, 0xaa }, /* 100001 */ + { 0x55, 0xaa, 0x00 }, /* 100010 */ + { 0x55, 0xaa, 0xaa }, /* 100011 */ + { 0xff, 0x00, 0x00 }, /* 100100 */ + { 0xff, 0x00, 0xaa }, /* 100101 */ + { 0xff, 0xaa, 0x00 }, /* 100110 */ + { 0xff, 0xaa, 0xaa }, /* 100111 */ + { 0x55, 0x00, 0x55 }, /* 101000 */ + { 0x55, 0x00, 0xff }, /* 101001 */ + { 0x55, 0xaa, 0x55 }, /* 101010 */ + { 0x55, 0xaa, 0xff }, /* 101011 */ + { 0xff, 0x00, 0x55 }, /* 101100 */ + { 0xff, 0x00, 0xff }, /* 101101 */ + { 0xff, 0xaa, 0x55 }, /* 101110 */ + { 0xff, 0xaa, 0xff }, /* 101111 */ + { 0x55, 0x55, 0x00 }, /* 110000 */ + { 0x55, 0x55, 0xaa }, /* 110001 */ + { 0x55, 0xff, 0x00 }, /* 110010 */ + { 0x55, 0xff, 0xaa }, /* 110011 */ + { 0xff, 0x55, 0x00 }, /* 110100 */ + { 0xff, 0x55, 0xaa }, /* 110101 */ + { 0xff, 0xff, 0x00 }, /* 110110 */ + { 0xff, 0xff, 0xaa }, /* 110111 */ + { 0x55, 0x55, 0x55 }, /* 111000 */ + { 0x55, 0x55, 0xff }, /* 111001 */ + { 0x55, 0xff, 0x55 }, /* 111010 */ + { 0x55, 0xff, 0xff }, /* 111011 */ + { 0xff, 0x55, 0x55 }, /* 111100 */ + { 0xff, 0x55, 0xff }, /* 111101 */ + { 0xff, 0xff, 0x55 }, /* 111110 */ + { 0xff, 0xff, 0xff }, /* 111111 */ }; +typedef struct { + mem_mapping_t mapping; -typedef struct incolor_t -{ - mem_mapping_t mapping; - - uint8_t crtc[32]; - int crtcreg; + uint8_t crtc[32]; + int crtcreg; - uint8_t ctrl, ctrl2, stat; + uint8_t ctrl, ctrl2, stat; - int64_t dispontime, dispofftime; - int64_t vidtime; - - int firstline, lastline; + uint64_t dispontime, dispofftime; + pc_timer_t timer; - int linepos, displine; - int vc, sc; - uint16_t ma, maback; - int con, coff, cursoron; - int dispon, blink; - int64_t vsynctime; - int vadj; + int firstline, lastline; - uint8_t palette[16]; /* EGA-style 16 -> 64 palette registers */ - uint8_t palette_idx; /* Palette write index */ - uint8_t latch[4]; /* Memory read/write latches */ - uint8_t *vram; + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int vsynctime; + int vadj; + + uint8_t palette[16]; /* EGA-style 16 -> 64 palette registers */ + uint8_t palette_idx; /* Palette write index */ + uint8_t latch[4]; /* Memory read/write latches */ + + uint32_t rgb[64]; + + uint8_t *vram; } incolor_t; -void incolor_recalctimings(incolor_t *incolor); -void incolor_write(uint32_t addr, uint8_t val, void *p); -uint8_t incolor_read(uint32_t addr, void *p); +static video_timings_t timing_incolor = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; -void incolor_out(uint16_t addr, uint8_t val, void *p) +static void +recalc_timings(incolor_t *dev) { - incolor_t *incolor = (incolor_t *)p; - switch (addr) - { - case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: - incolor->crtcreg = val & 31; - return; - case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: - if (incolor->crtcreg > 28) return; - /* Palette load register */ - if (incolor->crtcreg == INCOLOR_CRTC_PALETTE) - { - incolor->palette[incolor->palette_idx % 16] = val; - ++incolor->palette_idx; - } - incolor->crtc[incolor->crtcreg] = val; - if (incolor->crtc[10] == 6 && incolor->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ - { - incolor->crtc[10] = 0xb; - incolor->crtc[11] = 0xc; - } - incolor_recalctimings(incolor); - return; - case 0x3b8: - incolor->ctrl = val; - return; - case 0x3bf: - incolor->ctrl2 = val; - if (val & 2) - mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x10000); - else - mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x08000); - return; - } + double disptime; + double _dispontime, _dispofftime; + + disptime = dev->crtc[0] + 1; + _dispontime = dev->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= HERCCONST; + _dispofftime *= HERCCONST; + + dev->dispontime = (uint64_t)(_dispontime); + dev->dispofftime = (uint64_t)(_dispofftime); } -uint8_t incolor_in(uint16_t addr, void *p) + +static void +incolor_out(uint16_t port, uint8_t val, void *priv) { - incolor_t *incolor = (incolor_t *)p; - switch (addr) - { - case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: - return incolor->crtcreg; - case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: - if (incolor->crtcreg > 28) return 0xff; - incolor->palette_idx = 0; /* Read resets the palette index */ - return incolor->crtc[incolor->crtcreg]; - case 0x3ba: - /* 0x50: InColor card identity */ - return (incolor->stat & 0xf) | ((incolor->stat & 8) << 4) | 0x50; - } - return 0xff; -} + incolor_t *dev = (incolor_t *)priv; + uint8_t old; -void incolor_write(uint32_t addr, uint8_t val, void *p) -{ - incolor_t *incolor = (incolor_t *)p; - - int plane; - - unsigned char wmask = incolor->crtc[INCOLOR_CRTC_MASK]; - unsigned char wmode = incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_WRMODE; - unsigned char fg = incolor->crtc[INCOLOR_CRTC_RWCOL] & 0x0F; - unsigned char bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4)&0x0F; - unsigned char w = 0; - unsigned char vmask; /* Mask of bit within byte */ - unsigned char pmask; /* Mask of plane within colour value */ - unsigned char latch; - - egawrites++; - - addr &= 0xFFFF; - - /* In text mode, writes to the bottom 16k always touch all 4 planes */ - if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) - { - incolor->vram[addr] = val; + switch (port) { + case 0x3b0: + case 0x3b2: + case 0x3b4: + case 0x3b6: + dev->crtcreg = val & 31; return; - } - /* There are four write modes: - * 0: 1 => foreground, 0 => background - * 1: 1 => foreground, 0 => source latch - * 2: 1 => source latch, 0 => background - * 3: 1 => source latch, 0 => ~source latch - */ - pmask = 1; - for (plane = 0; plane < 4; pmask <<= 1, wmask >>= 1, addr += 0x10000, - plane++) - { - if (wmask & 0x10) /* Ignore writes to selected plane */ - { - continue; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (dev->crtcreg > 28) return; + /* Palette load register */ + if (dev->crtcreg == INCOLOR_CRTC_PALETTE) { + dev->palette[dev->palette_idx % 16] = val; + ++dev->palette_idx; + } + old = dev->crtc[dev->crtcreg]; + dev->crtc[dev->crtcreg] = val; + + if (dev->crtc[10] == 6 && dev->crtc[11] == 7) { + /*Fix for Generic Turbo XT BIOS, + * which sets up cursor registers wrong*/ + dev->crtc[10] = 0xb; + dev->crtc[11] = 0xc; } - latch = incolor->latch[plane]; - for (vmask = 0x80; vmask != 0; vmask >>= 1) - { - switch (wmode) - { - case 0x00: - if (val & vmask) w = (fg & pmask); - else w = (bg & pmask); - break; - case 0x10: - if (val & vmask) w = (fg & pmask); - else w = (latch & vmask); - break; - case 0x20: - if (val & vmask) w = (latch & vmask); - else w = (bg & pmask); - break; - case 0x30: - if (val & vmask) w = (latch & vmask); - else w = ((~latch) & vmask); - break; - } + if (old ^ val) + recalc_timings(dev); + return; + + case 0x3b8: + old = dev->ctrl; + dev->ctrl = val; + if (old ^ val) + recalc_timings(dev); + return; + + case 0x3bf: + dev->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x08000); + return; + } +} + + +static uint8_t +incolor_in(uint16_t port, void *priv) +{ + incolor_t *dev = (incolor_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x3b0: + case 0x3b2: + case 0x3b4: + case 0x3b6: + ret = dev->crtcreg; + break; + + case 0x3b1: + case 0x3b3: + case 0x3b5: + case 0x3b7: + if (dev->crtcreg > 28) break; + + dev->palette_idx = 0; /* Read resets the palette index */ + ret = dev->crtc[dev->crtcreg]; + break; + + case 0x3ba: + /* 0x50: InColor card identity */ + ret = (dev->stat & 0xf) | ((dev->stat & 8) << 4) | 0x50; + break; + + default: + break; + } + + return ret; +} + + +static void +incolor_write(uint32_t addr, uint8_t val, void *priv) +{ + incolor_t *dev = (incolor_t *)priv; + unsigned char wmask = dev->crtc[INCOLOR_CRTC_MASK]; + unsigned char wmode = dev->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_WRMODE; + unsigned char fg = dev->crtc[INCOLOR_CRTC_RWCOL] & 0x0F; + unsigned char bg = (dev->crtc[INCOLOR_CRTC_RWCOL] >> 4)&0x0F; + unsigned char w = 0; + unsigned char vmask; /* Mask of bit within byte */ + unsigned char pmask; /* Mask of plane within colour value */ + unsigned char latch; + int plane; + + addr &= 0xffff; + + /* In text mode, writes to the bottom 16k always touch all 4 planes */ + if (!(dev->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) { + dev->vram[addr] = val; + return; + } + + /* There are four write modes: + * 0: 1 => foreground, 0 => background + * 1: 1 => foreground, 0 => source latch + * 2: 1 => source latch, 0 => background + * 3: 1 => source latch, 0 => ~source latch + */ + pmask = 1; + for (plane = 0; plane < 4; pmask <<= 1, wmask >>= 1, addr += 0x10000, plane++) { + if (wmask & 0x10) /* Ignore writes to selected plane */ + { + continue; + } + latch = dev->latch[plane]; + for (vmask = 0x80; vmask != 0; vmask >>= 1) { + switch (wmode) { + case 0x00: + if (val & vmask) w = (fg & pmask); + else w = (bg & pmask); + break; + + case 0x10: + if (val & vmask) w = (fg & pmask); + else w = (latch & vmask); + break; + + case 0x20: + if (val & vmask) w = (latch & vmask); + else w = (bg & pmask); + break; + + case 0x30: + if (val & vmask) w = (latch & vmask); + else w = ((~latch) & vmask); + break; + } + /* w is nonzero to write a 1, zero to write a 0 */ - if (w) incolor->vram[addr] |= vmask; - else incolor->vram[addr] &= ~vmask; + if (w) dev->vram[addr] |= vmask; + else dev->vram[addr] &= ~vmask; + } + } +} + + +static uint8_t +incolor_read(uint32_t addr, void *priv) +{ + incolor_t *dev = (incolor_t *)priv; + unsigned plane; + unsigned char lp = dev->crtc[INCOLOR_CRTC_PROTECT]; + unsigned char value = 0; + unsigned char dc; /* "don't care" register */ + unsigned char bg; /* background colour */ + unsigned char fg; + unsigned char mask, pmask; + + addr &= 0xffff; + + /* Read the four planes into latches */ + for (plane = 0; plane < 4; plane++, addr += 0x10000) { + dev->latch[plane] &= lp; + dev->latch[plane] |= (dev->vram[addr] & ~lp); + } + addr &= 0xffff; + + /* In text mode, reads from the bottom 16k assume all planes have + * the same contents */ + if (!(dev->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) { + return dev->latch[0]; + } + + /* For each pixel, work out if its colour matches the background */ + for (mask = 0x80; mask != 0; mask >>= 1) { + fg = 0; + dc = dev->crtc[INCOLOR_CRTC_RWCTRL] & 0x0F; + bg = (dev->crtc[INCOLOR_CRTC_RWCOL] >> 4) & 0x0F; + for (plane = 0, pmask = 1; plane < 4; plane++, pmask <<= 1) { + if (dc & pmask) { + fg |= (bg & pmask); + } else if (dev->latch[plane] & mask) { + fg |= pmask; } - } -} + } + if (bg == fg) value |= mask; + } -uint8_t incolor_read(uint32_t addr, void *p) -{ - incolor_t *incolor = (incolor_t *)p; - unsigned plane; - unsigned char lp = incolor->crtc[INCOLOR_CRTC_PROTECT]; - unsigned char value = 0; - unsigned char dc; /* "don't care" register */ - unsigned char bg; /* background colour */ - unsigned char fg; - unsigned char mask, pmask; + if (dev->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY) + value = ~value; - egareads++; - - addr &= 0xFFFF; - /* Read the four planes into latches */ - for (plane = 0; plane < 4; plane++, addr += 0x10000) - { - incolor->latch[plane] &= lp; - incolor->latch[plane] |= (incolor->vram[addr] & ~lp); - } - addr &= 0xFFFF; - /* In text mode, reads from the bottom 16k assume all planes have - * the same contents */ - if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) - { - return incolor->latch[0]; - } - /* For each pixel, work out if its colour matches the background */ - for (mask = 0x80; mask != 0; mask >>= 1) - { - fg = 0; - dc = incolor->crtc[INCOLOR_CRTC_RWCTRL] & 0x0F; - bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4) & 0x0F; - for (plane = 0, pmask = 1; plane < 4; plane++, pmask <<= 1) - { - if (dc & pmask) - { - fg |= (bg & pmask); - } - else if (incolor->latch[plane] & mask) - { - fg |= pmask; - } - } - if (bg == fg) value |= mask; - } - if (incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY) - { - value = ~value; - } - return value; + return value; } - -void incolor_recalctimings(incolor_t *incolor) +static void +draw_char_rom(incolor_t *dev, int x, uint8_t chr, uint8_t attr) { - double disptime; - double _dispontime, _dispofftime; - disptime = incolor->crtc[0] + 1; - _dispontime = incolor->crtc[1]; - _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; - incolor->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - incolor->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); -} - - -static void incolor_draw_char_rom(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) -{ - unsigned i; - int elg, blk; - unsigned ull; - unsigned val; + int i; + int elg, blk; + unsigned ull; + unsigned val; unsigned ifg, ibg; const unsigned char *fnt; uint32_t fg, bg; int cw = INCOLOR_CW; blk = 0; - if (incolor->ctrl & INCOLOR_CTRL_BLINK) + if (dev->ctrl & INCOLOR_CTRL_BLINK) { if (attr & 0x80) { - blk = (incolor->blink & 16); + blk = (dev->blink & 16); } attr &= 0x7f; } - if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) { /* MDA-compatible attributes */ ibg = 0; @@ -439,19 +463,19 @@ static void incolor_draw_char_rom(incolor_t *incolor, int x, uint8_t chr, uint8_ ifg = attr & 0x0F; ibg = (attr >> 4) & 0x0F; } - if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) { - fg = incolor_rgb[incolor->palette[ifg]]; - bg = incolor_rgb[incolor->palette[ibg]]; + fg = dev->rgb[dev->palette[ifg]]; + bg = dev->rgb[dev->palette[ibg]]; } else { - fg = incolor_rgb[defpal[ifg]]; - bg = incolor_rgb[defpal[ibg]]; + fg = dev->rgb[defpal[ifg]]; + bg = dev->rgb[defpal[ibg]]; } /* ELG set to stretch 8px character to 9px */ - if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) { elg = 0; } @@ -460,13 +484,13 @@ static void incolor_draw_char_rom(incolor_t *incolor, int x, uint8_t chr, uint8_ elg = ((chr >= 0xc0) && (chr <= 0xdf)); } - fnt = &(fontdatm[chr][incolor->sc]); + fnt = &(fontdatm[chr][dev->sc]); if (blk) { val = 0x000; /* Blinking, draw all background */ } - else if (incolor->sc == ull) + else if (dev->sc == ull) { val = 0x1ff; /* Underscore, draw all foreground */ } @@ -481,32 +505,33 @@ static void incolor_draw_char_rom(incolor_t *incolor, int x, uint8_t chr, uint8_ } for (i = 0; i < cw; i++) { - ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = (val & 0x100) ? fg : bg; + buffer32->line[dev->displine][x * cw + i] = (val & 0x100) ? fg : bg; val = val << 1; } } -static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +static void +draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr) { - unsigned i; - int elg, blk; - unsigned ull; - unsigned val[4]; + int i; + int elg, blk; + unsigned ull; + unsigned val[4]; unsigned ifg, ibg, cfg, pmask, plane; const unsigned char *fnt; uint32_t fg; int cw = INCOLOR_CW; - int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; - int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; - int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + int blink = dev->ctrl & INCOLOR_CTRL_BLINK; + int altattr = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; blk = 0; if (blink) { if (attr & 0x80) { - blk = (incolor->blink & 16); + blk = (dev->blink & 16); } attr &= 0x7f; } @@ -542,7 +567,7 @@ static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8 ifg = attr & 0x0F; ibg = (attr >> 4) & 0x0F; } - if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) { elg = 0; } @@ -550,14 +575,14 @@ static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8 { elg = ((chr >= 0xc0) && (chr <= 0xdf)); } - fnt = incolor->vram + 0x4000 + 16 * chr + incolor->sc; + fnt = dev->vram + 0x4000 + 16 * chr + dev->sc; if (blk) { /* Blinking, draw all background */ val[0] = val[1] = val[2] = val[3] = 0x000; } - else if (incolor->sc == ull) + else if (dev->sc == ull) { /* Underscore, draw all foreground */ val[0] = val[1] = val[2] = val[3] = 0x1ff; @@ -591,14 +616,14 @@ static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8 if (altattr && (attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ if (palette) { - fg = incolor_rgb[incolor->palette[cfg]]; + fg = dev->rgb[dev->palette[cfg]]; } else { - fg = incolor_rgb[defpal[cfg]]; + fg = dev->rgb[defpal[cfg]]; } - ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + buffer32->line[dev->displine][x * cw + i] = fg; val[0] = val[0] << 1; val[1] = val[1] << 1; val[2] = val[2] << 1; @@ -607,19 +632,20 @@ static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8 } -static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +static void +draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) { - unsigned i; - int elg, blk, ul, ol, bld; - unsigned ull, oll, ulc = 0, olc = 0; - unsigned val[4]; + int i; + int elg, blk, ul, ol, bld; + unsigned ull, oll, ulc = 0, olc = 0; + unsigned val[4]; unsigned ifg = 0, ibg, cfg, pmask, plane; const unsigned char *fnt; uint32_t fg; int cw = INCOLOR_CW; - int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; - int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; - int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + int blink = dev->ctrl & INCOLOR_CTRL_BLINK; + int altattr = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; int font = (attr & 0x0F); if (font >= 12) font &= 7; @@ -629,7 +655,7 @@ static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint { if (attr & 0x40) { - blk = (incolor->blink & 16); + blk = (dev->blink & 16); } attr &= 0x7f; } @@ -662,8 +688,8 @@ static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint } if (ul) { - ull = incolor->crtc[INCOLOR_CRTC_UNDER] & 0x0F; - ulc = (incolor->crtc[INCOLOR_CRTC_UNDER] >> 4) & 0x0F; + ull = dev->crtc[INCOLOR_CRTC_UNDER] & 0x0F; + ulc = (dev->crtc[INCOLOR_CRTC_UNDER] >> 4) & 0x0F; if (ulc == 0) ulc = 7; } else @@ -672,8 +698,8 @@ static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint } if (ol) { - oll = incolor->crtc[INCOLOR_CRTC_OVER] & 0x0F; - olc = (incolor->crtc[INCOLOR_CRTC_OVER] >> 4) & 0x0F; + oll = dev->crtc[INCOLOR_CRTC_OVER] & 0x0F; + olc = (dev->crtc[INCOLOR_CRTC_OVER] >> 4) & 0x0F; if (olc == 0) olc = 7; } else @@ -681,7 +707,7 @@ static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint oll = 0xFFFF; } - if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) { elg = 0; } @@ -689,14 +715,14 @@ static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint { elg = ((chr >= 0xc0) && (chr <= 0xdf)); } - fnt = incolor->vram + 0x4000 + 16 * chr + 4096 * font + incolor->sc; + fnt = dev->vram + 0x4000 + 16 * chr + 4096 * font + dev->sc; if (blk) { /* Blinking, draw all background */ val[0] = val[1] = val[2] = val[3] = 0x000; } - else if (incolor->sc == ull) + else if (dev->sc == ull) { /* Underscore, draw all foreground */ val[0] = val[1] = val[2] = val[3] = 0x1ff; @@ -728,11 +754,11 @@ static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint /* Generate pixel colour */ cfg = 0; pmask = 1; - if (incolor->sc == oll) + if (dev->sc == oll) { cfg = olc ^ ibg; /* Strikethrough */ } - else if (incolor->sc == ull) + else if (dev->sc == ull) { cfg = ulc ^ ibg; /* Underline */ } @@ -750,14 +776,14 @@ static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint } if (palette) { - fg = incolor_rgb[incolor->palette[cfg]]; + fg = dev->rgb[dev->palette[cfg]]; } else { - fg = incolor_rgb[defpal[cfg]]; + fg = dev->rgb[defpal[cfg]]; } - ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + buffer32->line[dev->displine][x * cw + i] = fg; val[0] = val[0] << 1; val[1] = val[1] << 1; val[2] = val[2] << 1; @@ -766,318 +792,314 @@ static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint } - - - - -static void incolor_text_line(incolor_t *incolor, uint16_t ca) +static void +text_line(incolor_t *dev, uint16_t ca) { - int drawcursor; - int x, c; - uint8_t chr, attr; - uint32_t col; + int drawcursor; + int x, c; + uint8_t chr, attr; + uint32_t col; - for (x = 0; x < incolor->crtc[1]; x++) - { - chr = incolor->vram[(incolor->ma << 1) & 0xfff]; - attr = incolor->vram[((incolor->ma << 1) + 1) & 0xfff]; + for (x = 0; x < dev->crtc[1]; x++) { + if (dev->ctrl & 8) { + chr = dev->vram[(dev->ma << 1) & 0xfff]; + attr = dev->vram[((dev->ma << 1) + 1) & 0xfff]; + } else + chr = attr = 0; - drawcursor = ((incolor->ma == ca) && incolor->con && incolor->cursoron); + drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); - switch (incolor->crtc[INCOLOR_CRTC_XMODE] & 5) + switch (dev->crtc[INCOLOR_CRTC_XMODE] & 5) { + case 0: + case 4: /* ROM font */ + draw_char_rom(dev, x, chr, attr); + break; + + case 1: /* 4k RAMfont */ + draw_char_ram4(dev, x, chr, attr); + break; + + case 5: /* 48k RAMfont */ + draw_char_ram48(dev, x, chr, attr); + break; + } + ++dev->ma; + + if (drawcursor) { + int cw = INCOLOR_CW; + uint8_t ink = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_CURSOR; + if (ink == 0) ink = (attr & 0x08) | 7; + + /* In MDA-compatible mode, cursor brightness comes from + * background */ + if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) { - case 0: - case 4: /* ROM font */ - incolor_draw_char_rom(incolor, x, chr, attr); - break; - case 1: /* 4k RAMfont */ - incolor_draw_char_ram4(incolor, x, chr, attr); - break; - case 5: /* 48k RAMfont */ - incolor_draw_char_ram48(incolor, x, chr, attr); - break; - + ink = (attr & 0x08) | (ink & 7); } - ++incolor->ma; - if (drawcursor) - { - int cw = INCOLOR_CW; - uint8_t ink = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_CURSOR; - if (ink == 0) ink = (attr & 0x08) | 7; - - /* In MDA-compatible mode, cursor brightness comes from - * background */ - if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) - { - ink = (attr & 0x08) | (ink & 7); - } - if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) - { - col = incolor_rgb[incolor->palette[ink]]; - } - else - { - col = incolor_rgb[defpal[ink]]; - } - for (c = 0; c < cw; c++) - { - ((uint32_t *)buffer32->line[incolor->displine])[x * cw + c] = col; - } + if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + { + col = dev->rgb[dev->palette[ink]]; + } + else + { + col = dev->rgb[defpal[ink]]; + } + for (c = 0; c < cw; c++) + { + buffer32->line[dev->displine][x * cw + c] = col; } } + } } -static void incolor_graphics_line(incolor_t *incolor) +static void +graphics_line(incolor_t *dev) { - uint8_t mask; - uint16_t ca; - int x, c, plane, col; - uint8_t ink; - uint16_t val[4]; + uint8_t mask; + uint16_t ca; + int x, c, plane, col; + uint8_t ink; + uint16_t val[4]; - /* Graphics mode. */ - ca = (incolor->sc & 3) * 0x2000; - if ((incolor->ctrl & INCOLOR_CTRL_PAGE1) && (incolor->ctrl2 & INCOLOR_CTRL2_PAGE1)) - ca += 0x8000; + /* Graphics mode. */ + ca = (dev->sc & 3) * 0x2000; + if ((dev->ctrl & INCOLOR_CTRL_PAGE1) && (dev->ctrl2 & INCOLOR_CTRL2_PAGE1)) + ca += 0x8000; - for (x = 0; x < incolor->crtc[1]; x++) + for (x = 0; x < dev->crtc[1]; x++) { + mask = dev->crtc[INCOLOR_CRTC_MASK]; /* Planes to display */ + for (plane = 0; plane < 4; plane++, mask = mask >> 1) { - mask = incolor->crtc[INCOLOR_CRTC_MASK]; /* Planes to display */ - for (plane = 0; plane < 4; plane++, mask = mask >> 1) - { + if (dev->ctrl & 8) { if (mask & 1) - val[plane] = (incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | - incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + val[plane] = (dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | + dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; else val[plane] = 0; - } - incolor->ma++; - for (c = 0; c < 16; c++) + } else + val[plane] = 0; + } + dev->ma++; + + for (c = 0; c < 16; c++) + { + ink = 0; + for (plane = 0; plane < 4; plane++) { - ink = 0; - for (plane = 0; plane < 4; plane++) - { - ink = ink >> 1; - if (val[plane] & 0x8000) ink |= 8; - val[plane] = val[plane] << 1; - } - /* Is palette in use? */ - if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) - col = incolor->palette[ink]; - else col = defpal[ink]; - - ((uint32_t *)buffer32->line[incolor->displine])[(x << 4) + c] = incolor_rgb[col]; + ink = ink >> 1; + if (val[plane] & 0x8000) ink |= 8; + val[plane] = val[plane] << 1; } + /* Is palette in use? */ + if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + col = dev->palette[ink]; + else col = defpal[ink]; + + buffer32->line[dev->displine][(x << 4) + c] = dev->rgb[col]; } + } } -void incolor_poll(void *p) + +static void +incolor_poll(void *priv) { - incolor_t *incolor = (incolor_t *)p; - uint16_t ca = (incolor->crtc[15] | (incolor->crtc[14] << 8)) & 0x3fff; - int x; - int oldvc; - int oldsc; + incolor_t *dev = (incolor_t *)priv; + uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; + int x; + int oldvc; + int oldsc; - if (!incolor->linepos) - { - incolor->vidtime += incolor->dispofftime; - incolor->stat |= 1; - incolor->linepos = 1; - oldsc = incolor->sc; - if ((incolor->crtc[8] & 3) == 3) - incolor->sc = (incolor->sc << 1) & 7; - if (incolor->dispon) - { - if (incolor->displine < incolor->firstline) - { - incolor->firstline = incolor->displine; - video_wait_for_buffer(); - } - incolor->lastline = incolor->displine; - if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) - { - incolor_graphics_line(incolor); - } - else - { - incolor_text_line(incolor, ca); - } - } - incolor->sc = oldsc; - if (incolor->vc == incolor->crtc[7] && !incolor->sc) - { - incolor->stat |= 8; - } - incolor->displine++; - if (incolor->displine >= 500) - incolor->displine = 0; - } - else - { - incolor->vidtime += incolor->dispontime; - if (incolor->dispon) - incolor->stat &= ~1; - incolor->linepos = 0; - if (incolor->vsynctime) - { - incolor->vsynctime--; - if (!incolor->vsynctime) - { - incolor->stat &= ~8; - } - } - if (incolor->sc == (incolor->crtc[11] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[11] & 31) >> 1))) - { - incolor->con = 0; - incolor->coff = 1; - } - if (incolor->vadj) - { - incolor->sc++; - incolor->sc &= 31; - incolor->ma = incolor->maback; - incolor->vadj--; - if (!incolor->vadj) - { - incolor->dispon = 1; - incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; - incolor->sc = 0; - } - } - else if (incolor->sc == incolor->crtc[9] || ((incolor->crtc[8] & 3) == 3 && incolor->sc == (incolor->crtc[9] >> 1))) - { - incolor->maback = incolor->ma; - incolor->sc = 0; - oldvc = incolor->vc; - incolor->vc++; - incolor->vc &= 127; - if (incolor->vc == incolor->crtc[6]) - incolor->dispon = 0; - if (oldvc == incolor->crtc[4]) - { - incolor->vc = 0; - incolor->vadj = incolor->crtc[5]; - if (!incolor->vadj) incolor->dispon=1; - if (!incolor->vadj) incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; - if ((incolor->crtc[10] & 0x60) == 0x20) incolor->cursoron = 0; - else incolor->cursoron = incolor->blink & 16; - } - if (incolor->vc == incolor->crtc[7]) - { - incolor->dispon = 0; - incolor->displine = 0; - incolor->vsynctime = 16; - if (incolor->crtc[7]) - { - if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) - { - x = incolor->crtc[1] << 4; - } - else - { - x = incolor->crtc[1] * 9; - } - incolor->lastline++; - if ((x != xsize) || ((incolor->lastline - incolor->firstline) != ysize) || video_force_resize_get()) - { - xsize = x; - ysize = incolor->lastline - incolor->firstline; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, ysize); + if (! dev->linepos) { + timer_advance_u64(&dev->timer, dev->dispofftime); + dev->stat |= 1; + dev->linepos = 1; + oldsc = dev->sc; + if ((dev->crtc[8] & 3) == 3) + dev->sc = (dev->sc << 1) & 7; - if (video_force_resize_get()) - video_force_resize_set(0); - } - video_blit_memtoscreen(0, incolor->firstline, 0, incolor->lastline - incolor->firstline, xsize, incolor->lastline - incolor->firstline); - frames++; - if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) - { - video_res_x = incolor->crtc[1] * 16; - video_res_y = incolor->crtc[6] * 4; - video_bpp = 1; - } - else - { - video_res_x = incolor->crtc[1]; - video_res_y = incolor->crtc[6]; - video_bpp = 0; - } - } - incolor->firstline = 1000; - incolor->lastline = 0; - incolor->blink++; - } - } - else - { - incolor->sc++; - incolor->sc &= 31; - incolor->ma = incolor->maback; - } - if ((incolor->sc == (incolor->crtc[10] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[10] & 31) >> 1)))) - { - incolor->con = 1; - } - } -} - -void *incolor_init(const device_t *info) -{ - int c; - incolor_t *incolor = malloc(sizeof(incolor_t)); - memset(incolor, 0, sizeof(incolor_t)); - - incolor->vram = malloc(0x40000); /* 4 planes of 64k */ - - timer_add(incolor_poll, &incolor->vidtime, TIMER_ALWAYS_ENABLED, incolor); - mem_mapping_add(&incolor->mapping, 0xb0000, 0x08000, incolor_read, NULL, NULL, incolor_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, incolor); - io_sethandler(0x03b0, 0x0010, incolor_in, NULL, NULL, incolor_out, NULL, NULL, incolor); - - for (c = 0; c < 64; c++) - { - incolor_rgb[c] = makecol32(init_rgb[c][0], init_rgb[c][1], init_rgb[c][2]); + if (dev->dispon) { + if (dev->displine < dev->firstline) { + dev->firstline = dev->displine; + video_wait_for_buffer(); + } + dev->lastline = dev->displine; + if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH)) + graphics_line(dev); + else + text_line(dev, ca); + } + dev->sc = oldsc; + if (dev->vc == dev->crtc[7] && !dev->sc) + dev->stat |= 8; + dev->displine++; + if (dev->displine >= 500) + dev->displine = 0; + } else { + timer_advance_u64(&dev->timer, dev->dispontime); + if (dev->dispon) + dev->stat &= ~1; + dev->linepos = 0; + if (dev->vsynctime) { + dev->vsynctime--; + if (! dev->vsynctime) + dev->stat &= ~8; } -/* Initialise CRTC regs to safe values */ - incolor->crtc[INCOLOR_CRTC_MASK ] = 0x0F; /* All planes displayed */ - incolor->crtc[INCOLOR_CRTC_RWCTRL] = INCOLOR_RWCTRL_POLARITY; - incolor->crtc[INCOLOR_CRTC_RWCOL ] = 0x0F; /* White on black */ - incolor->crtc[INCOLOR_CRTC_EXCEPT] = INCOLOR_EXCEPT_ALTATTR; - for (c = 0; c < 16; c++) - { - incolor->palette[c] = defpal[c]; + if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { + dev->con = 0; + dev->coff = 1; } - incolor->palette_idx = 0; - lpt3_init(0x3BC); + if (dev->vadj) { + dev->sc++; + dev->sc &= 31; + dev->ma = dev->maback; + dev->vadj--; + if (! dev->vadj) { + dev->dispon = 1; + dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->sc = 0; + } + } else if (dev->sc == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) { + dev->maback = dev->ma; + dev->sc = 0; + oldvc = dev->vc; + dev->vc++; + dev->vc &= 127; + if (dev->vc == dev->crtc[6]) + dev->dispon = 0; + if (oldvc == dev->crtc[4]) { + dev->vc = 0; + dev->vadj = dev->crtc[5]; + if (!dev->vadj) dev->dispon=1; + if (!dev->vadj) dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + if ((dev->crtc[10] & 0x60) == 0x20) dev->cursoron = 0; + else dev->cursoron = dev->blink & 16; + } - return incolor; + if (dev->vc == dev->crtc[7]) { + dev->dispon = 0; + dev->displine = 0; + dev->vsynctime = 16; + if (dev->crtc[7]) { + if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH)) + x = dev->crtc[1] << 4; + else + x = dev->crtc[1] * 9; + dev->lastline++; + if ((dev->ctrl & 8) && + ((x != xsize) || ((dev->lastline - dev->firstline) != ysize) || video_force_resize_get())) { + xsize = x; + ysize = dev->lastline - dev->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, dev->firstline, 0, dev->lastline - dev->firstline, xsize, dev->lastline - dev->firstline); + frames++; + if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH)) { + video_res_x = dev->crtc[1] * 16; + video_res_y = dev->crtc[6] * 4; + video_bpp = 1; + } else { + video_res_x = dev->crtc[1]; + video_res_y = dev->crtc[6]; + video_bpp = 0; + } + } + dev->firstline = 1000; + dev->lastline = 0; + dev->blink++; + } + } else { + dev->sc++; + dev->sc &= 31; + dev->ma = dev->maback; + } + + if ((dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1)))) + dev->con = 1; + } } -void incolor_close(void *p) -{ - incolor_t *incolor = (incolor_t *)p; - free(incolor->vram); - free(incolor); +static void * +incolor_init(const device_t *info) +{ + incolor_t *dev; + int c; + + dev = (incolor_t *)malloc(sizeof(incolor_t)); + memset(dev, 0x00, sizeof(incolor_t)); + + dev->vram = (uint8_t *)malloc(0x40000); /* 4 planes of 64k */ + + timer_add(&dev->timer, incolor_poll, dev, 1); + + mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, + incolor_read,NULL,NULL, incolor_write,NULL,NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + + io_sethandler(0x03b0, 16, + incolor_in,NULL,NULL, incolor_out,NULL,NULL, dev); + + for (c = 0; c < 64; c++) { + dev->rgb[c] = makecol32(init_rgb[c][0], init_rgb[c][1], init_rgb[c][2]); + } + + /* Initialise CRTC regs to safe values */ + dev->crtc[INCOLOR_CRTC_MASK ] = 0x0F; /* All planes displayed */ + dev->crtc[INCOLOR_CRTC_RWCTRL] = INCOLOR_RWCTRL_POLARITY; + dev->crtc[INCOLOR_CRTC_RWCOL ] = 0x0F; /* White on black */ + dev->crtc[INCOLOR_CRTC_EXCEPT] = INCOLOR_EXCEPT_ALTATTR; + for (c = 0; c < 16; c++) + dev->palette[c] = defpal[c]; + dev->palette_idx = 0; + + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_incolor); + + /* Force the LPT3 port to be enabled. */ + lpt3_init(0x3BC); + + return dev; } -void incolor_speed_changed(void *p) + +static void +incolor_close(void *priv) { - incolor_t *incolor = (incolor_t *)p; - - incolor_recalctimings(incolor); + incolor_t *dev = (incolor_t *)priv; + + if (!dev) + return; + + if (dev->vram) + free(dev->vram); + + free(dev); } -const device_t incolor_device = + +static void +speed_changed(void *priv) { - "Hercules InColor", - DEVICE_ISA, 0, - incolor_init, incolor_close, NULL, - NULL, - incolor_speed_changed, - NULL, - NULL + incolor_t *dev = (incolor_t *)priv; + + recalc_timings(dev); +} + + +const device_t incolor_device = { + "Hercules InColor", + DEVICE_ISA, + 0, + incolor_init, incolor_close, NULL, + NULL, + speed_changed, + NULL, + NULL }; diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index 51921bd78..2651e30ea 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -8,13 +8,13 @@ * * MDA emulation. * - * Version: @(#)vid_mda.c 1.0.11 2018/04/26 + * Version: @(#)vid_mda.c 1.0.14 2019/11/24 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -23,43 +23,19 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../lpt.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_mda.h" - -typedef struct mda_t -{ - mem_mapping_t mapping; - - uint8_t crtc[32]; - int crtcreg; - - uint8_t ctrl, stat; - - int64_t dispontime, dispofftime; - int64_t vidtime; - - int firstline, lastline; - - int linepos, displine; - int vc, sc; - uint16_t ma, maback; - int con, coff, cursoron; - int dispon, blink; - int64_t vsynctime; - int vadj; - - uint8_t *vram; -} mda_t; - static int mdacols[256][2][2]; +static video_timings_t timing_mda = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + void mda_recalctimings(mda_t *mda); void mda_out(uint16_t addr, uint8_t val, void *p) @@ -122,8 +98,8 @@ void mda_recalctimings(mda_t *mda) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - mda->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - mda->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + mda->dispontime = (uint64_t)(_dispontime); + mda->dispofftime = (uint64_t)(_dispofftime); } void mda_poll(void *p) @@ -138,7 +114,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; @@ -149,6 +125,7 @@ void mda_poll(void *p) 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++) @@ -160,20 +137,20 @@ 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]; + 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]; + buffer32->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][mda->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer32->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][mda->sc] & 1]; + else 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]; + buffer32->line[mda->displine][(x * 9) + c] ^= mdacols[attr][0][1]; } } } @@ -188,7 +165,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) @@ -279,18 +256,9 @@ void mda_poll(void *p) } } - -void *mda_init(const device_t *info) +void mda_init(mda_t *mda) { - int c; - mda_t *mda = malloc(sizeof(mda_t)); - memset(mda, 0, sizeof(mda_t)); - - mda->vram = malloc(0x1000); - - timer_add(mda_poll, &mda->vidtime, TIMER_ALWAYS_ENABLED, mda); - mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, mda); - io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + int c; for (c = 0; c < 256; c++) { @@ -318,13 +286,34 @@ void *mda_init(const device_t *info) { cga_palette = 0; } - cgapal_rebuild(); + cgapal_rebuild(); + + timer_add(&mda->timer, mda_poll, mda, 1); +} + +void *mda_standalone_init(const device_t *info) +{ + mda_t *mda = malloc(sizeof(mda_t)); + memset(mda, 0, sizeof(mda_t)); + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_mda); + + mda->vram = malloc(0x1000); + + 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); + + mda_init(mda); lpt3_init(0x3BC); return mda; } +void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink) +{ + mdacols[chr][blink][fg] = 16 + cga_ink; +} + void mda_close(void *p) { mda_t *mda = (mda_t *)p; @@ -372,7 +361,7 @@ const device_t mda_device = { "MDA", DEVICE_ISA, 0, - mda_init, mda_close, NULL, + mda_standalone_init, mda_close, NULL, NULL, mda_speed_changed, NULL, diff --git a/src/video/vid_mda.h b/src/video/vid_mda.h index 4e1e78e41..82a8f5e19 100644 --- a/src/video/vid_mda.h +++ b/src/video/vid_mda.h @@ -1,4 +1,40 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ +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; + int vadj; + + uint8_t *vram; +} mda_t; + +void mda_init(mda_t *mda); +void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink); +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); + +#ifdef EMU_DEVICE_H extern const device_t mda_device; +#endif diff --git a/src/video/vid_nv_riva128.c b/src/video/vid_nv_riva128.c deleted file mode 100644 index a74569153..000000000 --- a/src/video/vid_nv_riva128.c +++ /dev/null @@ -1,3711 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * nVidia RIVA 128 emulation. - * - * Version: @(#)vid_nv_riva128.c 1.0.7 2018/04/29 - * - * Author: Melissa Goad - * Miran Grca, - * - * Copyright 2015-2018 Melissa Goad. - * Copyright 2015-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "../86box.h" -#include "../cpu/cpu.h" -#include "../machine/machine.h" -#include "../io.h" -#include "../mem.h" -#include "../pci.h" -#include "../pic.h" -#include "../rom.h" -#include "../timer.h" -#include "../device.h" -#include "../plat.h" -#include "video.h" -#include "vid_nv_riva128.h" -#include "vid_svga.h" -#include "vid_svga_render.h" - - -typedef struct riva128_t -{ - mem_mapping_t linear_mapping; - mem_mapping_t ramin_mapping; - mem_mapping_t mmio_mapping; - - rom_t bios_rom; - - svga_t svga; - - uint8_t card_id; - int pci_card; - int is_nv3t; - - uint16_t vendor_id; - uint16_t device_id; - - uint32_t linear_base, linear_size; - - uint16_t rma_addr; - - uint8_t pci_regs[256]; - - int memory_size; - - uint8_t ext_regs_locked; - - uint8_t read_bank; - uint8_t write_bank; - - struct - { - uint32_t intr; - uint32_t intr_en; - uint32_t intr_line; - uint32_t enable; - } pmc; - - struct - { - uint32_t intr; - uint32_t intr_en; - } pbus; - - struct - { - uint32_t cache_error; - uint32_t intr; - uint32_t intr_en; - - uint32_t ramht; - uint32_t ramht_addr; - uint32_t ramht_size; - - uint32_t ramfc; - uint32_t ramfc_addr; - - uint32_t ramro; - uint32_t ramro_addr; - uint32_t ramro_size; - - uint16_t chan_mode; - uint16_t chan_dma; - uint16_t chan_size; //0 = 1024, 1 = 512 - - uint32_t runout_put, runout_get; - - struct - { - uint32_t dmaput; - uint32_t dmaget; - } channels[16]; - - struct - { - int chanid; - int push_enabled; - int runout; - uint32_t get, put; - uint32_t ctx; - } caches[2]; - - struct - { - int subchan; - uint16_t method; - uint32_t param; - } cache0, cache1[64]; - } pfifo; - - struct - { - uint32_t addr; - uint32_t data; - uint8_t access_reg[4]; - uint8_t mode; - } rma; - - struct - { - uint32_t intr, intr_en; - - uint64_t time; - uint32_t alarm; - - uint16_t clock_mul, clock_div; - } ptimer; - - struct - { - int width; - int bpp; - uint32_t config_0; - } pfb; - - struct - { - uint32_t boot_0; - } pextdev; - - struct - { - int pgraph_speedhack; - - uint32_t obj_handle[8]; - uint16_t obj_class[8]; - - uint32_t debug[5]; - - uint32_t intr; - uint32_t intr_en; - - uint32_t invalid; - uint32_t invalid_en; - - uint32_t ctx_switch[5]; - uint32_t ctx_control; - uint32_t ctx_user; - uint32_t ctx_cache[8][5]; - - uint32_t fifo_enable; - - uint32_t fifo_st2_addr; - uint32_t fifo_st2_data; - - uint32_t uclip_xmin, uclip_ymin, uclip_xmax, uclip_ymax; - uint32_t oclip_xmin, oclip_ymin, oclip_xmax, oclip_ymax; - - uint32_t src_canvas_min, src_canvas_max; - uint32_t dst_canvas_min, dst_canvas_max; - - uint8_t rop; - - uint32_t chroma; - - uint32_t beta; - - uint32_t notify; - - //NV4+ - uint32_t surf_base[6]; - uint32_t surf_limit[6]; - - //NV3 - uint32_t surf_offset[4]; - uint32_t surf_pitch[4]; - - uint32_t cliprect_min[2]; - uint32_t cliprect_max[2]; - uint32_t cliprect_ctrl; - - uint32_t instance; - - uint32_t dma_intr, dma_intr_en; - - uint32_t status; - - struct - { - uint32_t point_color; - int32_t point_x[0x20], point_y[0x20]; - } speedhack; - } pgraph; - - struct - { - uint32_t nvpll; - uint32_t nv_m,nv_n,nv_p; - - uint32_t mpll; - uint32_t m_m,m_n,m_p; - - uint32_t vpll; - uint32_t v_m,v_n,v_p; - - uint32_t pll_ctrl; - - uint32_t gen_ctrl; - } pramdac; - - uint32_t pramin[0x80000]; - - uint32_t channels[16][8][0x2000]; - - struct - { - int scl; - int sda; - enum - { - I2C_START, I2C_STOP, I2C_WAITACK, I2C_READ, I2C_WRITE - } state; - unsigned addrbits; - unsigned databits; - uint8_t addr; //actually 7 bits - uint8_t data; - struct - { - uint8_t addr; //actually 7 bits - uint8_t edid_rom[128]; - } edid_rom; - } i2c; - - int64_t mtime, mfreq; - int64_t nvtime, nvfreq; - int64_t menable; - int64_t nvenable; -} riva128_t; - -//Internally, the RIVA 128 operates in a weird 38-bit color depth, with 10 bits for RGB, and 8 bits for alpha, according to envytools. -typedef struct -{ - uint8_t a; - unsigned r : 10; - unsigned g : 10; - unsigned b : 10; -} riva128_color_t; - -const char* riva128_pmc_interrupts[32] = -{ - "","","","","PMEDIA","","","","PFIFO","","","","PGRAPH","","","","PRAMDAC.VIDEO","","","","PTIMER","","","","PCRTC","","","","PBUS","","","" -}; - -const char* riva128_pbus_interrupts[32] = -{ - "BUS_ERROR","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" -}; - -const char* riva128_pfifo_interrupts[32] = -{ - "CACHE_ERROR","","","","RUNOUT","","","","RUNOUT_OVERFLOW","","","","DMA_PUSHER","","","","DMA_PTE","","","","","","","","","","","","","","","" -}; - - uint32_t riva128_ramht_lookup(uint32_t handle, void *p); -// void riva128_pgraph_volatile_reset(void *p); - - uint8_t riva128_pci_read(int func, int addr, void *p); - void riva128_pci_write(int func, int addr, uint8_t val, void *p); - - uint8_t riva128_in(uint16_t addr, void *p); - void riva128_out(uint16_t addr, uint8_t val, void *p); - - void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p); - -#ifdef ENABLE_NV_RIVA_LOG -int nv_riva_do_log = ENABLE_NV_RIVA_LOG; -#endif - - -static void -nv_riva_log(const char *fmt, ...) -{ -#ifdef ENABLE_NV_RIVA_LOG - va_list ap; - - if (nv_riva_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - -/* riva128_color_t riva128_pgraph_expand_color(uint32_t ctx, uint32_t color) -{ - riva128_color_t ret; - int format = ctx & 7; - int alpha_enable = (ctx >> 3) & 1; - - switch(format) - { - default: - nv_riva_log("RIVA 128 Unknown color format %i found!\n", format); - ret.a = 0x0; - break; - case 0: - ret.a = ((color >> 15) & 1) * 0xff; - ret.r = ((color >> 10) & 0x1f) << 5; - ret.g = ((color >> 5) & 0x1f) << 5; - ret.b = ((color >> 0) & 0x1f) << 5; - break; - case 1: - ret.a = ((color >> 24) & 0xff); - ret.r = ((color >> 16) & 0xff) << 2; - ret.g = ((color >> 8) & 0xff) << 2; - ret.b = ((color >> 0) & 0xff) << 2; - break; - case 2: - ret.a = ((color >> 30) & 3) * 0x55; - ret.r = ((color >> 20) & 0x3ff); - ret.g = ((color >> 10) & 0x3ff); - ret.b = ((color >> 0) & 0x3ff); - break; - case 3: - ret.a = ((color >> 8) & 0xff); - ret.r = ret.g = ret.b = ((color >> 0) & 0xff) << 2; - break; - case 4: - ret.a = ((color >> 16) & 0xffff) >> 8; - ret.r = ret.g = ret.b = ((color >> 0) & 0xffff) >> 6; - break; - } - - if(!alpha_enable) ret.a = 0xff; - - return ret; -} - - uint32_t riva128_pgraph_blend_factor(uint32_t alpha, uint32_t beta) -{ - if(beta == 0xff) return alpha; - if(alpha == 0xff) return beta; - alpha >>= 4; - beta >>= 3; - return (alpha * beta) >> 1; -} - - uint32_t riva128_pgraph_do_blend(uint32_t factor, uint32_t dst, uint32_t src, int is_r5g5b5) -{ - factor &= 0xf8; - if(factor == 0xf8) return src; - if(!factor) return dst; - src >>= 2; - dst >>= 2; - if(is_r5g5b5) - { - src &= 0xf8; - dst &= 0xf8; - } - return ((dst * (0x100 - factor)) + (src * factor)) >> 6; -}*/ - - uint8_t riva128_pmc_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - - //nv_riva_log("RIVA 128 PMC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - if(riva128->card_id == 0x03) switch(addr) - { - case 0x000000: - ret = 0x00; - break; - case 0x000001: - ret = 0x01; - break; - case 0x000002: - ret = 0x03; - break; - case 0x000003: - ret = 0x00; - break; - } - else if(riva128->card_id == 0x04) switch(addr) - { - case 0x000000: - ret = 0x00; - break; - case 0x000001: - ret = 0x40; - break; - case 0x000002: - ret = 0x00; - break; - case 0x000003: - ret = 0x00; - break; - } - else if(riva128->card_id == 0x05) switch(addr) - { - case 0x000000: - ret = 0x00; - break; - case 0x000001: - ret = 0x40; - break; - case 0x000002: - ret = 0x10; - break; - case 0x000003: - ret = 0x00; - break; - } - switch(addr) - { - case 0x000100: - ret = riva128->pmc.intr & 0xff; - break; - case 0x000101: - ret = (riva128->pmc.intr >> 8) & 0xff; - break; - case 0x000102: - ret = (riva128->pmc.intr >> 16) & 0xff; - break; - case 0x000103: - ret = (riva128->pmc.intr >> 24) & 0xff; - break; - case 0x000140: - ret = riva128->pmc.intr & 0xff; - break; - case 0x000141: - ret = (riva128->pmc.intr_en >> 8) & 0xff; - break; - case 0x000142: - ret = (riva128->pmc.intr_en >> 16) & 0xff; - break; - case 0x000143: - ret = (riva128->pmc.intr_en >> 24) & 0xff; - break; - case 0x000160: - ret = riva128->pmc.intr_line & 0xff; - break; - case 0x000161: - ret = (riva128->pmc.intr_line >> 8) & 0xff; - break; - case 0x000162: - ret = (riva128->pmc.intr_line >> 16) & 0xff; - break; - case 0x000163: - ret = (riva128->pmc.intr_line >> 24) & 0xff; - break; - case 0x000200: - ret = riva128->pmc.enable & 0xff; - break; - case 0x000201: - ret = (riva128->pmc.enable >> 8) & 0xff; - break; - case 0x000202: - ret = (riva128->pmc.enable >> 16) & 0xff; - break; - case 0x000203: - ret = (riva128->pmc.enable >> 24) & 0xff; - break; - } - - return ret; -} - - void riva128_pmc_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - //nv_riva_log("RIVA 128 PMC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x000100: - { - uint32_t tmp = riva128->pmc.intr & ~val; - pci_clear_irq(riva128->pci_card, PCI_INTA); - riva128->pmc.intr = tmp; - break; - } - case 0x000140: - riva128->pmc.intr_en = val & 3; - break; - case 0x000200: - riva128->pmc.enable = val; - break; - } -} - - void riva128_pmc_interrupt(int num, void *p) -{ - //nv_riva_log("RIVA 128 PMC interrupt #%d fired!\n", num); - riva128_t *riva128 = (riva128_t *)p; - - riva128->pmc.intr |= (1 << num); - - if(riva128->pmc.intr_en & 1) - { - pci_set_irq(riva128->pci_card, PCI_INTA); - } -} - - uint8_t riva128_pbus_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - - //nv_riva_log("RIVA 128 PBUS read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x001100: - ret = riva128->pbus.intr & 0xff; - break; - case 0x001101: - ret = (riva128->pbus.intr >> 8) & 0xff; - break; - case 0x001102: - ret = (riva128->pbus.intr >> 16) & 0xff; - break; - case 0x001103: - ret = (riva128->pbus.intr >> 24) & 0xff; - break; - case 0x001140: - ret = riva128->pbus.intr & 0xff; - break; - case 0x001141: - ret = (riva128->pbus.intr_en >> 8) & 0xff; - break; - case 0x001142: - ret = (riva128->pbus.intr_en >> 16) & 0xff; - break; - case 0x001143: - ret = (riva128->pbus.intr_en >> 24) & 0xff; - break; - } - - if((addr >= 0x001800) && (addr <= 0x0018ff)) ret = riva128_pci_read(0, addr - 0x1800, riva128); - - return ret; -} - - void riva128_pbus_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - //nv_riva_log("RIVA 128 PBUS write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x001100: - riva128->pbus.intr &= ~val; - break; - case 0x001140: - riva128->pbus.intr_en = val; - break; - } - - if((addr >= 0x001800) && (addr <= 0x0018ff)) - { - riva128_pci_write(0, (addr & 0xfc) + 0, (val >> 0) & 0xff, riva128); - riva128_pci_write(0, (addr & 0xfc) + 1, (val >> 8) & 0xff, riva128); - riva128_pci_write(0, (addr & 0xfc) + 2, (val >> 16) & 0xff, riva128); - riva128_pci_write(0, (addr & 0xfc) + 3, (val >> 24) & 0xff, riva128); - } -} - -void riva128_pfifo_interrupt(int num, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->pfifo.intr |= (1 << num); - - if(num == 0) riva128->pfifo.cache_error = 0x11; - - riva128_pmc_interrupt(8, riva128); -} - -uint32_t riva128_pfifo_runout_next(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint32_t next = (riva128->pfifo.runout_put + 8) & ((riva128->pfifo.ramro_size) - 1); - return next; -} - -uint32_t riva128_pfifo_cache1_next(uint32_t ptr) -{ - //Apparently, PFIFO's CACHE1 uses some sort of Gray code... oh well - int bits = 5; - uint32_t tmp = ptr >> 2; - if(tmp == (1 << (bits - 1))) return 0; - for(int bit = bits - 1;bit > 0;bit--) - { - if(tmp == (1 << (bit - 1))) return ptr ^ (1 << (2 + bit)); - if(tmp & (1 << bit)) tmp ^= 3 << (bit - 1); - } - return ptr ^ 4; -} - -uint32_t riva128_pfifo_cache1_lin(uint32_t ptr) -{ - int bits = 5; - uint32_t res = 0; - uint32_t tmp = ptr >> 2; - for(int bit = bits = 1; bit > 0; bit--) - { - if(tmp & (1 << bit)) - { - tmp ^= 3 << (bit - 1); - res ^= 4 << bit; - } - } - if(tmp & 1) res ^= 4; - return res; -} - -uint32_t riva128_pfifo_cache1_free(uint32_t chid, void* p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint32_t get = riva128_pfifo_cache1_lin(riva128->pfifo.caches[1].get); - uint32_t put = riva128_pfifo_cache1_lin(riva128->pfifo.caches[1].put); - - if(riva128->pfifo.caches[1].runout) return 0; - if(chid != riva128->pfifo.caches[1].chanid || !riva128->pfifo.caches[1].push_enabled) - { - if(riva128->pfifo.caches[1].get != riva128->pfifo.caches[1].put) return 0; - return 0x7c; - } - return (get - put - 4) & 0x7c; -} - - uint8_t riva128_pfifo_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - - // nv_riva_log("RIVA 128 PFIFO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x002080: - ret = riva128->pfifo.cache_error & 0xff; - break; - case 0x002081: - ret = (riva128->pfifo.cache_error >> 8) & 0xff; - break; - case 0x002082: - ret = (riva128->pfifo.cache_error >> 16) & 0xff; - break; - case 0x002083: - ret = (riva128->pfifo.cache_error >> 24) & 0xff; - break; - case 0x002100: - ret = riva128->pfifo.intr & 0xff; - break; - case 0x002101: - ret = (riva128->pfifo.intr >> 8) & 0xff; - break; - case 0x002102: - ret = (riva128->pfifo.intr >> 16) & 0xff; - break; - case 0x002103: - ret = (riva128->pfifo.intr >> 24) & 0xff; - break; - case 0x002140: - ret = riva128->pfifo.intr_en & 0xff; - break; - case 0x002141: - ret = (riva128->pfifo.intr_en >> 8) & 0xff; - break; - case 0x002142: - ret = (riva128->pfifo.intr_en >> 16) & 0xff; - break; - case 0x002143: - ret = (riva128->pfifo.intr_en >> 24) & 0xff; - break; - case 0x002210: - ret = riva128->pfifo.ramht & 0xff; - break; - case 0x002211: - ret = (riva128->pfifo.ramht >> 8) & 0xff; - break; - case 0x002212: - ret = (riva128->pfifo.ramht >> 16) & 0xff; - break; - case 0x002213: - ret = (riva128->pfifo.ramht >> 24) & 0xff; - break; - case 0x002214: - ret = riva128->pfifo.ramfc & 0xff; - break; - case 0x002215: - ret = (riva128->pfifo.ramfc >> 8) & 0xff; - break; - case 0x002216: - ret = (riva128->pfifo.ramfc >> 16) & 0xff; - break; - case 0x002217: - ret = (riva128->pfifo.ramfc >> 24) & 0xff; - break; - case 0x002218: - ret = riva128->pfifo.ramro & 0xff; - break; - case 0x002219: - ret = (riva128->pfifo.ramro >> 8) & 0xff; - break; - case 0x00221a: - ret = (riva128->pfifo.ramro >> 16) & 0xff; - break; - case 0x00221b: - ret = (riva128->pfifo.ramro >> 24) & 0xff; - break; - case 0x002504: - ret = riva128->pfifo.chan_mode & 0xff; - break; - case 0x002505: - ret = (riva128->pfifo.chan_mode >> 8) & 0xff; - break; - case 0x002506: - ret = (riva128->pfifo.chan_mode >> 16) & 0xff; - break; - case 0x002507: - ret = (riva128->pfifo.chan_mode >> 24) & 0xff; - break; - case 0x002508: - ret = riva128->pfifo.chan_dma & 0xff; - break; - case 0x002509: - ret = (riva128->pfifo.chan_dma >> 8) & 0xff; - break; - case 0x00250a: - ret = (riva128->pfifo.chan_dma >> 16) & 0xff; - break; - case 0x00250b: - ret = (riva128->pfifo.chan_dma >> 24) & 0xff; - break; - case 0x00250c: - ret = riva128->pfifo.chan_size & 0xff; - break; - case 0x00250d: - ret = (riva128->pfifo.chan_size >> 8) & 0xff; - break; - case 0x00250e: - ret = (riva128->pfifo.chan_size >> 16) & 0xff; - break; - case 0x00250f: - ret = (riva128->pfifo.chan_size >> 24) & 0xff; - break; - //HACK - case 0x002400: - ret = 0x10; - break; - case 0x002401: - ret = 0x00; - break; - case 0x003204: - ret = riva128->pfifo.caches[1].chanid; - break; - case 0x003214: - ret = 0x10; - break; - case 0x003215: - ret = 0x00; - break; - case 0x003220: - ret = 0x01; - break; - } - - return ret; -} - - void riva128_pfifo_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - // nv_riva_log("RIVA 128 PFIFO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x002100: - riva128->pfifo.intr &= ~val; - break; - case 0x002140: - riva128->pfifo.intr_en = val; - break; - case 0x002210: - riva128->pfifo.ramht = val; - riva128->pfifo.ramht_addr = (val & 0x1f0) << 8; - switch(val & 0x30000) - { - case 0x00000: - riva128->pfifo.ramht_size = 4 * 1024; - break; - case 0x10000: - riva128->pfifo.ramht_size = 8 * 1024; - break; - case 0x20000: - riva128->pfifo.ramht_size = 16 * 1024; - break; - case 0x30000: - riva128->pfifo.ramht_size = 32 * 1024; - break; - } - break; - case 0x002214: - riva128->pfifo.ramfc = val; - riva128->pfifo.ramfc_addr = (val & 0x1fe) << 4; - break; - case 0x002218: - riva128->pfifo.ramro = val; - riva128->pfifo.ramro_addr = (val & 0x1fe) << 4; - if(val & 0x10000) riva128->pfifo.ramro_size = 8192; - else riva128->pfifo.ramro_size = 512; - break; - case 0x002504: - riva128->pfifo.chan_mode = val; - break; - case 0x002508: - riva128->pfifo.chan_dma = val; - break; - case 0x00250c: - riva128->pfifo.chan_size = val; - break; - case 0x003200: - riva128->pfifo.caches[1].push_enabled = val; - break; - case 0x003204: - riva128->pfifo.caches[1].chanid = val; - break; - //HACKS - case 0x002500: - riva128_pfifo_interrupt(0, riva128); - break; - } -} - - uint8_t riva128_ptimer_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - - //nv_riva_log("RIVA 128 PTIMER read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x009100: - ret = riva128->ptimer.intr & 0xff; - break; - case 0x009101: - ret = (riva128->ptimer.intr >> 8) & 0xff; - break; - case 0x009102: - ret = (riva128->ptimer.intr >> 16) & 0xff; - break; - case 0x009103: - ret = (riva128->ptimer.intr >> 24) & 0xff; - break; - case 0x009140: - ret = riva128->ptimer.intr & 0xff; - break; - case 0x009141: - ret = (riva128->ptimer.intr_en >> 8) & 0xff; - break; - case 0x009142: - ret = (riva128->ptimer.intr_en >> 16) & 0xff; - break; - case 0x009143: - ret = (riva128->ptimer.intr_en >> 24) & 0xff; - break; - case 0x009200: - ret = riva128->ptimer.clock_div & 0xff; - break; - case 0x009201: - ret = (riva128->ptimer.clock_div >> 8) & 0xff; - break; - case 0x009202: - ret = (riva128->ptimer.clock_div >> 16) & 0xff; - break; - case 0x009203: - ret = (riva128->ptimer.clock_div >> 24) & 0xff; - break; - case 0x009210: - ret = riva128->ptimer.clock_mul & 0xff; - break; - case 0x009211: - ret = (riva128->ptimer.clock_mul >> 8) & 0xff; - break; - case 0x009212: - ret = (riva128->ptimer.clock_mul >> 16) & 0xff; - break; - case 0x009213: - ret = (riva128->ptimer.clock_mul >> 24) & 0xff; - break; - case 0x009400: - ret = riva128->ptimer.time & 0xff; - break; - case 0x009401: - ret = (riva128->ptimer.time >> 8) & 0xff; - break; - case 0x009402: - ret = (riva128->ptimer.time >> 16) & 0xff; - break; - case 0x009403: - ret = (riva128->ptimer.time >> 24) & 0xff; - break; - case 0x009410: - ret = (riva128->ptimer.time >> 32) & 0xff; - break; - case 0x009411: - ret = (riva128->ptimer.time >> 40) & 0xff; - break; - case 0x009412: - ret = (riva128->ptimer.time >> 48) & 0xff; - break; - case 0x009413: - ret = (riva128->ptimer.time >> 56) & 0xff; - break; - case 0x009420: - ret = riva128->ptimer.alarm & 0xff; - break; - case 0x009421: - ret = (riva128->ptimer.alarm >> 8) & 0xff; - break; - case 0x009422: - ret = (riva128->ptimer.alarm >> 16) & 0xff; - break; - case 0x009423: - ret = (riva128->ptimer.alarm >> 24) & 0xff; - break; - } - - - //riva128->ptimer.time += 0x10000; - - return ret; -} - - void riva128_ptimer_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - nv_riva_log("RIVA 128 PTIMER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x009100: - riva128->ptimer.intr &= ~val; - break; - case 0x009140: - riva128->ptimer.intr_en = val; - break; - case 0x009200: - if(!(val & 0xffff)) val = 1; - riva128->ptimer.clock_div = val & 0xffff; - break; - case 0x009210: - if((val & 0xffff) < riva128->ptimer.clock_div) val = riva128->ptimer.clock_div; - riva128->ptimer.clock_mul = val & 0xffff; - break; - case 0x009400: - riva128->ptimer.time &= 0x0fffffff00000000ULL; - riva128->ptimer.time |= val & 0xffffffe0; - break; - case 0x009410: - riva128->ptimer.time &= 0xffffffe0; - riva128->ptimer.time |= val & 0x0fffffff00000000ULL; - break; - case 0x009420: - riva128->ptimer.alarm = val & 0xffffffe0; - break; - } -} - - void riva128_ptimer_interrupt(int num, void *p) -{ - //nv_riva_log("RIVA 128 PTIMER interrupt #%d fired!\n", num); - riva128_t *riva128 = (riva128_t *)p; - - riva128->ptimer.intr |= (1 << num); - - riva128_pmc_interrupt(20, riva128); -} - - uint8_t riva128_pfb_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - - //nv_riva_log("RIVA 128 PFB read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x100000: - { - switch(riva128->card_id) - { - case 0x03: - { - switch(riva128->memory_size) - { - case 1: - case 8: - ret = 0; - case 2: - ret = 1; - case 4: - ret = 2; - } - ret |= 0x0c; - break; - } - case 0x04: - case 0x05: - { - switch(riva128->memory_size) - { - case 4: - ret = 1; - break; - case 8: - ret = 2; - break; - case 16: - ret = 3; - break; - case 32: - ret = 0; - break; - } - ret |= 0x14; - break; - } - } - break; - } - case 0x100200: - ret = riva128->pfb.config_0 & 0xff; - break; - case 0x100201: - ret = (riva128->pfb.config_0 >> 8) & 0xff; - break; - case 0x100202: - ret = (riva128->pfb.config_0 >> 16) & 0xff; - break; - case 0x100203: - ret = (riva128->pfb.config_0 >> 24) & 0xff; - break; - } - - return ret; -} - - void riva128_pfb_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - //nv_riva_log("RIVA 128 PFB write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x100200: - riva128->pfb.config_0 = (val & 0x33f) | 0x1000; - riva128->pfb.width = (val & 0x3f) << 5; - switch((val >> 8) & 3) - { - case 1: - riva128->pfb.bpp = 8; - break; - case 2: - riva128->pfb.bpp = 16; - break; - case 3: - riva128->pfb.bpp = 32; - break; - } - break; - } -} - -uint8_t riva128_pextdev_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - - //nv_riva_log("RIVA 128 PEXTDEV read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - //For NV3, we give it PCI 66MHz, card mode, PCI bus type, 13.5MHz crystal, no TV encoder, and PCI 2.1. - //For NV4, we give it normal PCI line polarity, card mode, 13.5 MHz crystal, no TV encoder, and PCI bus type - - switch(addr) - { - case 0x101000: - switch(riva128->card_id) - { - case 0x03: - ret = 0x13; - break; - case 0x04: - ret = 0x83; - break; - } - break; - case 0x101001: - switch(riva128->card_id) - { - case 0x03: - if(!riva128->is_nv3t) ret = 0x02; - else ret = 0x00; - break; - case 0x04: case 0x05: - //Bits 12-13 of the NV4+ strap set 0 configure the GPU's PCI device ID. - ret = (riva128->pextdev.boot_0 & 0x80000000) ? (0x8f | ((riva128->pextdev.boot_0 >> 8) & 0x30)) : 0x8f; - break; - break; - } - } - - return ret; -} - -void riva128_pextdev_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - //nv_riva_log("RIVA 128 PEXTDEV write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x101000: - riva128->pextdev.boot_0 = val; - if((val & 0x80000000) && ((riva128->card_id == 0x05) || (riva128->card_id == 0x10) || (riva128->card_id == 0x11) || (riva128->card_id == 0x15) - || (riva128->card_id == 0x1a))) - { - riva128->device_id = (riva128->device_id & 0xfffc) | ((val >> 12) & 3); - } - break; - } -} - -void rivatnt_pgraph_ctx_switch(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - unsigned old_subc = (riva128->pgraph.ctx_user >> 13) & 7; - unsigned new_subc = (riva128->pgraph.fifo_st2_addr >> 12) & 7; - unsigned mthd = (riva128->pgraph.fifo_st2_addr >> 1) & 0x7ff; - unsigned do_ctx_switch = mthd == 0; - - if(!(riva128->pgraph.fifo_st2_addr & 1)) return; - riva128->pgraph.fifo_st2_addr &= ~1; - - if(old_subc != new_subc || do_ctx_switch) - { - uint32_t ctx_mask = 0x0303f0ff; - - unsigned reload = (riva128->pgraph.debug[1] >> 15) & 1; - - unsigned reset = (riva128->pgraph.debug[2] >> 28) & 1; - - if(do_ctx_switch) riva128->pgraph.ctx_cache[new_subc][3] = riva128->pgraph.fifo_st2_data & 0xffff; - - if(reload || do_ctx_switch) - { - uint32_t instance = riva128_ramht_lookup(riva128->pgraph.fifo_st2_data, riva128); - riva128->pgraph.ctx_cache[new_subc][0] = riva128->pramin[(instance >> 2)] & ctx_mask; - riva128->pgraph.ctx_cache[new_subc][1] = riva128->pramin[(instance >> 2) + 1] & 0xffff3f03; - riva128->pgraph.ctx_cache[new_subc][2] = riva128->pramin[(instance >> 2) + 2]; - riva128->pgraph.ctx_cache[new_subc][4] = riva128->pramin[(instance >> 2) + 3]; - } - - if(reset) - { - riva128->pgraph.debug[1] |= 1; - //riva128_pgraph_volatile_reset(riva128); - } - else riva128->pgraph.debug[1] &= ~1; - - if(riva128->pgraph.debug[1] & 0x100000) - { - int i; - for(i = 0; i < 5; i++) riva128->pgraph.ctx_switch[i] = riva128->pgraph.ctx_cache[new_subc][i]; - } - } -} - - uint8_t riva128_pgraph_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - - nv_riva_log("RIVA 128 PGRAPH read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x400080: - ret = riva128->pgraph.debug[0] & 0xff; - break; - case 0x400081: - ret = (riva128->pgraph.debug[0] >> 8) & 0xff; - break; - case 0x400082: - ret = (riva128->pgraph.debug[0] >> 16) & 0xff; - break; - case 0x400083: - ret = (riva128->pgraph.debug[0] >> 24) & 0xff; - break; - case 0x400084: - ret = riva128->pgraph.debug[1] & 0xff; - break; - case 0x400085: - ret = (riva128->pgraph.debug[1] >> 8) & 0xff; - break; - case 0x400086: - ret = (riva128->pgraph.debug[1] >> 16) & 0xff; - break; - case 0x400087: - ret = (riva128->pgraph.debug[1] >> 24) & 0xff; - break; - case 0x400088: - ret = riva128->pgraph.debug[2] & 0xff; - break; - case 0x400089: - ret = (riva128->pgraph.debug[2] >> 8) & 0xff; - break; - case 0x40008a: - ret = (riva128->pgraph.debug[2] >> 16) & 0xff; - break; - case 0x40008b: - ret = (riva128->pgraph.debug[2] >> 24) & 0xff; - break; - case 0x40008c: - ret = riva128->pgraph.debug[3] & 0xff; - break; - case 0x40008d: - ret = (riva128->pgraph.debug[3] >> 8) & 0xff; - break; - case 0x40008e: - ret = (riva128->pgraph.debug[3] >> 16) & 0xff; - break; - case 0x40008f: - ret = (riva128->pgraph.debug[3] >> 24) & 0xff; - break; - - case 0x400100: - ret = riva128->pgraph.intr & 0xff; - break; - case 0x400101: - ret = (riva128->pgraph.intr >> 8) & 0xff; - break; - case 0x400102: - ret = (riva128->pgraph.intr >> 16) & 0xff; - break; - case 0x400103: - ret = (riva128->pgraph.intr >> 24) & 0xff; - break; - case 0x400104: - ret = riva128->pgraph.invalid & 0xff; - break; - case 0x400105: - ret = (riva128->pgraph.invalid >> 8) & 0xff; - break; - case 0x400106: - ret = (riva128->pgraph.invalid >> 16) & 0xff; - break; - case 0x400107: - ret = (riva128->pgraph.invalid >> 24) & 0xff; - break; - case 0x400140: - ret = riva128->pgraph.intr_en & 0xff; - break; - case 0x400141: - ret = (riva128->pgraph.intr_en >> 8) & 0xff; - break; - case 0x400142: - ret = (riva128->pgraph.intr_en >> 16) & 0xff; - break; - case 0x400143: - ret = (riva128->pgraph.intr_en >> 24) & 0xff; - break; - case 0x400144: - ret = riva128->pgraph.invalid_en & 0xff; - break; - case 0x400145: - ret = (riva128->pgraph.invalid_en >> 8) & 0xff; - break; - case 0x400146: - ret = (riva128->pgraph.invalid_en >> 16) & 0xff; - break; - case 0x400147: - ret = (riva128->pgraph.invalid_en >> 24) & 0xff; - break; - - case 0x400180: - ret = riva128->pgraph.ctx_switch[0] & 0xff; - break; - case 0x400181: - ret = (riva128->pgraph.ctx_switch[0] >> 8) & 0xff; - break; - case 0x400182: - ret = (riva128->pgraph.ctx_switch[0] >> 16) & 0xff; - break; - case 0x400183: - ret = (riva128->pgraph.ctx_switch[0] >> 24) & 0xff; - break; - - case 0x400190: - ret = riva128->pgraph.ctx_control & 0xff; - break; - case 0x400191: - ret = (riva128->pgraph.ctx_control >> 8) & 0xff; - break; - case 0x400192: - ret = (riva128->pgraph.ctx_control >> 16) & 0xff; - break; - case 0x400193: - ret = (riva128->pgraph.ctx_control >> 24) & 0xff; - break; - case 0x400194: - ret = riva128->pgraph.ctx_user & 0xff; - break; - case 0x400195: - ret = (riva128->pgraph.ctx_user >> 8) & 0xff; - break; - case 0x400196: - ret = (riva128->pgraph.ctx_user >> 16) & 0xff; - break; - case 0x400197: - ret = (riva128->pgraph.ctx_user >> 24) & 0xff; - break; - - case 0x4001a0: case 0x4001a1: case 0x4001a2: case 0x4001a3: case 0x4001a4: case 0x4001a5: case 0x4001a6: case 0x4001a7: - case 0x4001a8: case 0x4001a9: case 0x4001aa: case 0x4001ab: case 0x4001ac: case 0x4001ad: case 0x4001ae: case 0x4001af: - case 0x4001b0: case 0x4001b1: case 0x4001b2: case 0x4001b3: case 0x4001b4: case 0x4001b5: case 0x4001b6: case 0x4001b7: - case 0x4001b8: case 0x4001b9: case 0x4001ba: case 0x4001bb: case 0x4001bc: case 0x4001bd: case 0x4001be: case 0x4001bf: - ret = (riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] >> ((addr & 3) << 3)) & 0xff; - break; - - case 0x4006a4: - ret = riva128->pgraph.fifo_enable & 1; - break; - - case 0x4006b0: - ret = riva128->pgraph.status & 0xff; - break; - case 0x4006b1: - ret = (riva128->pgraph.status >> 8) & 0xff; - break; - case 0x4006b2: - ret = (riva128->pgraph.status >> 16) & 0xff; - break; - case 0x4006b3: - ret = (riva128->pgraph.status >> 24) & 0xff; - //HACK - riva128->pgraph.status ^= 0x1f131111; - break; - - case 0x401100: - ret = riva128->pgraph.dma_intr & 0xff; - break; - case 0x401101: - ret = (riva128->pgraph.dma_intr >> 8) & 0xff; - break; - case 0x401102: - ret = (riva128->pgraph.dma_intr >> 16) & 0xff; - break; - case 0x401103: - ret = (riva128->pgraph.dma_intr >> 24) & 0xff; - break; - case 0x401140: - ret = riva128->pgraph.dma_intr_en & 0xff; - break; - case 0x401141: - ret = (riva128->pgraph.dma_intr_en >> 8) & 0xff; - break; - case 0x401142: - ret = (riva128->pgraph.dma_intr_en >> 16) & 0xff; - break; - case 0x401143: - ret = (riva128->pgraph.dma_intr_en >> 24) & 0xff; - break; - } - - if(riva128->card_id == 0x03) switch(addr) - { - case 0x40053c: - ret = riva128->pgraph.uclip_xmin & 0xff; - break; - case 0x40053d: - ret = (riva128->pgraph.uclip_xmin >> 8) & 0xff; - break; - case 0x40053e: - ret = (riva128->pgraph.uclip_xmin >> 16) & 0xff; - break; - case 0x40053f: - ret = (riva128->pgraph.uclip_xmin >> 24) & 0xff; - break; - case 0x400540: - ret = riva128->pgraph.uclip_ymin & 0xff; - break; - case 0x400541: - ret = (riva128->pgraph.uclip_ymin >> 8) & 0xff; - break; - case 0x400542: - ret = (riva128->pgraph.uclip_ymin >> 16) & 0xff; - break; - case 0x400543: - ret = (riva128->pgraph.uclip_ymin >> 24) & 0xff; - break; - case 0x400544: - ret = riva128->pgraph.uclip_xmax & 0xff; - break; - case 0x400545: - ret = (riva128->pgraph.uclip_xmax >> 8) & 0xff; - break; - case 0x400546: - ret = (riva128->pgraph.uclip_xmax >> 16) & 0xff; - break; - case 0x400547: - ret = (riva128->pgraph.uclip_xmax >> 24) & 0xff; - break; - case 0x400548: - ret = riva128->pgraph.uclip_ymax & 0xff; - break; - case 0x400549: - ret = (riva128->pgraph.uclip_ymax >> 8) & 0xff; - break; - case 0x40054a: - ret = (riva128->pgraph.uclip_ymax >> 16) & 0xff; - break; - case 0x40054b: - ret = (riva128->pgraph.uclip_ymax >> 24) & 0xff; - break; - case 0x400560: - ret = riva128->pgraph.oclip_xmin & 0xff; - break; - case 0x400561: - ret = (riva128->pgraph.oclip_xmin >> 8) & 0xff; - break; - case 0x400562: - ret = (riva128->pgraph.oclip_xmin >> 16) & 0xff; - break; - case 0x400563: - ret = (riva128->pgraph.oclip_xmin >> 24) & 0xff; - break; - case 0x400564: - ret = riva128->pgraph.oclip_ymin & 0xff; - break; - case 0x400565: - ret = (riva128->pgraph.oclip_ymin >> 8) & 0xff; - break; - case 0x400566: - ret = (riva128->pgraph.oclip_ymin >> 16) & 0xff; - break; - case 0x400567: - ret = (riva128->pgraph.oclip_ymin >> 24) & 0xff; - break; - case 0x400568: - ret = riva128->pgraph.oclip_xmax & 0xff; - break; - case 0x400569: - ret = (riva128->pgraph.oclip_xmax >> 8) & 0xff; - break; - case 0x40056a: - ret = (riva128->pgraph.oclip_xmax >> 16) & 0xff; - break; - case 0x40056b: - ret = (riva128->pgraph.oclip_xmax >> 24) & 0xff; - break; - case 0x40056c: - ret = riva128->pgraph.oclip_ymax & 0xff; - break; - case 0x40056d: - ret = (riva128->pgraph.oclip_ymax >> 8) & 0xff; - break; - case 0x40056e: - ret = (riva128->pgraph.oclip_ymax >> 16) & 0xff; - break; - case 0x40056f: - ret = (riva128->pgraph.oclip_ymax >> 24) & 0xff; - break; - case 0x400624: - ret = riva128->pgraph.rop; - break; - case 0x40062c: - ret = riva128->pgraph.beta & 0xff; - break; - case 0x40062d: - ret = (riva128->pgraph.beta >> 8) & 0xff; - break; - case 0x40062e: - ret = (riva128->pgraph.beta >> 16) & 0xff; - break; - case 0x40062f: - ret = (riva128->pgraph.beta >> 24) & 0xff; - break; - case 0x400640: - ret = riva128->pgraph.beta & 0xff; - break; - case 0x400641: - ret = (riva128->pgraph.beta >> 8) & 0xff; - break; - case 0x400642: - ret = (riva128->pgraph.beta >> 16) & 0xff; - break; - case 0x400643: - ret = (riva128->pgraph.beta >> 24) & 0xff; - break; - case 0x400684: - ret = riva128->pgraph.notify & 0xff; - break; - case 0x400685: - ret = (riva128->pgraph.notify >> 8) & 0xff; - break; - case 0x400686: - ret = (riva128->pgraph.notify >> 16) & 0xff; - break; - case 0x400687: - ret = (riva128->pgraph.notify >> 24) & 0xff; - break; - case 0x400690: - ret = riva128->pgraph.cliprect_min[0] & 0xff; - break; - case 0x400691: - ret = (riva128->pgraph.cliprect_min[0] >> 8) & 0xff; - break; - case 0x400692: - ret = (riva128->pgraph.cliprect_min[0] >> 16) & 0xff; - break; - case 0x400693: - ret = (riva128->pgraph.cliprect_min[0] >> 24) & 0xff; - break; - case 0x400694: - ret = riva128->pgraph.cliprect_max[0] & 0xff; - break; - case 0x400695: - ret = (riva128->pgraph.cliprect_max[0] >> 8) & 0xff; - break; - case 0x400696: - ret = (riva128->pgraph.cliprect_max[0] >> 16) & 0xff; - break; - case 0x400697: - ret = (riva128->pgraph.cliprect_max[0] >> 24) & 0xff; - break; - case 0x400698: - ret = riva128->pgraph.cliprect_min[1] & 0xff; - break; - case 0x400699: - ret = (riva128->pgraph.cliprect_min[1] >> 8) & 0xff; - break; - case 0x40069a: - ret = (riva128->pgraph.cliprect_min[1] >> 16) & 0xff; - break; - case 0x40069b: - ret = (riva128->pgraph.cliprect_min[1] >> 24) & 0xff; - break; - case 0x40069c: - ret = riva128->pgraph.cliprect_max[1] & 0xff; - break; - case 0x40069d: - ret = (riva128->pgraph.cliprect_max[1] >> 8) & 0xff; - break; - case 0x40069e: - ret = (riva128->pgraph.cliprect_max[1] >> 16) & 0xff; - break; - case 0x40069f: - ret = (riva128->pgraph.cliprect_max[1] >> 24) & 0xff; - break; - case 0x4006a0: - ret = riva128->pgraph.cliprect_ctrl & 0xff; - break; - case 0x4006a1: - ret = (riva128->pgraph.cliprect_ctrl >> 8) & 0xff; - break; - case 0x4006a2: - ret = (riva128->pgraph.cliprect_ctrl >> 16) & 0xff; - break; - case 0x4006a3: - ret = (riva128->pgraph.cliprect_ctrl >> 24) & 0xff; - break; - } - - return ret; -} - - void riva128_pgraph_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - nv_riva_log("RIVA 128 PGRAPH write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x400100: - riva128->pgraph.intr &= ~val; - break; - case 0x400104: - riva128->pgraph.invalid &= ~val; - break; - case 0x400140: - riva128->pgraph.intr_en = val; - if(riva128->card_id == 0x03) riva128->pgraph.intr_en &= 0x11111111; - else if(riva128->card_id < 0x10) riva128->pgraph.intr_en &= 0x00011311; - break; - case 0x400144: - if(riva128->card_id == 0x03) - { - riva128->pgraph.invalid_en = val; - riva128->pgraph.invalid_en &= 0x00011111; - } - break; - } - - if(riva128->card_id == 0x03) switch(addr) - { - case 0x400080: - riva128->pgraph.debug[0] = val & 0x13311110; - break; - case 0x400084: - riva128->pgraph.debug[1] = val & 0x10113301; - break; - case 0x400088: - riva128->pgraph.debug[2] = val & 0x1133f111; - break; - case 0x40008c: - riva128->pgraph.debug[3] = val & 0x1173ff31; - break; - case 0x400180: - riva128->pgraph.debug[1] &= ~1; //Clear recent volatile reset bit on object switch. - riva128->pgraph.ctx_switch[0] = val & 0x3ff3f71f; - break; - case 0x400190: - riva128->pgraph.ctx_control = val & 0x11010103; - break; - case 0x400194: - riva128->pgraph.ctx_user = val & 0x7f1fe000; - break; - case 0x4001a0: case 0x4001a4: case 0x4001a8: case 0x4001ac: case 0x4001b0: case 0x4001b4: case 0x4001b8: case 0x4001bc: - riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] = val & 0x3ff3f71f; - break; - case 0x40053c: - riva128->pgraph.uclip_xmin = val & 0x3ffff; - break; - case 0x400540: - riva128->pgraph.uclip_ymin = val & 0x3ffff; - break; - case 0x400544: - riva128->pgraph.uclip_xmax = val & 0x3ffff; - break; - case 0x400548: - riva128->pgraph.uclip_ymax = val & 0x3ffff; - break; - case 0x400550: - riva128->pgraph.src_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); - break; - case 0x400554: - riva128->pgraph.src_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); - break; - case 0x400558: - riva128->pgraph.dst_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); - break; - case 0x40055c: - riva128->pgraph.dst_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); - break; - case 0x400560: - riva128->pgraph.oclip_xmin = val & 0x3ffff; - break; - case 0x400564: - riva128->pgraph.oclip_ymin = val & 0x3ffff; - break; - case 0x400568: - riva128->pgraph.oclip_xmax = val & 0x3ffff; - break; - case 0x40056c: - riva128->pgraph.oclip_ymax = val & 0x3ffff; - break; - case 0x400624: - riva128->pgraph.rop = val & 0xff; - break; - case 0x40062c: - riva128->pgraph.chroma = val & 0x7fffffff; - break; - case 0x400630: - riva128->pgraph.surf_offset[0] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); - break; - case 0x400634: - riva128->pgraph.surf_offset[1] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); - break; - case 0x400638: - riva128->pgraph.surf_offset[2] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); - break; - case 0x40063c: - riva128->pgraph.surf_offset[3] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); - break; - case 0x400640: - { - uint32_t tmp = val & 0x7f800000; - if(val & 0x80000000) tmp = 0; - riva128->pgraph.beta = tmp; - break; - } - case 0x400650: - riva128->pgraph.surf_pitch[0] = val & 0x1ff0; - break; - case 0x400654: - riva128->pgraph.surf_pitch[1] = val & 0x1ff0; - break; - case 0x400658: - riva128->pgraph.surf_pitch[2] = val & 0x1ff0; - break; - case 0x40065c: - riva128->pgraph.surf_pitch[3] = val & 0x1ff0; - break; - case 0x400684: - riva128->pgraph.notify = val & 0x0011ffff; - break; - case 0x4006a0: - riva128->pgraph.cliprect_ctrl = val & 0x113; - break; - case 0x4006a4: - riva128->pgraph.fifo_enable = val & 1; - break; - case 0x401100: - riva128->pgraph.dma_intr &= ~val; - break; - case 0x401140: - riva128->pgraph.dma_intr_en = val & 0x00011111; - break; - } - else if(riva128->card_id < 0x10) switch(addr) - { - case 0x400080: - riva128->pgraph.debug[0] = val & 0x1337f000; - break; - case 0x400084: - riva128->pgraph.debug[1] = val & ((riva128->card_id == 0x04) ? 0x72113101 : 0xf2ffb701); - break; - case 0x400088: - riva128->pgraph.debug[2] = val & 0x11d7fff1; - break; - case 0x40008c: - riva128->pgraph.debug[3] = val & ((riva128->card_id == 0x04) ? 0x11ffff33 : 0xfbffff73); - break; - } - if(riva128->card_id >= 0x04) switch(addr) - { - case 0x400754: - riva128->pgraph.fifo_st2_addr = val; - break; - case 0x400758: - riva128->pgraph.fifo_st2_data = val; - rivatnt_pgraph_ctx_switch(riva128); - break; - } -} - - void riva128_pgraph_interrupt(int num, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->pgraph.intr |= (1 << num); - - riva128_pmc_interrupt(12, riva128); -} - - void riva128_pgraph_invalid_interrupt(int num, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->pgraph.invalid |= (1 << num); - - riva128_pgraph_interrupt(0, riva128); -} - -void riva128_pgraph_vblank_interrupt(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->pgraph.invalid |= (1 << 8); - - riva128_pmc_interrupt(24, riva128); -} - - uint8_t riva128_pramdac_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - - //nv_riva_log("RIVA 128 PRAMDAC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x680500: - ret = riva128->pramdac.nvpll & 0xff; - break; - case 0x680501: - ret = (riva128->pramdac.nvpll >> 8) & 0xff; - break; - case 0x680502: - ret = (riva128->pramdac.nvpll >> 16) & 0xff; - break; - case 0x680503: - ret = (riva128->pramdac.nvpll >> 24) & 0xff; - break; - case 0x680504: - ret = riva128->pramdac.mpll & 0xff; - break; - case 0x680505: - ret = (riva128->pramdac.mpll >> 8) & 0xff; - break; - case 0x680506: - ret = (riva128->pramdac.mpll >> 16) & 0xff; - break; - case 0x680507: - ret = (riva128->pramdac.mpll >> 24) & 0xff; - break; - case 0x680508: - ret = riva128->pramdac.vpll & 0xff; - break; - case 0x680509: - ret = (riva128->pramdac.vpll >> 8) & 0xff; - break; - case 0x68050a: - ret = (riva128->pramdac.vpll >> 16) & 0xff; - break; - case 0x68050b: - ret = (riva128->pramdac.vpll >> 24) & 0xff; - break; - case 0x68050c: - ret = riva128->pramdac.pll_ctrl & 0xff; - break; - case 0x68050d: - ret = (riva128->pramdac.pll_ctrl >> 8) & 0xff; - break; - case 0x68050e: - ret = (riva128->pramdac.pll_ctrl >> 16) & 0xff; - break; - case 0x68050f: - ret = (riva128->pramdac.pll_ctrl >> 24) & 0xff; - break; - case 0x680600: - ret = riva128->pramdac.gen_ctrl & 0xff; - break; - case 0x680601: - ret = (riva128->pramdac.gen_ctrl >> 8) & 0xff; - break; - case 0x680602: - ret = (riva128->pramdac.gen_ctrl >> 16) & 0xff; - break; - case 0x680603: - ret = (riva128->pramdac.gen_ctrl >> 24) & 0xff; - break; - } - - return ret; -} - - void riva128_pramdac_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t* svga = &riva128->svga; - //nv_riva_log("RIVA 128 PRAMDAC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x680500: - riva128->pramdac.nvpll = val; - riva128->pramdac.nv_m = val & 0xff; - riva128->pramdac.nv_n = (val >> 8) & 0xff; - riva128->pramdac.nv_p = (val >> 16) & 7; - svga_recalctimings(svga); - break; - case 0x680504: - riva128->pramdac.mpll = val; - riva128->pramdac.m_m = val & 0xff; - riva128->pramdac.m_n = (val >> 8) & 0xff; - riva128->pramdac.m_p = (val >> 16) & 7; - svga_recalctimings(svga); - break; - case 0x680508: - riva128->pramdac.vpll = val; - riva128->pramdac.v_m = val & 0xff; - riva128->pramdac.v_n = (val >> 8) & 0xff; - riva128->pramdac.v_p = (val >> 16) & 7; - svga_recalctimings(svga); - break; - case 0x68050c: - riva128->pramdac.pll_ctrl = val; - break; - case 0x680600: - riva128->pramdac.gen_ctrl = val; - break; - } -} - - uint32_t riva128_ramht_lookup(uint32_t handle, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint32_t ramht_base = riva128->pfifo.ramht_addr; - uint32_t ret = 0; - - uint32_t tmp = handle; - uint32_t hash = 0; - - int bits; - - switch(riva128->pfifo.ramht_size) - { - case 4096: - bits = 12; - case 8192: - bits = 13; - case 16384: - bits = 14; - case 32768: - bits = 15; - } - - while(tmp) - { - hash ^= (tmp & (riva128->pfifo.ramht_size - 1)); - tmp = tmp >> 1; - } - - hash ^= riva128->pfifo.caches[1].chanid << (bits - 4); - - ret = riva128->pramin[ramht_base + (hash * 8)]; - - nv_riva_log("RIVA 128 RAMHT lookup with handle %08X returned %08X %04X:%08X\n", handle, ret, CS, cpu_state.pc); - - return ret; -} - - void riva128_puller_exec_method(int chanid, int subchanid, int offset, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - nv_riva_log("RIVA 128 Puller executing method %04X on channel %01X[%01X] param %08X %04X:%08X\n", offset, chanid, subchanid, val, CS, cpu_state.pc); - - if(riva128->card_id == 0x03) - { - uint32_t tmp = riva128_ramht_lookup(val, riva128); - unsigned new_class = (tmp >> 16) & 0x1f; - unsigned old_subc = (riva128->pgraph.ctx_user >> 13) & 7; - unsigned new_subc = subchanid & 7; - riva128->pgraph.instance = (tmp & 0xffff) << 2; - if((old_subc != new_subc) || !offset) - { - uint32_t tmp_ctx = riva128->pramin[riva128->pgraph.instance]; - if(!offset) riva128->pgraph.ctx_cache[new_subc][0] = tmp_ctx & 0x3ff3f71f; - riva128->pgraph.ctx_user &= 0x1fe000; - riva128->pgraph.ctx_user |= tmp & 0x1f0000; - riva128->pgraph.ctx_user |= new_subc << 13; - if(riva128->pgraph.debug[1] & 0x100000) riva128->pgraph.ctx_switch[0] = riva128->pgraph.ctx_cache[new_subc][0]; - if(riva128->pgraph.debug[2] & 0x10000000) - { - //riva128_pgraph_volatile_reset(riva128); - riva128->pgraph.debug[1] |= 1; - } - else riva128->pgraph.debug[1] &= ~1; - if(riva128->pgraph.notify & 0x10000) - { - riva128_pgraph_invalid_interrupt(16, riva128); - riva128->pgraph.fifo_enable = 0; - } - } - - if(!riva128->pgraph.invalid && (((riva128->pgraph.debug[3] >> 20) & 3) == 3) && offset) - { - riva128_pgraph_invalid_interrupt(4, riva128); - riva128->pgraph.fifo_enable = 0; - } - - if((riva128->pgraph.debug[1] & 0x10000) && ((riva128->pgraph.instance >> 4) != riva128->pgraph.ctx_switch[3]) && (new_class == 0x0d || new_class == 0x0e || new_class == 0x14 || new_class == 0x17 || offset == 0x0104)) - { - riva128->pgraph.ctx_switch[3] = riva128->pgraph.instance >> 4; - riva128->pgraph.ctx_switch[1] = riva128->pramin[riva128->pgraph.instance + 4] & 0xffff; - riva128->pgraph.notify &= 0xf10000; - riva128->pgraph.notify |= (riva128->pramin[riva128->pgraph.instance + 4] >> 16) & 0xffff; - riva128->pgraph.ctx_switch[2] = riva128->pramin[riva128->pgraph.instance + 8] & 0x1ffff; - } - } - else rivatnt_pgraph_ctx_switch(riva128); -} - - void riva128_pusher_run(int chanid, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - while(riva128->pfifo.channels[chanid].dmaget != riva128->pfifo.channels[chanid].dmaput) - { - uint32_t dmaget = riva128->pfifo.channels[chanid].dmaget; - uint32_t cmd = ((uint32_t*)svga->vram)[dmaget >> 2]; - uint32_t* params = (uint32_t *)(((uint32_t*)svga->vram)[(dmaget + 4) >> 2]); - if(((cmd & 0xe0000003) == 0x20000000) && (riva128->card_id >= 0x04)) - { - //old nv4 jump command - riva128->pfifo.channels[chanid].dmaget = cmd & 0x1ffffffc; - } - if((cmd & 0xe0030003) == 0) - { - //nv3 increasing method command - uint32_t method = cmd & 0x1ffc; - int subchannel = (cmd >> 13) & 7; - int method_count = (cmd >> 18) & 0x7ff; - int i; - for(i = 0; ipfifo.channels[chanid].dmaget += 4; - } -} - -uint8_t riva128_user_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - int chanid = (addr >> 16) & 0xf; - int subchanid = (addr >> 13) & 0x7; - int offset = addr & 0x1fff; - uint8_t ret = 0; - - nv_riva_log("RIVA 128 USER read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - addr -= 0x800000; - - if(riva128->pfifo.chan_mode & (1 << chanid)) - { - //DMA mode reads??? - } - else - { - //PIO mode - switch(offset) - { - case 0x10: ret = riva128_pfifo_cache1_free(chanid, riva128) & 0xfc; break; - case 0x11: ret = riva128_pfifo_cache1_free(chanid, riva128) >> 8; break; - } - } - - return ret; -} - - void riva128_user_write(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - int chanid = (addr >> 16) & 0xf; - int subchanid = (addr >> 13) & 0x7; - int offset = addr & 0x1fff; - - nv_riva_log("RIVA 128 USER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - addr -= 0x800000; - - if(riva128->pfifo.chan_mode & (1 << chanid)) - { - //DMA mode, at least this has docs. - switch(offset) - { - case 0x40: - riva128->pfifo.channels[chanid].dmaput = val; - if(riva128->pfifo.caches[1].push_enabled) riva128_pusher_run(chanid, riva128); - break; - case 0x44: - riva128->pfifo.channels[chanid].dmaget = val; - break; - } - } - else - { - uint32_t err = -1; - int intr = 1; - //PIO mode - //if((offset & 0x1f00) && (offset != 0)) err = 5; //Reserved access - //if((offset & 0x1ff0) == 0x0020) intr = 0; - //if(!riva128->pfifo.caches[1].push_enabled) err = 1; //Pusher disabled - //else - { - riva128_puller_exec_method(chanid, subchanid, offset, val, riva128); - riva128->pgraph.status = 0x1f131111; //HACK - } - if(err != -1) - { - uint32_t w = (addr & 0x7fffff) | (err << 28); - if(intr) riva128_pfifo_interrupt(4, riva128); - - } - } -} - - uint8_t riva128_mmio_read(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - - addr &= 0xffffff; - - //This logging condition is necessary to prevent A CATASTROPHIC LOG BLOWUP when polling PTIMER or PFIFO. DO NOT REMOVE. - if(/*!((addr >= 0x009000) && (addr <= 0x009fff)) && !((addr >= 0x002000) && (addr <= 0x003fff)) && !((addr >= 0x000000) - && (addr <= 0x000003)) && !((addr <= 0x680fff) && (addr >= 0x680000)) && !((addr >= 0x0c0000) && (addr <= 0x0cffff)) - && !((addr >= 0x110000) && (addr <= 0x11ffff)) && !(addr <= 0x000fff) && (addr >= 0x000000)*/1) nv_riva_log("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - - if((addr >= 0x000000) && (addr <= 0x000fff)) ret = riva128_pmc_read(addr, riva128); - if((addr >= 0x001000) && (addr <= 0x001fff)) ret = riva128_pbus_read(addr, riva128); - if((addr >= 0x002000) && (addr <= 0x002fff)) ret = riva128_pfifo_read(addr, riva128); - if((addr >= 0x009000) && (addr <= 0x009fff)) ret = riva128_ptimer_read(addr, riva128); - if((addr >= 0x100000) && (addr <= 0x100fff)) ret = riva128_pfb_read(addr, riva128); - if((addr >= 0x101000) && (addr <= 0x101fff)) ret = riva128_pextdev_read(addr, riva128); - if((addr >= 0x110000) && (addr <= 0x11ffff) && (riva128->card_id == 0x03)) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; - if((addr >= 0x300000) && (addr <= 0x30ffff) && (riva128->card_id >= 0x04)) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; - if((addr >= 0x400000) && (addr <= 0x400fff)) ret = riva128_pgraph_read(addr, riva128); - if((addr >= 0x680000) && (addr <= 0x680fff)) ret = riva128_pramdac_read(addr, riva128); - if(addr >= 0x800000) ret = riva128_user_read(addr, riva128); - - switch(addr) - { - case 0x6013b4: case 0x6013b5: - case 0x6013d4: case 0x6013d5: - case 0x6013da: - case 0x0c03c2: case 0x0c03c3: case 0x0c03c4: case 0x0c03c5: - case 0x6813c6: case 0x6813c7: case 0x6813c8: case 0x6813c9: case 0x6813ca: case 0x6813cb: case 0x6813cc: - ret = riva128_in(addr & 0xfff, riva128); - break; - } - return ret; -} - - uint16_t riva128_mmio_read_w(uint32_t addr, void *p) -{ - addr &= 0xffffff; - //nv_riva_log("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8); -} - - uint32_t riva128_mmio_read_l(uint32_t addr, void *p) -{ - addr &= 0xffffff; - //nv_riva_log("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); - return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8) | (riva128_mmio_read(addr+2,p) << 16) | (riva128_mmio_read(addr+3,p) << 24); -} - - void riva128_mmio_write(uint32_t addr, uint8_t val, void *p) -{ - addr &= 0xffffff; - //nv_riva_log("RIVA 128 MMIO write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - if(addr != 0x6013d4 && addr != 0x6013d5 && addr != 0x6013b4 && addr != 0x6013b5 && addr != 0x6013da && !((addr >= 0x6813c6) && (addr <= 0x6813cc))) - { - uint32_t tmp = riva128_mmio_read_l(addr,p); - tmp &= ~(0xff << ((addr & 3) << 3)); - tmp |= val << ((addr & 3) << 3); - riva128_mmio_write_l(addr, tmp, p); - } - else - { - riva128_out(addr & 0xfff, val & 0xff, p); - } -} - - void riva128_mmio_write_w(uint32_t addr, uint16_t val, void *p) -{ - uint32_t tmp; - addr &= 0xffffff; - //nv_riva_log("RIVA 128 MMIO write %08X %04X %04X:%08X\n", addr, val, CS, cpu_state.pc); - tmp = riva128_mmio_read_l(addr,p); - tmp &= ~(0xffff << ((addr & 2) << 4)); - tmp |= val << ((addr & 2) << 4); - riva128_mmio_write_l(addr, tmp, p); -} - - void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - addr &= 0xffffff; - - //DO NOT REMOVE. This fixes a monstrous log blowup in win9x's drivers when accessing PFIFO. - if(/*!((addr >= 0x002000) && (addr <= 0x003fff)) && !((addr >= 0xc0000) && (addr <= 0xcffff)) && (addr != 0x000140)*/1) nv_riva_log("RIVA 128 MMIO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - - if((addr >= 0x000000) && (addr <= 0x000fff)) riva128_pmc_write(addr, val, riva128); - if((addr >= 0x001000) && (addr <= 0x001fff)) riva128_pbus_write(addr, val, riva128); - if((addr >= 0x002000) && (addr <= 0x002fff)) riva128_pfifo_write(addr, val, riva128); - if((addr >= 0x009000) && (addr <= 0x009fff)) riva128_ptimer_write(addr, val, riva128); - if((addr >= 0x100000) && (addr <= 0x100fff)) riva128_pfb_write(addr, val, riva128); - if((addr >= 0x101000) && (addr <= 0x101fff)) riva128_pextdev_write(addr, val, riva128); - if((addr >= 0x400000) && (addr <= 0x400fff)) riva128_pgraph_write(addr, val, riva128); - if((addr >= 0x680000) && (addr <= 0x680fff)) riva128_pramdac_write(addr, val, riva128); - if((addr >= 0x800000) && (addr <= 0xffffff)) riva128_user_write(addr, val, riva128); - - switch(addr) - { - case 0x6013b4: case 0x6013b5: - case 0x6013d4: case 0x6013d5: - case 0x6013da: - case 0x0c03c2: case 0x0c03c3: case 0x0c03c4: case 0x0c03c5: - case 0x6813c6: case 0x6813c7: case 0x6813c8: case 0x6813c9: case 0x6813ca: case 0x6813cb: case 0x6813cc: - riva128_out(addr & 0xfff, val & 0xff, p); - riva128_out((addr+1) & 0xfff, (val>>8) & 0xff, p); - riva128_out((addr+2) & 0xfff, (val>>16) & 0xff, p); - riva128_out((addr+3) & 0xfff, (val>>24) & 0xff, p); - break; - } -} - -void riva128_ptimer_tick(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - //nv_riva_log("RIVA 128 PTIMER tick!\n"); - - double time = ((double)riva128->ptimer.clock_mul * 10000000.0f) / (double)riva128->ptimer.clock_div; - uint32_t tmp; - int alarm_check; - - //if(cs == 0x0008 && !riva128->pgraph.beta) nv_riva_log("RIVA 128 PTIMER time elapsed %f alarm %08x, time_low %08x\n", time, riva128->ptimer.alarm, riva128->ptimer.time & 0xffffffff); - - tmp = riva128->ptimer.time; - riva128->ptimer.time += (uint64_t)time; - - alarm_check = (riva128->ptimer.alarm - tmp) < (uint32_t)riva128->ptimer.time; - - if(alarm_check && (riva128->ptimer.intr_en & 1)) - { - //nv_riva_log("RIVA 128 PTIMER ALARM interrupt fired!\n"); - riva128_ptimer_interrupt(0, riva128); - } -} - - void riva128_mclk_poll(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - //if(!riva128->pgraph.beta) nv_riva_log("RIVA 128 MCLK poll PMC enable %08x\n", riva128->pmc.enable); - - if((riva128->pmc.enable & 0x00010000) && (riva128->card_id == 0x03)) riva128_ptimer_tick(riva128); - - riva128->mtime += (int64_t)((TIMER_USEC * 100000000.0) / riva128->mfreq); -} - - void riva128_nvclk_poll(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - if((riva128->pmc.enable & 0x00010000) && ((riva128->card_id < 0x40) && (riva128->card_id != 0x03))) riva128_ptimer_tick(riva128); - - riva128->nvtime += (int64_t)((TIMER_USEC * 100000000.0) / riva128->nvfreq); -} - - void riva128_vblank_start(svga_t *svga) -{ - riva128_t *riva128 = (riva128_t *)svga->p; - - riva128_pgraph_vblank_interrupt(riva128); -} - - uint8_t riva128_rma_in(uint16_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t* svga = &riva128->svga; - uint8_t ret = 0; - - addr &= 0xff; - - //nv_riva_log("RIVA 128 RMA read %04X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x00: - ret = 0x65; - break; - case 0x01: - ret = 0xd0; - break; - case 0x02: - ret = 0x16; - break; - case 0x03: - ret = 0x2b; - break; - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - if(riva128->rma.addr < 0x1000000) ret = riva128_mmio_read((riva128->rma.addr + (addr & 3)) & 0xffffff, riva128); - else ret = svga_read_linear((riva128->rma.addr - 0x1000000), svga); - break; - } - - return ret; -} - - void riva128_rma_out(uint16_t addr, uint8_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t* svga = &riva128->svga; - - addr &= 0xff; - - //nv_riva_log("RIVA 128 RMA write %04X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x04: - riva128->rma.addr &= ~0xff; - riva128->rma.addr |= val; - break; - case 0x05: - riva128->rma.addr &= ~0xff00; - riva128->rma.addr |= (val << 8); - break; - case 0x06: - riva128->rma.addr &= ~0xff0000; - riva128->rma.addr |= (val << 16); - break; - case 0x07: - riva128->rma.addr &= ~0xff000000; - riva128->rma.addr |= (val << 24); - break; - case 0x08: - case 0x0c: - case 0x10: - case 0x14: - riva128->rma.data &= ~0xff; - riva128->rma.data |= val; - break; - case 0x09: - case 0x0d: - case 0x11: - case 0x15: - riva128->rma.data &= ~0xff00; - riva128->rma.data |= (val << 8); - break; - case 0x0a: - case 0x0e: - case 0x12: - case 0x16: - riva128->rma.data &= ~0xff0000; - riva128->rma.data |= (val << 16); - break; - case 0x0b: - case 0x0f: - case 0x13: - case 0x17: - riva128->rma.data &= ~0xff000000; - riva128->rma.data |= (val << 24); - if(riva128->rma.addr < 0x1000000) riva128_mmio_write_l(riva128->rma.addr & 0xffffff, riva128->rma.data, riva128); - else svga_writel_linear((riva128->rma.addr - 0x1000000), riva128->rma.data, svga); - break; - } - - if(addr & 0x10) riva128->rma.addr+=4; -} - - uint8_t riva128_in(uint16_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t* svga = &riva128->svga; - uint8_t ret = 0; - - if((addr >= 0x3d0) && (addr <= 0x3d3)) - { - //nv_riva_log("RIVA 128 RMA BAR Register read %04X %04X:%08X\n", addr, CS, cpu_state.pc); - if(!(riva128->rma.mode & 1)) return ret; - ret = riva128_rma_in(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128); - return ret; - } - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - // if (addr != 0x3da) nv_riva_log("S3 in %04X %04X:%08X ", addr, CS, cpu_state.pc); - switch (addr) - { - case 0x3D4: - ret = svga->crtcreg; - break; - case 0x3D5: - switch(svga->crtcreg) - { - case 0x28: - ret = svga->crtc[0x28] & 0x3f; - break; - case 0x34: - ret = svga->displine & 0xff; - break; - case 0x35: - ret = (svga->displine >> 8) & 7; - break; - case 0x3e: - //DDC status register - ret = (riva128->i2c.sda << 3) | (riva128->i2c.scl << 2); - if(riva128->i2c.state == I2C_READ) - { - if(riva128->i2c.scl) - { - if(riva128->i2c.databits > 8) - { - riva128->i2c.data <<= 1; - if(riva128->i2c.addr == 0xA1) - { - riva128->i2c.data |= (riva128->i2c.edid_rom.edid_rom[riva128->i2c.edid_rom.addr] & (0x80 >> riva128->i2c.databits)) >> riva128->i2c.databits; - } - else riva128->i2c.data = 0; - riva128->i2c.databits++; - } - if(riva128->i2c.databits == 8) - { - riva128->i2c.state = I2C_WAITACK; - riva128->i2c.sda = 0; - riva128->i2c.edid_rom.addr++; - } - } - } - break; - default: - ret = svga->crtc[svga->crtcreg]; - break; - } - if(svga->crtcreg > 0x18) - nv_riva_log("RIVA 128 Extended CRTC read %02X %04X:%08X\n", svga->crtcreg, CS, cpu_state.pc); - break; - default: - ret = svga_in(addr, svga); - break; - } - // if (addr != 0x3da) nv_riva_log("%02X\n", ret); - return ret; -} - - void riva128_out(uint16_t addr, uint8_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - uint8_t old; - - if((addr >= 0x3d0) && (addr <= 0x3d3)) - { - //nv_riva_log("RIVA 128 RMA BAR Register write %04X %02x %04X:%08X\n", addr, val, CS, cpu_state.pc); - riva128->rma.access_reg[addr & 3] = val; - if(!(riva128->rma.mode & 1)) return; - riva128_rma_out(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128->rma.access_reg[addr & 3], riva128); - return; - } - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - switch(addr) - { - case 0x3D4: - svga->crtcreg = val; - 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; - switch(svga->crtcreg) - { - case 0x1a: - svga_recalctimings(svga); - break; - case 0x1e: - riva128->read_bank = val; - if (svga->chain4) svga->read_bank = riva128->read_bank << 15; - else svga->read_bank = riva128->read_bank << 13; - break; - case 0x1d: - riva128->write_bank = val; - if (svga->chain4) svga->write_bank = riva128->write_bank << 15; - else svga->write_bank = riva128->write_bank << 13; - break; - case 0x26: - if (!svga->attrff) - svga->attraddr = val & 31; - break; - case 0x19: - case 0x25: - case 0x28: - case 0x2d: - svga_recalctimings(svga); - break; - case 0x38: - riva128->rma.mode = val & 0xf; - break; - case 0x3f: - //FULL EMULATION OF I2C AND DDC PROTOCOLS INCOMING - if(riva128->i2c.sda && riva128->i2c.scl && ((val & 0x30) == 0)) - { - riva128->i2c.state = I2C_START; - riva128->i2c.addr = 0; - riva128->i2c.addrbits = 0; - riva128->i2c.data = 0; - riva128->i2c.databits = 0; - } - else if(!riva128->i2c.sda && !riva128->i2c.scl && ((val & 0x30) == 0x30)) riva128->i2c.state = I2C_STOP; - else if(riva128->i2c.state == I2C_START) - { - if(val & 0x20) - { - if(riva128->i2c.addrbits > 8) - { - riva128->i2c.addr <<= 1; - riva128->i2c.addr |= (val >> 4) & 1; - riva128->i2c.addrbits++; - } - if(riva128->i2c.addrbits == 8) - { - riva128->i2c.state = I2C_WAITACK; - riva128->i2c.sda = 0; - if(riva128->i2c.addr == 0xA1) riva128->i2c.edid_rom.addr = 0; - } - } - } - else if(riva128->i2c.state == I2C_WAITACK) - { - if(riva128->i2c.edid_rom.addr == 0x80) - { - riva128->i2c.edid_rom.addr = 0; - riva128->i2c.state = I2C_STOP; - } - else riva128->i2c.state = I2C_READ; - } - - riva128->i2c.sda = (val >> 4) & 1; - riva128->i2c.scl = (val >> 5) & 1; - break; - } - //if(svga->crtcreg > 0x18) - // nv_riva_log("RIVA 128 Extended CRTC write %02X %02x %04X:%08X\n", svga->crtcreg, val, CS, cpu_state.pc); - if (old != val) - { - if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) - { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } - return; - } - - svga_out(addr, val, svga); -} - - uint32_t riva128_ramin_readl(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; - return ret; -} - - uint8_t riva128_ramin_readb(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; - ret >>= 24 - ((addr & 3) << 3); - return ret; -} - - uint16_t riva128_ramin_readw(uint32_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; - ret >>= 16 - ((addr & 2) << 3); - return ret; -} - - void riva128_ramin_writel(uint32_t addr, uint32_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - riva128->pramin[(addr & 0x1ffffc) >> 2] = val; -} - - void riva128_ramin_writeb(uint32_t addr, uint8_t val, void *p) -{ - uint32_t tmp = riva128_ramin_readl(addr,p); - tmp &= ~(0xff << ((addr & 3) << 3)); - tmp |= val << ((addr & 3) << 3); - riva128_ramin_writel(addr, tmp, p); -} - - void riva128_ramin_writew(uint32_t addr, uint16_t val, void *p) -{ - uint32_t tmp = riva128_ramin_readl(addr,p); - tmp &= ~(0xffff << ((addr & 2) << 4)); - tmp |= val << ((addr & 2) << 4); - riva128_ramin_writel(addr, tmp, p); -} - - uint8_t riva128_pci_read(int func, int addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - //nv_riva_log("RIVA 128 PCI read %02X %04X:%08X\n", addr, CS, cpu_state.pc); - switch (addr) - { - case 0x00: - ret = riva128->vendor_id & 0xff; - break; - case 0x01: - ret = riva128->vendor_id >> 8; - break; - - case 0x02: - ret = riva128->device_id & 0xff; - break; - case 0x03: - ret = riva128->device_id >> 8; - break; - - case 0x04: - ret = riva128->pci_regs[0x04] & 0x37; - break; - case 0x05: - ret = riva128->pci_regs[0x05] & 0x01; - break; - - case 0x06: - ret = 0x20; - break; - case 0x07: - ret = riva128->pci_regs[0x07] & 0x73; - break; - - case 0x08: - ret = 0x00; - 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 0x0e: - ret = 0x00; - break; /*Header type*/ - - case 0x13: - case 0x17: - ret = riva128->pci_regs[addr]; - break; - - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: - ret = riva128->pci_regs[addr]; - //if(CS == 0x0028) output = 3; - break; - - case 0x30: - return riva128->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ - case 0x31: - return 0x00; - case 0x32: - return riva128->pci_regs[0x32]; - case 0x33: - return riva128->pci_regs[0x33]; - - case 0x34: - ret = 0x00; - break; - - case 0x3c: - ret = riva128->pci_regs[0x3c]; - break; - - case 0x3d: - ret = 0x01; - break; /*INTA*/ - - case 0x3e: - ret = 0x03; - break; - case 0x3f: - ret = 0x01; - break; - - } - // nv_riva_log("%02X\n", ret); - return ret; -} - - void riva128_reenable_svga_mappings(svga_t *svga) -{ - 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; - } -} - - void riva128_pci_write(int func, int addr, uint8_t val, void *p) -{ - //nv_riva_log("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - riva128_t *riva128 = (riva128_t *)p; - svga_t* svga = &riva128->svga; - 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: - riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; - mem_mapping_disable(&svga->mapping); - mem_mapping_disable(&riva128->mmio_mapping); - mem_mapping_disable(&riva128->linear_mapping); - mem_mapping_disable(&riva128->ramin_mapping); - if (val & PCI_COMMAND_IO) - { - io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - } - else io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - if (val & PCI_COMMAND_MEM) - { - uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; - uint32_t linear_addr = riva128->pci_regs[0x17] << 24; - if (!mmio_addr && !linear_addr) - { - riva128_reenable_svga_mappings(svga); - } - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); - mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); - } - } - return; - - case 0x05: - riva128->pci_regs[0x05] = val & 0x01; - return; - - case 0x07: - riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); - return; - - case 0x13: - { - uint32_t mmio_addr; - riva128->pci_regs[addr] = val; - mmio_addr = riva128->pci_regs[0x13] << 24; - mem_mapping_disable(&riva128->mmio_mapping); - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - return; - } - - case 0x17: - { - uint32_t linear_addr; - riva128->pci_regs[addr] = val; - linear_addr = riva128->pci_regs[0x17] << 24; - mem_mapping_disable(&riva128->linear_mapping); - mem_mapping_disable(&riva128->ramin_mapping); - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0xc00000); - mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); - } - return; - } - - case 0x30: - case 0x32: - case 0x33: - riva128->pci_regs[addr] = val; - mem_mapping_disable(&riva128->bios_rom.mapping); - if (riva128->pci_regs[0x30] & 0x01) - { - uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); - // nv_riva_log("RIVA 128 bios_rom enabled at %08x\n", addr); - mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x8000); - } - return; - - case 0x3c: - riva128->pci_regs[0x3c] = val & 0x0f; - return; - - case 0x40: - case 0x41: - case 0x42: - case 0x43: - riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f - return; - } -} - - void rivatnt_pci_write(int func, int addr, uint8_t val, void *p) -{ - //nv_riva_log("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - 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: - riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; - mem_mapping_disable(&svga->mapping); - mem_mapping_disable(&riva128->mmio_mapping); - mem_mapping_disable(&riva128->linear_mapping); - if (val & PCI_COMMAND_IO) - { - io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - } - else io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - if (val & PCI_COMMAND_MEM) - { - uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; - uint32_t linear_addr = riva128->pci_regs[0x17] << 24; - if (!mmio_addr && !linear_addr) - { - riva128_reenable_svga_mappings(svga); - } - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); - } - } - return; - - case 0x05: - riva128->pci_regs[0x05] = val & 0x01; - return; - - case 0x07: - riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); - return; - - case 0x13: - { - uint32_t mmio_addr; - riva128->pci_regs[addr] = val; - mmio_addr = riva128->pci_regs[0x13] << 24; - mem_mapping_disable(&riva128->mmio_mapping); - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - return; - } - - case 0x17: - { - uint32_t linear_addr; - riva128->pci_regs[addr] = val; - linear_addr = riva128->pci_regs[0x17] << 24; - mem_mapping_disable(&riva128->linear_mapping); - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); - } - return; - } - - case 0x30: - case 0x32: - case 0x33: - riva128->pci_regs[addr] = val; - mem_mapping_disable(&riva128->bios_rom.mapping); - if (riva128->pci_regs[0x30] & 0x01) - { - uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); - // nv_riva_log("RIVA TNT bios_rom enabled at %08x\n", addr); - mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x10000); - } - return; - - case 0x3c: - riva128->pci_regs[0x3c] = val & 0x0f; - return; - - case 0x40: - case 0x41: - case 0x42: - case 0x43: - riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f - return; - } -} - - void riva128_recalctimings(svga_t *svga) -{ - riva128_t *riva128 = (riva128_t *)svga->p; - - svga->ma_latch += (svga->crtc[0x19] & 0x1f) << 16; - svga->rowoffset += (svga->crtc[0x19] & 0xe0) << 3; - if (svga->crtc[0x25] & 0x01) svga->vtotal += 0x400; - if (svga->crtc[0x25] & 0x02) svga->dispend += 0x400; - if (svga->crtc[0x25] & 0x04) svga->vblankstart += 0x400; - if (svga->crtc[0x25] & 0x08) svga->vsyncstart += 0x400; - if (svga->crtc[0x25] & 0x10) svga->htotal += 0x100; - if (svga->crtc[0x2d] & 0x01) svga->hdisp += 0x100; - //The effects of the large screen bit seem to just be doubling the row offset. - //However, these large modes still don't work. Possibly core SVGA bug? It does report 640x2 res after all. - if (!(svga->crtc[0x1a] & 0x04)) svga->rowoffset <<= 1; - switch(svga->crtc[0x28] & 3) - { - case 1: - svga->bpp = 8; - svga->lowres = 0; - svga->render = svga_render_8bpp_highres; - break; - case 2: - svga->bpp = 16; - svga->lowres = 0; - svga->render = svga_render_16bpp_highres; - break; - case 3: - svga->bpp = 32; - svga->lowres = 0; - svga->render = svga_render_32bpp_highres; - break; - } - - /*if((svga->crtc[0x28] & 3) != 0) - { - if(svga->crtc[0x1a] & 2) svga_set_ramdac_type(svga, RAMDAC_6BIT); - else svga_set_ramdac_type(svga, RAMDAC_8BIT); - } - else svga_set_ramdac_type(svga, RAMDAC_6BIT);*/ - - double freq; - - if (((svga->miscout >> 2) & 2) == 2) - { - freq = 13500000.0; - - if(riva128->pramdac.v_m == 0) riva128->pramdac.v_m = 1; - else - { - freq = (freq * riva128->pramdac.v_n) / (1 << riva128->pramdac.v_p) / riva128->pramdac.v_m; - //nv_riva_log("RIVA 128 Pixel clock is %f Hz\n", freq); - } - - svga->clock = cpuclock / freq; - } - - if(riva128->card_id == 0x03) - { - freq = 13500000.0; - - if(riva128->pramdac.m_m == 0) riva128->pramdac.m_m = 1; - else - { - freq = (freq * riva128->pramdac.m_n) / (1 << riva128->pramdac.m_p) / riva128->pramdac.m_m; - //nv_riva_log("RIVA 128 Memory clock is %f Hz\n", freq); - } - - riva128->mfreq = freq; - riva128->mtime = (int64_t)((TIMER_USEC * 100000000.0) / riva128->mfreq); - riva128->menable = 1; - } - - if(riva128->card_id >= 0x04) - { - freq = 13500000.0; - - if(riva128->pramdac.nv_m == 0) riva128->pramdac.nv_m = 1; - else - { - freq = (freq * riva128->pramdac.nv_n) / (1 << riva128->pramdac.nv_p) / riva128->pramdac.nv_m; - //nv_riva_log("RIVA 128 Core clock is %f Hz\n", freq); - } - - riva128->nvfreq = freq; - riva128->nvtime = (int64_t)((TIMER_USEC * 100000000.0) / riva128->nvfreq); - riva128->nvenable = 1; - } -} - - -void *riva128_init(const device_t *info) -{ - riva128_t *riva128 = malloc(sizeof(riva128_t)); - memset(riva128, 0, sizeof(riva128_t)); - - riva128->card_id = 0x03; - riva128->is_nv3t = 0; - - riva128->vendor_id = 0x12d2; - riva128->device_id = 0x0018; - - riva128->memory_size = device_get_config_int("memory"); - - svga_init(&riva128->svga, riva128, riva128->memory_size << 20, - riva128_recalctimings, - riva128_in, riva128_out, - NULL, NULL); - - riva128->svga.decode_mask = (riva128->memory_size << 20) - 1; - - rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (PCI) - mem_mapping_disable(&riva128->bios_rom.mapping); - - mem_mapping_add(&riva128->mmio_mapping, 0, 0, - riva128_mmio_read, - riva128_mmio_read_w, - riva128_mmio_read_l, - riva128_mmio_write, - riva128_mmio_write_w, - riva128_mmio_write_l, - NULL, - 0, - riva128); - - mem_mapping_add(&riva128->ramin_mapping, 0, 0, - riva128_ramin_readb, - riva128_ramin_readw, - riva128_ramin_readl, - riva128_ramin_writeb, - riva128_ramin_writew, - riva128_ramin_writel, - NULL, - 0, - riva128); - - mem_mapping_add(&riva128->linear_mapping, 0, 0, - svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - 0, - &riva128->svga); - - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - - // riva128->pci_regs[4] = 3; - riva128->pci_regs[4] = 7; - riva128->pci_regs[5] = 0; - riva128->pci_regs[6] = 0; - riva128->pci_regs[7] = 2; - - riva128->pci_regs[0x2c] = 0xd2; - riva128->pci_regs[0x2d] = 0x12; - riva128->pci_regs[0x2e] = 0x00; - riva128->pci_regs[0x2f] = 0x03; - - riva128->pci_regs[0x30] = 0x00; - riva128->pci_regs[0x32] = 0x0c; - riva128->pci_regs[0x33] = 0x00; - - riva128->pmc.intr = 0; - riva128->pbus.intr = 0; - riva128->pfifo.intr = 0; - riva128->pgraph.intr = 0; - riva128->ptimer.intr = 0; - riva128->ptimer.intr_en = 0xffffffff; - - riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, riva128_pci_write, riva128); - - riva128->ptimer.clock_mul = 1; - riva128->ptimer.clock_div = 1; - - //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. - riva128->pramdac.m_m = 0x03; - riva128->pramdac.m_n = 0xc2; - riva128->pramdac.m_p = 0x0d; - - riva128->pramdac.nv_m = 0x03; - riva128->pramdac.nv_n = 0xc2; - riva128->pramdac.nv_p = 0x0d; - - riva128->i2c.addrbits = 0; - riva128->i2c.databits = 0; - riva128->i2c.state = I2C_STOP; - - uint8_t edid_rom[128] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x08, 0x01, 0x03, 0x81, 0x32, 0x26, 0x78, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x61, 0x40, - 0x45, 0x40, 0x31, 0x40, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, - 0x00, 0xfd, 0x00, 0x01, 0xff, 0x01, 0xff, 0xff, - 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 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, 0xec}; - - { - int i = 0; - for(;i<128;i++) - { - riva128->i2c.edid_rom.edid_rom[i] = edid_rom[i]; - } - } - - riva128->menable = 1; - riva128->nvenable = 1; - - timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); - timer_add(riva128_nvclk_poll, &riva128->nvtime, &timer_one, riva128); - - riva128->svga.vblank_start = riva128_vblank_start; - - riva128->pgraph.beta = 0xffffffff; - - return riva128; -} - -void riva128_close(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - FILE *f = fopen("vram.dmp", "wb"); - fwrite(riva128->svga.vram, 4 << 20, 1, f); - fclose(f); - - svga_close(&riva128->svga); - - free(riva128); -} - -int riva128_available(void) -{ - return rom_present(L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi"); -} - -void riva128_speed_changed(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_recalctimings(&riva128->svga); -} - -void riva128_force_redraw(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->svga.fullchange = changeframecount; -} - -const device_config_t riva128_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 4, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - { - "" - } - }, - }, - { - "", "", -1 - } -}; - -#if 0 -const device_config_t riva128zx_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "" - } - }, - .default_int = 4 - }, - { - .type = -1 - } -}; -#endif - -const device_t riva128_device = -{ - "nVidia RIVA 128", - DEVICE_PCI, - 0, - riva128_init, - riva128_close, - NULL, - riva128_available, - riva128_speed_changed, - riva128_force_redraw, - riva128_config -}; - - -void *rivatnt_init(const device_t *info) -{ - riva128_t *riva128 = malloc(sizeof(riva128_t)); - memset(riva128, 0, sizeof(riva128_t)); - - riva128->card_id = 0x04; - riva128->is_nv3t = 0; - - riva128->vendor_id = 0x10de; - riva128->device_id = 0x0020; - - riva128->memory_size = device_get_config_int("memory"); - - svga_init(&riva128->svga, riva128, riva128->memory_size << 20, - riva128_recalctimings, - riva128_in, riva128_out, - NULL, NULL); - - riva128->svga.decode_mask = (riva128->memory_size << 20) - 1; - - rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/NV4_diamond_revB.rom", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); - if (PCI) - mem_mapping_disable(&riva128->bios_rom.mapping); - - mem_mapping_add(&riva128->mmio_mapping, 0, 0, - riva128_mmio_read, - riva128_mmio_read_w, - riva128_mmio_read_l, - riva128_mmio_write, - riva128_mmio_write_w, - riva128_mmio_write_l, - NULL, - 0, - riva128); - mem_mapping_add(&riva128->linear_mapping, 0, 0, - svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - 0, - &riva128->svga); - - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - - // riva128->pci_regs[4] = 3; - riva128->pci_regs[4] = 7; - riva128->pci_regs[5] = 0; - riva128->pci_regs[6] = 0; - riva128->pci_regs[7] = 2; - - riva128->pci_regs[0x2c] = 0x02; - riva128->pci_regs[0x2d] = 0x11; - riva128->pci_regs[0x2e] = 0x16; - riva128->pci_regs[0x2f] = 0x10; - - riva128->pci_regs[0x30] = 0x00; - riva128->pci_regs[0x32] = 0x0c; - riva128->pci_regs[0x33] = 0x00; - - riva128->pmc.intr = 0; - riva128->pbus.intr = 0; - riva128->pfifo.intr = 0; - riva128->pgraph.intr = 0; - - riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, rivatnt_pci_write, riva128); - - //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. - riva128->pramdac.m_m = 0x03; - riva128->pramdac.m_n = 0xc2; - riva128->pramdac.m_p = 0x0d; - - riva128->pramdac.nv_m = 0x03; - riva128->pramdac.nv_n = 0xc2; - riva128->pramdac.nv_p = 0x0d; - - riva128->i2c.addrbits = 0; - riva128->i2c.databits = 0; - riva128->i2c.state = I2C_STOP; - - uint8_t edid_rom[128] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x08, 0x01, 0x03, 0x81, 0x32, 0x26, 0x78, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x61, 0x40, - 0x45, 0x40, 0x31, 0x40, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, - 0x00, 0xfd, 0x00, 0x01, 0xff, 0x01, 0xff, 0xff, - 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 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, 0xec}; - - { - int i = 0; - for(;i<128;i++) - { - riva128->i2c.edid_rom.edid_rom[i] = edid_rom[i]; - } - } - - riva128->menable = 1; - riva128->nvenable = 1; - - timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); - timer_add(riva128_nvclk_poll, &riva128->nvtime, &timer_one, riva128); - - riva128->svga.vblank_start = riva128_vblank_start; - - return riva128; -} - -void rivatnt_close(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - FILE *f = fopen("vram.dmp", "wb"); - fwrite(riva128->svga.vram, 4 << 20, 1, f); - fclose(f); - - svga_close(&riva128->svga); - - free(riva128); -} - -int rivatnt_available(void) -{ - return rom_present(L"roms/video/nv_riva128/NV4_diamond_revB.rom"); -} - -void rivatnt_speed_changed(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_recalctimings(&riva128->svga); -} - -void rivatnt_force_redraw(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->svga.fullchange = changeframecount; -} - -const device_config_t rivatnt_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 16, - { - { - "4 MB", 4 - }, - { - "8 MB", 8 - }, - { - "16 MB", 16 - }, - { - "" - } - }, - }, - { - "", "", -1 - } -}; - -const device_t rivatnt_device = -{ - "nVidia RIVA TNT", - DEVICE_PCI, - 0, - rivatnt_init, - rivatnt_close, - NULL, - rivatnt_available, - rivatnt_speed_changed, - rivatnt_force_redraw, - rivatnt_config -}; - -void *rivatnt2_init(const device_t *info) -{ - riva128_t *riva128 = malloc(sizeof(riva128_t)); - memset(riva128, 0, sizeof(riva128_t)); - - riva128->card_id = 0x05; - riva128->is_nv3t = 0; - - int model = device_get_config_int("model"); - - riva128->vendor_id = 0x10de; - riva128->device_id = ((model > 1) ? 0x0029 : 0x0028); - - riva128->memory_size = device_get_config_int("memory"); - - svga_init(&riva128->svga, riva128, riva128->memory_size << 20, - riva128_recalctimings, - riva128_in, riva128_out, - NULL, NULL); - - riva128->svga.decode_mask = 0x3fffff; - - switch(model) - { - case 0: - rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/NV5diamond.bin", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); - break; - case 1: - rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/inno3d64bit.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); - break; - case 2: - rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/creative.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); - break; - } - if (PCI) - mem_mapping_disable(&riva128->bios_rom.mapping); - - mem_mapping_add(&riva128->mmio_mapping, 0, 0, - riva128_mmio_read, - riva128_mmio_read_w, - riva128_mmio_read_l, - riva128_mmio_write, - riva128_mmio_write_w, - riva128_mmio_write_l, - NULL, - 0, - riva128); - mem_mapping_add(&riva128->linear_mapping, 0, 0, - svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - 0, - &riva128->svga); - - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - - // riva128->pci_regs[4] = 3; - riva128->pci_regs[4] = 7; - riva128->pci_regs[5] = 0; - riva128->pci_regs[6] = 0; - riva128->pci_regs[7] = 2; - - riva128->pci_regs[0x2c] = 0x02; - riva128->pci_regs[0x2d] = 0x11; - riva128->pci_regs[0x2e] = 0x16; - riva128->pci_regs[0x2f] = 0x10; - - riva128->pci_regs[0x30] = 0x00; - riva128->pci_regs[0x32] = 0x0c; - riva128->pci_regs[0x33] = 0x00; - - riva128->pmc.intr = 0; - riva128->pbus.intr = 0; - riva128->pfifo.intr = 0; - riva128->pgraph.intr = 0; - - riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, rivatnt_pci_write, riva128); - - //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. - riva128->pramdac.m_m = 0x03; - riva128->pramdac.m_n = 0xc2; - riva128->pramdac.m_p = 0x0d; - - riva128->pramdac.nv_m = 0x03; - riva128->pramdac.nv_n = 0xc2; - riva128->pramdac.nv_p = 0x0d; - - riva128->i2c.addrbits = 0; - riva128->i2c.databits = 0; - riva128->i2c.state = I2C_STOP; - - uint8_t edid_rom[128] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x08, 0x01, 0x03, 0x81, 0x32, 0x26, 0x78, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x61, 0x40, - 0x45, 0x40, 0x31, 0x40, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, - 0x00, 0xfd, 0x00, 0x01, 0xff, 0x01, 0xff, 0xff, - 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 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, 0xec}; - - { - int i = 0; - for(;i<128;i++) - { - riva128->i2c.edid_rom.edid_rom[i] = edid_rom[i]; - } - } - - riva128->menable = 1; - riva128->nvenable = 1; - - timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); - timer_add(riva128_nvclk_poll, &riva128->nvtime, &timer_one, riva128); - - riva128->svga.vblank_start = riva128_vblank_start; - - return riva128; -} - -void rivatnt2_close(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - FILE *f = fopen("vram.dmp", "wb"); - fwrite(riva128->svga.vram, 4 << 20, 1, f); - fclose(f); - - svga_close(&riva128->svga); - - free(riva128); -} - -int rivatnt2_available(void) -{ - return rom_present(L"roms/video/nv_riva128/NV5diamond.bin") || rom_present(L"roms/video/nv_riva128/inno3d64bit.BIN") || rom_present(L"roms/video/nv_riva128/creative.BIN"); -} - -void rivatnt2_speed_changed(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_recalctimings(&riva128->svga); -} - -void rivatnt2_force_redraw(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->svga.fullchange = changeframecount; -} - -const device_config_t rivatnt2_config[] = -{ - { - "model", "Card model", CONFIG_SELECTION, "", 0, - { - { - "Vanilla TNT2", 0, - }, - { - "TNT2 Pro", 1, - }, - { - "TNT2 Ultra", 2, - }, - }, - }, - { - "memory", "Memory size", CONFIG_SELECTION, "", 32, - { - { - "4 MB", 4 - }, - { - "8 MB", 8 - }, - { - "16 MB", 16 - }, - { - "32 MB", 32 - }, - { - "" - } - }, - }, - { - "", "", -1 - } -}; - -const device_t rivatnt2_device = -{ - "nVidia RIVA TNT2", - DEVICE_PCI, - 0, - rivatnt2_init, - rivatnt2_close, - NULL, - rivatnt2_available, - rivatnt2_speed_changed, - rivatnt2_force_redraw, - rivatnt2_config -}; diff --git a/src/video/vid_nv_riva128.h b/src/video/vid_nv_riva128.h deleted file mode 100644 index 8c8e2cd6b..000000000 --- a/src/video/vid_nv_riva128.h +++ /dev/null @@ -1,3 +0,0 @@ -extern const device_t riva128_device; -extern const device_t rivatnt_device; -extern const device_t rivatnt2_device; diff --git a/src/video/vid_nvidia.c b/src/video/vid_nvidia.c deleted file mode 100644 index 2c210e0ac..000000000 --- a/src/video/vid_nvidia.c +++ /dev/null @@ -1,965 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * nVidia RIVA 128 emulation. - * - * Version: @(#)vid_nv_riva128.c 1.0.7 2018/04/29 - * - * Author: Melissa Goad - * Miran Grca, - * - * Copyright 2015-2018 Melissa Goad. - * Copyright 2015-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "../86box.h" -#include "../cpu/cpu.h" -#include "../machine/machine.h" -#include "../io.h" -#include "../mem.h" -#include "../pci.h" -#include "../pic.h" -#include "../rom.h" -#include "../timer.h" -#include "../device.h" -#include "../plat.h" -#include "video.h" -#include "vid_nv_riva128.h" -#include "vid_svga.h" -#include "vid_svga_render.h" - -typedef struct riva128_t -{ - mem_mapping_t linear_mapping; - mem_mapping_t mmio_mapping; - - rom_t bios_rom; - - svga_t svga; - - uint8_t card_id; - int pci_card; - int is_nv3t; - - uint16_t vendor_id; - uint16_t device_id; - - uint32_t linear_base, linear_size; - - uint16_t rma_addr; - - uint8_t pci_regs[256]; - - int memory_size; - - uint8_t ext_regs_locked; - - uint8_t read_bank; - uint8_t write_bank; - - struct - { - uint32_t intr; - uint32_t intr_en; - uint32_t intr_line; - uint32_t enable; - } pmc; - - struct - { - uint32_t intr; - uint32_t intr_en; - } pbus; - - struct - { - uint32_t cache_error; - uint32_t intr; - uint32_t intr_en; - - uint32_t ramht; - uint32_t ramht_addr; - uint32_t ramht_size; - - uint32_t ramfc; - uint32_t ramfc_addr; - - uint32_t ramro; - uint32_t ramro_addr; - uint32_t ramro_size; - - uint16_t chan_mode; - uint16_t chan_dma; - uint16_t chan_size; //0 = 1024, 1 = 512 - - uint32_t runout_put, runout_get; - - struct - { - uint32_t dmaput; - uint32_t dmaget; - } channels[16]; - - struct - { - int chanid; - int push_enabled; - int runout; - uint32_t get, put; - uint32_t ctx; - } caches[2]; - - struct - { - int subchan; - uint16_t method; - uint32_t param; - } cache0, cache1[64]; - } pfifo; - - struct - { - uint32_t addr; - uint32_t data; - uint8_t access_reg[4]; - uint8_t mode; - } rma; - - struct - { - uint32_t intr, intr_en; - - uint64_t time; - uint32_t alarm; - - uint16_t clock_mul, clock_div; - } ptimer; - - struct - { - int width; - int bpp; - uint32_t config_0; - } pfb; - - struct - { - uint32_t boot_0; - } pextdev; - - struct - { - int pgraph_speedhack; - - uint32_t obj_handle[8]; - uint16_t obj_class[8]; - - uint32_t debug[5]; - - uint32_t intr; - uint32_t intr_en; - - uint32_t invalid; - uint32_t invalid_en; - - uint32_t ctx_switch[5]; - uint32_t ctx_control; - uint32_t ctx_user; - uint32_t ctx_cache[8][5]; - - uint32_t fifo_enable; - - uint32_t fifo_st2_addr; - uint32_t fifo_st2_data; - - uint32_t uclip_xmin, uclip_ymin, uclip_xmax, uclip_ymax; - uint32_t oclip_xmin, oclip_ymin, oclip_xmax, oclip_ymax; - - uint32_t src_canvas_min, src_canvas_max; - uint32_t dst_canvas_min, dst_canvas_max; - - uint8_t rop; - - uint32_t chroma; - - uint32_t beta; - - uint32_t notify; - - //NV3 - uint32_t surf_offset[4]; - uint32_t surf_pitch[4]; - - uint32_t cliprect_min[2]; - uint32_t cliprect_max[2]; - uint32_t cliprect_ctrl; - - uint32_t instance; - - uint32_t dma_intr, dma_intr_en; - - uint32_t status; - } pgraph; - - struct - { - uint32_t nvpll; - uint32_t nv_m,nv_n,nv_p; - - uint32_t mpll; - uint32_t m_m,m_n,m_p; - - uint32_t vpll; - uint32_t v_m,v_n,v_p; - - uint32_t pll_ctrl; - - uint32_t gen_ctrl; - } pramdac; - - uint32_t channels[16][8][0x2000]; - - struct - { - int scl; - int sda; - } i2c; - - int64_t mtime, mfreq; -} riva128_t; - - -#ifdef ENABLE_NVIDIA_LOG -int nvidia_do_log = ENABLE_NVIDIA_LOG; -#endif - - -static void -nvidia_log(const char *fmt, ...) -{ -#ifdef ENABLE_NVIDIA_LOG - va_list ap; - - if (nvidia_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - -uint8_t riva128_rma_in(uint16_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t* svga = &riva128->svga; - uint8_t ret = 0; - - addr &= 0xff; - - //nvidia_log("RIVA 128 RMA read %04X %04X:%08X\n", addr, CS, cpu_state.pc); - - switch(addr) - { - case 0x00: - ret = 0x65; - break; - case 0x01: - ret = 0xd0; - break; - case 0x02: - ret = 0x16; - break; - case 0x03: - ret = 0x2b; - break; - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - if(riva128->rma.addr < 0x1000000) /*ret = riva128_mmio_read((riva128->rma.addr + (addr & 3)) & 0xffffff, riva128);*/nvidia_log("RIVA 128 MMIO write %08x %08x\n", riva128->rma.addr & 0xffffff, riva128->rma.data); - else ret = svga_read_linear((riva128->rma.addr - 0x1000000), svga); - break; - } - - return ret; -} - -void riva128_rma_out(uint16_t addr, uint8_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t* svga = &riva128->svga; - - addr &= 0xff; - - //nvidia_log("RIVA 128 RMA write %04X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - - switch(addr) - { - case 0x04: - riva128->rma.addr &= ~0xff; - riva128->rma.addr |= val; - break; - case 0x05: - riva128->rma.addr &= ~0xff00; - riva128->rma.addr |= (val << 8); - break; - case 0x06: - riva128->rma.addr &= ~0xff0000; - riva128->rma.addr |= (val << 16); - break; - case 0x07: - riva128->rma.addr &= ~0xff000000; - riva128->rma.addr |= (val << 24); - break; - case 0x08: - case 0x0c: - case 0x10: - case 0x14: - riva128->rma.data &= ~0xff; - riva128->rma.data |= val; - break; - case 0x09: - case 0x0d: - case 0x11: - case 0x15: - riva128->rma.data &= ~0xff00; - riva128->rma.data |= (val << 8); - break; - case 0x0a: - case 0x0e: - case 0x12: - case 0x16: - riva128->rma.data &= ~0xff0000; - riva128->rma.data |= (val << 16); - break; - case 0x0b: - case 0x0f: - case 0x13: - case 0x17: - riva128->rma.data &= ~0xff000000; - riva128->rma.data |= (val << 24); - if(riva128->rma.addr < 0x1000000) /*riva128_mmio_write_l(riva128->rma.addr & 0xffffff, riva128->rma.data, riva128);*/nvidia_log("RIVA 128 MMIO write %08x %08x\n", riva128->rma.addr & 0xffffff, riva128->rma.data); - else svga_writel_linear((riva128->rma.addr - 0x1000000), riva128->rma.data, svga); - break; - } - - if(addr & 0x10) riva128->rma.addr+=4; -} - -uint8_t riva128_in(uint16_t addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t* svga = &riva128->svga; - uint8_t ret = 0; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - // if (addr != 0x3da) nvidia_log("S3 in %04X %04X:%08X ", addr, CS, cpu_state.pc); - switch (addr) - { - case 0x3D4: - ret = svga->crtcreg; - break; - case 0x3D5: - switch(svga->crtcreg) - { - case 0x28: - ret = svga->crtc[0x28] & 0x3f; - break; - case 0x34: - ret = svga->displine & 0xff; - break; - case 0x35: - ret = (svga->displine >> 8) & 7; - break; - case 0x3e: - //DDC status register - ret = (riva128->i2c.sda << 3) | (riva128->i2c.scl << 2); - break; - default: - ret = svga->crtc[svga->crtcreg]; - break; - } - //if(svga->crtcreg > 0x18) - // nvidia_log("RIVA 128 Extended CRTC read %02X %04X:%08X\n", svga->crtcreg, CS, cpu_state.pc); - break; - default: - ret = svga_in(addr, svga); - break; - } - // if (addr != 0x3da) nvidia_log("%02X\n", ret); - return ret; -} - -void riva128_out(uint16_t addr, uint8_t val, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - svga_t *svga = &riva128->svga; - - uint8_t old; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - switch(addr) - { - case 0x3D4: - svga->crtcreg = val; - 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; - switch(svga->crtcreg) - { - case 0x1e: - riva128->read_bank = val; - if (svga->chain4) svga->read_bank = riva128->read_bank << 15; - else svga->read_bank = riva128->read_bank << 13; - break; - case 0x1d: - riva128->write_bank = val; - if (svga->chain4) svga->write_bank = riva128->write_bank << 15; - else svga->write_bank = riva128->write_bank << 13; - break; - case 0x19: - case 0x1a: - case 0x25: - case 0x28: - case 0x2d: - svga_recalctimings(svga); - break; - case 0x38: - riva128->rma.mode = val & 0xf; - break; - case 0x3f: - riva128->i2c.sda = (val >> 4) & 1; - riva128->i2c.scl = (val >> 5) & 1; - break; - } - //if(svga->crtcreg > 0x18) - // nvidia_log("RIVA 128 Extended CRTC write %02X %02x %04X:%08X\n", svga->crtcreg, val, CS, cpu_state.pc); - if (old != val) - { - if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) - { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } - return; - } - - svga_out(addr, val, svga); -} - -uint8_t riva128_pci_read(int func, int addr, void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - uint8_t ret = 0; - //nvidia_log("RIVA 128 PCI read %02X %04X:%08X\n", addr, CS, cpu_state.pc); - switch (addr) - { - case 0x00: - ret = riva128->vendor_id & 0xff; - break; - case 0x01: - ret = riva128->vendor_id >> 8; - break; - - case 0x02: - ret = riva128->device_id & 0xff; - break; - case 0x03: - ret = riva128->device_id >> 8; - break; - - case 0x04: - ret = riva128->pci_regs[0x04] & 0x37; - break; - case 0x05: - ret = riva128->pci_regs[0x05] & 0x01; - break; - - case 0x06: - ret = 0x20; - break; - case 0x07: - ret = riva128->pci_regs[0x07] & 0x73; - break; - - case 0x08: - ret = 0x00; - 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 0x0e: - ret = 0x00; - break; /*Header type*/ - - case 0x13: - case 0x17: - ret = riva128->pci_regs[addr]; - break; - - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: - ret = riva128->pci_regs[addr]; - //if(CS == 0x0028) output = 3; - break; - - case 0x30: - return riva128->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ - case 0x31: - return 0x00; - case 0x32: - return riva128->pci_regs[0x32]; - case 0x33: - return riva128->pci_regs[0x33]; - - case 0x34: - ret = 0x00; - break; - - case 0x3c: - ret = riva128->pci_regs[0x3c]; - break; - - case 0x3d: - ret = 0x01; - break; /*INTA*/ - - case 0x3e: - ret = 0x03; - break; - case 0x3f: - ret = 0x01; - break; - - } - // nvidia_log("%02X\n", ret); - return ret; -} - -void riva128_reenable_svga_mappings(svga_t *svga) -{ - 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; - } -} - -void riva128_pci_write(int func, int addr, uint8_t val, void *p) -{ - //nvidia_log("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); - riva128_t *riva128 = (riva128_t *)p; - svga_t* svga = &riva128->svga; - 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: - riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; - mem_mapping_disable(&svga->mapping); - mem_mapping_disable(&riva128->mmio_mapping); - mem_mapping_disable(&riva128->linear_mapping); - if (val & PCI_COMMAND_IO) - { - io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - } - else io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - if (val & PCI_COMMAND_MEM) - { - uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; - uint32_t linear_addr = riva128->pci_regs[0x17] << 24; - if (!mmio_addr && !linear_addr) - { - riva128_reenable_svga_mappings(svga); - } - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); - } - } - return; - - case 0x05: - riva128->pci_regs[0x05] = val & 0x01; - return; - - case 0x07: - riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); - return; - - case 0x13: - { - uint32_t mmio_addr; - riva128->pci_regs[addr] = val; - mmio_addr = riva128->pci_regs[0x13] << 24; - mem_mapping_disable(&riva128->mmio_mapping); - if (mmio_addr) - { - mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); - } - return; - } - - case 0x17: - { - uint32_t linear_addr; - riva128->pci_regs[addr] = val; - linear_addr = riva128->pci_regs[0x17] << 24; - mem_mapping_disable(&riva128->linear_mapping); - if (linear_addr) - { - mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); - } - return; - } - - case 0x30: - case 0x32: - case 0x33: - riva128->pci_regs[addr] = val; - mem_mapping_disable(&riva128->bios_rom.mapping); - if (riva128->pci_regs[0x30] & 0x01) - { - uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); - // nvidia_log("RIVA 128 bios_rom enabled at %08x\n", addr); - mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x8000); - } - return; - - case 0x3c: - riva128->pci_regs[0x3c] = val & 0x0f; - return; - - case 0x40: - case 0x41: - case 0x42: - case 0x43: - riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f - return; - } -} - -void riva128_recalctimings(svga_t *svga) -{ - riva128_t *riva128 = (riva128_t *)svga->p; - - svga->ma_latch += (svga->crtc[0x19] & 0x1f) << 16; - svga->rowoffset += (svga->crtc[0x19] & 0xe0) << 3; - if (svga->crtc[0x25] & 0x01) svga->vtotal += 0x400; - if (svga->crtc[0x25] & 0x02) svga->dispend += 0x400; - if (svga->crtc[0x25] & 0x04) svga->vblankstart += 0x400; - if (svga->crtc[0x25] & 0x08) svga->vsyncstart += 0x400; - if (svga->crtc[0x25] & 0x10) svga->htotal += 0x100; - if (svga->crtc[0x2d] & 0x01) svga->hdisp += 0x100; - //The effects of the large screen bit seem to just be doubling the row offset. - //However, these large modes still don't work. Possibly core SVGA bug? It does report 640x2 res after all. - //if (!(svga->crtc[0x1a] & 0x04)) svga->rowoffset <<= 1; - switch(svga->crtc[0x28] & 3) - { - case 1: - svga->bpp = 8; - svga->lowres = 0; - svga->render = svga_render_8bpp_highres; - break; - case 2: - svga->bpp = 16; - svga->lowres = 0; - svga->render = svga_render_16bpp_highres; - break; - case 3: - svga->bpp = 32; - svga->lowres = 0; - svga->render = svga_render_32bpp_highres; - break; - } - - /*if((svga->crtc[0x28] & 3) != 0) - { - if(svga->crtc[0x1a] & 2) svga_set_ramdac_type(svga, RAMDAC_6BIT); - else svga_set_ramdac_type(svga, RAMDAC_8BIT); - } - else svga_set_ramdac_type(svga, RAMDAC_6BIT);*/ - - double freq; - - if (((svga->miscout >> 2) & 2) == 2) - { - freq = 13500000.0; - - if(riva128->pramdac.v_m == 0) riva128->pramdac.v_m = 1; - else - { - freq = (freq * riva128->pramdac.v_n) / (1 << riva128->pramdac.v_p) / riva128->pramdac.v_m; - //nvidia_log("RIVA 128 Pixel clock is %f Hz\n", freq); - } - - svga->clock = cpuclock / freq; - } - - if(riva128->card_id == 0x03) - { - freq = 13500000.0; - - if(riva128->pramdac.m_m == 0) riva128->pramdac.m_m = 1; - else - { - freq = (freq * riva128->pramdac.m_n) / (1 << riva128->pramdac.m_p) / riva128->pramdac.m_m; - //nvidia_log("RIVA 128 Memory clock is %f Hz\n", freq); - } - - riva128->mfreq = freq; - riva128->mtime = (int64_t)((TIMER_USEC * 100000000.0) / riva128->mfreq); - } -} - - -void *riva128_init(const device_t *info) -{ - riva128_t *riva128 = malloc(sizeof(riva128_t)); - memset(riva128, 0, sizeof(riva128_t)); - - riva128->card_id = 0x03; - riva128->is_nv3t = 0; - - riva128->vendor_id = 0x12d2; - riva128->device_id = 0x0018; - - riva128->memory_size = device_get_config_int("memory"); - - svga_init(&riva128->svga, riva128, riva128->memory_size << 20, - riva128_recalctimings, - riva128_in, riva128_out, - NULL, NULL); - - riva128->svga.decode_mask = (riva128->memory_size << 20) - 1; - - rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (PCI) - mem_mapping_disable(&riva128->bios_rom.mapping); - - /*mem_mapping_add(&riva128->mmio_mapping, 0, 0, - riva128_mmio_read, - riva128_mmio_read_w, - riva128_mmio_read_l, - riva128_mmio_write, - riva128_mmio_write_w, - riva128_mmio_write_l, - NULL, - 0, - riva128);*/ - - mem_mapping_add(&riva128->linear_mapping, 0, 0, - svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - 0, - &riva128->svga); - - io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); - - // riva128->pci_regs[4] = 3; - riva128->pci_regs[4] = 7; - riva128->pci_regs[5] = 0; - riva128->pci_regs[6] = 0; - riva128->pci_regs[7] = 2; - - riva128->pci_regs[0x2c] = 0xd2; - riva128->pci_regs[0x2d] = 0x12; - riva128->pci_regs[0x2e] = 0x00; - riva128->pci_regs[0x2f] = 0x03; - - riva128->pci_regs[0x30] = 0x00; - riva128->pci_regs[0x32] = 0x0c; - riva128->pci_regs[0x33] = 0x00; - - riva128->pmc.intr = 0; - riva128->pbus.intr = 0; - riva128->pfifo.intr = 0; - riva128->pgraph.intr = 0; - riva128->ptimer.intr = 0; - - riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, riva128_pci_write, riva128); - - riva128->ptimer.clock_mul = 1; - riva128->ptimer.clock_div = 1; - - //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. - riva128->pramdac.m_m = 0x03; - riva128->pramdac.m_n = 0xc2; - riva128->pramdac.m_p = 0x0d; - - //timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); - - return riva128; -} - -void riva128_close(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - FILE *f = fopen("vram.dmp", "wb"); - fwrite(riva128->svga.vram, 4 << 20, 1, f); - fclose(f); - - svga_close(&riva128->svga); - - free(riva128); -} - -int riva128_available(void) -{ - return rom_present(L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi"); -} - -void riva128_speed_changed(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - svga_recalctimings(&riva128->svga); -} - -void riva128_force_redraw(void *p) -{ - riva128_t *riva128 = (riva128_t *)p; - - riva128->svga.fullchange = changeframecount; -} - -const device_config_t riva128_config[] = -{ - { - "memory", "Memory size", CONFIG_SELECTION, "", 4, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - { - "" - } - }, - }, - { - "", "", -1 - } -}; - -#if 0 -const device_config_t riva128zx_config[] = -{ - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "" - } - }, - .default_int = 4 - }, - { - .type = -1 - } -}; -#endif - -const device_t riva128_device = -{ - "nVidia RIVA 128", - DEVICE_PCI, - 0, - riva128_init, - riva128_close, - NULL, - riva128_available, - riva128_speed_changed, - riva128_force_redraw, - riva128_config -}; \ No newline at end of file diff --git a/src/video/vid_nvidia.h b/src/video/vid_nvidia.h deleted file mode 100644 index c55533d2c..000000000 --- a/src/video/vid_nvidia.h +++ /dev/null @@ -1 +0,0 @@ -extern const device_t riva128_device; diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index 9d166d6e0..467d2a67c 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -8,7 +8,7 @@ * * Oak OTI037C/67/077 emulation. * - * Version: @(#)vid_oak_oti.c 1.0.12 2018/04/26 + * Version: @(#)vid_oak_oti.c 1.0.18 2018/10/09 * * Authors: Sarah Walker, * Miran Grca, @@ -16,13 +16,13 @@ * Copyright 2008-2018 Sarah Walker. * Copyright 2016-2018 Miran Grca. */ -#include #include -#include #include +#include #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -30,10 +30,18 @@ #include "vid_oak_oti.h" #include "vid_svga.h" -#define BIOS_37C_PATH L"roms/video/oti/bios.bin" -#define BIOS_77_PATH L"roms/video/oti/oti077.vbi" +#define BIOS_037C_PATH L"roms/video/oti/bios.bin" +#define BIOS_067_AMA932J_PATH L"roms/machines/ama932j/oti067.bin" +#define BIOS_077_PATH L"roms/video/oti/oti077.vbi" +enum { + OTI_037C, + OTI_067 = 2, + OTI_067_AMA932J, + OTI_077 = 5 +}; + typedef struct { svga_t svga; @@ -42,16 +50,17 @@ typedef struct { int index; uint8_t regs[32]; + uint8_t chip_id; uint8_t pos; - - uint8_t enable_register; + uint8_t enable_register; + uint8_t dipswitch_val; uint32_t vram_size; uint32_t vram_mask; - - uint8_t chip_id; } oti_t; +static video_timings_t timing_oti = {VIDEO_ISA, 6, 8,16, 6, 8,16}; + static void oti_out(uint16_t addr, uint8_t val, void *p) @@ -59,34 +68,43 @@ oti_out(uint16_t addr, uint8_t val, void *p) oti_t *oti = (oti_t *)p; svga_t *svga = &oti->svga; uint8_t old; - uint8_t idx; + uint8_t idx, enable; + + if (!oti->chip_id && !(oti->enable_register & 1) && (addr != 0x3C3)) + return; - if (!(oti->enable_register & 1) && addr != 0x3C3) - return; - if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { case 0x3C3: - oti->enable_register = val & 1; - return; - + if (!oti->chip_id) { + oti->enable_register = val & 1; + return; + } else + break; + case 0x3D4: - svga->crtcreg = val; + if (oti->chip_id) + svga->crtcreg = val & 0x3f; + else + svga->crtcreg = val; /* FIXME: The BIOS wants to set the test bit? */ return; case 0x3D5: - if (svga->crtcreg & 0x20) + if (oti->chip_id && (svga->crtcreg & 0x20)) return; - if (((svga->crtcreg & 31) < 7) && (svga->crtc[0x11] & 0x80)) + idx = svga->crtcreg; + if (!oti->chip_id) + idx &= 0x1f; + if ((idx < 7) && (svga->crtc[0x11] & 0x80)) return; - if (((svga->crtcreg & 31) == 7) && (svga->crtc[0x11] & 0x80)) + if ((idx == 7) && (svga->crtc[0x11] & 0x80)) val = (svga->crtc[7] & ~0x10) | (val & 0x10); - old = svga->crtc[svga->crtcreg & 31]; - svga->crtc[svga->crtcreg & 31] = val; + old = svga->crtc[idx]; + svga->crtc[idx] = val; if (old != val) { - if ((svga->crtcreg & 31) < 0xE || (svga->crtcreg & 31) > 0x10) { + if ((idx < 0x0e) || (idx > 0x10)) { svga->fullchange = changeframecount; svga_recalctimings(svga); } @@ -94,30 +112,60 @@ oti_out(uint16_t addr, uint8_t val, void *p) break; case 0x3DE: - oti->index = val; + if (oti->chip_id) + oti->index = val & 0x1f; + else + oti->index = val; return; case 0x3DF: - idx = oti->index & 0x1f; + idx = oti->index; + if (!oti->chip_id) + idx &= 0x1f; oti->regs[idx] = val; switch (idx) { case 0xD: - if (oti->chip_id) - { + if (oti->chip_id == OTI_067) { svga->vram_display_mask = (val & 0xc) ? oti->vram_mask : 0x3ffff; + if (!(val & 0x80)) + svga->vram_display_mask = 0x3ffff; + if ((val & 0x80) && oti->vram_size == 256) mem_mapping_disable(&svga->mapping); else mem_mapping_enable(&svga->mapping); - if (!(val & 0x80)) - svga->vram_display_mask = 0x3ffff; - } - else - { - if (val & 0x80) - mem_mapping_disable(&svga->mapping); + } else if (oti->chip_id == OTI_077) { + svga->vram_display_mask = (val & 0xc) ? oti->vram_mask : 0x3ffff; + + switch ((val & 0xc0) >> 6) { + case 0x00: /* 256 kB of memory */ + default: + enable = (oti->vram_size >= 256); + if (val & 0xc) + svga->vram_display_mask = MIN(oti->vram_mask, 0x3ffff); + break; + case 0x01: /* 1 MB of memory */ + case 0x03: + enable = (oti->vram_size >= 1024); + if (val & 0xc) + svga->vram_display_mask = MIN(oti->vram_mask, 0xfffff); + break; + case 0x02: /* 512 kB of memory */ + enable = (oti->vram_size >= 512); + if (val & 0xc) + svga->vram_display_mask = MIN(oti->vram_mask, 0x7ffff); + break; + } + + if (enable) + mem_mapping_enable(&svga->mapping); else - mem_mapping_enable(&svga->mapping); + mem_mapping_disable(&svga->mapping); + } else { + if (val & 0x80) + mem_mapping_disable(&svga->mapping); + else + mem_mapping_enable(&svga->mapping); } break; @@ -138,33 +186,57 @@ oti_in(uint16_t addr, void *p) { oti_t *oti = (oti_t *)p; svga_t *svga = &oti->svga; - uint8_t temp; - - if (!(oti->enable_register & 1) && addr != 0x3C3) - return 0xff; + uint8_t idx, temp; + if (!oti->chip_id && !(oti->enable_register & 1) && (addr != 0x3C3)) + return 0xff; + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { - case 0x3C3: - temp = oti->enable_register; + case 0x3C2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; break; - + + case 0x3C3: + if (oti->chip_id) + temp = svga_in(addr, svga); + else + temp = oti->enable_register; + break; + + case 0x3CF: + return svga->gdcreg[svga->gdcaddr & 0xf]; + case 0x3D4: temp = svga->crtcreg; break; case 0x3D5: - if (svga->crtcreg & 0x20) - temp = 0xff; - else - temp = svga->crtc[svga->crtcreg & 31]; + if (oti->chip_id) { + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg]; + } else + temp = svga->crtc[svga->crtcreg & 0x1f]; break; case 0x3DA: + if (oti->chip_id) { + temp = svga_in(addr, svga); + break; + } + svga->attrff = 0; - 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) @@ -194,17 +266,23 @@ oti_in(uint16_t addr, void *p) svga->cgastat |= 0x20; break; } - return svga->cgastat; + temp = svga->cgastat; + break; - case 0x3DE: - temp = oti->index | (oti->chip_id << 5); + case 0x3DE: + temp = oti->index; + if (oti->chip_id) + temp |= (oti->chip_id << 5); break; - case 0x3DF: - if ((oti->index & 0x1f)==0x10) - temp = 0x18; - else - temp = oti->regs[oti->index & 0x1f]; + case 0x3DF: + idx = oti->index; + if (!oti->chip_id) + idx &= 0x1f; + if (idx == 0x10) + temp = oti->dipswitch_val; + else + temp = oti->regs[idx]; break; default: @@ -221,7 +299,7 @@ oti_pos_out(uint16_t addr, uint8_t val, void *p) { oti_t *oti = (oti_t *)p; - if ((val & 8) != (oti->pos & 8)) { + if ((val ^ oti->pos) & 8) { if (val & 8) io_sethandler(0x03c0, 32, oti_in, NULL, NULL, oti_out, NULL, NULL, oti); @@ -252,7 +330,7 @@ oti_recalctimings(svga_t *svga) if (oti->regs[0x0d] & 0x0c) svga->rowoffset <<= 1; - svga->interlace = oti->regs[0x14] & 0x80; + svga->interlace = oti->regs[0x14] & 0x80; } @@ -265,34 +343,50 @@ oti_init(const device_t *info) memset(oti, 0x00, sizeof(oti_t)); oti->chip_id = info->local; + oti->dipswitch_val = 0x18; + switch(oti->chip_id) { - case 0: - romfn = BIOS_37C_PATH; + case OTI_037C: + romfn = BIOS_037C_PATH; + oti->vram_size = 256; + oti->regs[0] = 0x08; /* FIXME: The BIOS wants to read this at index 0? This index is undocumented. */ + /* io_sethandler(0x03c0, 32, + oti_in, NULL, NULL, oti_out, NULL, NULL, oti); */ break; - - case 2: - case 5: - romfn = BIOS_77_PATH; + + case OTI_067_AMA932J: + romfn = BIOS_067_AMA932J_PATH; + oti->chip_id = 2; + oti->vram_size = device_get_config_int("memory"); + oti->dipswitch_val |= 0x20; + oti->pos = 0x08; /* Tell the BIOS the I/O ports are already enabled to avoid a double I/O handler mess. */ + io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti); + break; + + case OTI_067: + case OTI_077: + romfn = BIOS_077_PATH; + oti->vram_size = device_get_config_int("memory"); + oti->pos = 0x08; /* Tell the BIOS the I/O ports are already enabled to avoid a double I/O handler mess. */ + io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti); break; } rom_init(&oti->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - oti->vram_size = device_get_config_int("memory"); oti->vram_mask = (oti->vram_size << 10) - 1; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_oti); + svga_init(&oti->svga, oti, oti->vram_size << 10, oti_recalctimings, oti_in, oti_out, NULL, NULL); io_sethandler(0x03c0, 32, oti_in, NULL, NULL, oti_out, NULL, NULL, oti); - io_sethandler(0x46e8, 1, oti_pos_in,NULL,NULL, oti_pos_out,NULL,NULL, oti); - - oti->svga.miscout = 1; - oti->regs[0] = 0x08; /* fixme: bios wants to read this at index 0? this index is undocumented */ - + oti->svga.miscout = 1; + return(oti); } @@ -329,14 +423,19 @@ oti_force_redraw(void *p) static int oti037c_available(void) { - return(rom_present(BIOS_37C_PATH)); + return(rom_present(BIOS_037C_PATH)); } +static int +oti067_ama932j_available(void) +{ + return(rom_present(BIOS_067_AMA932J_PATH)); +} static int oti067_077_available(void) { - return(rom_present(BIOS_77_PATH)); + return(rom_present(BIOS_077_PATH)); } @@ -362,6 +461,28 @@ static const device_config_t oti067_config[] = }; +static const device_config_t oti067_ama932j_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 256, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + static const device_config_t oti077_config[] = { { @@ -394,8 +515,7 @@ const device_t oti037c_device = oti_init, oti_close, NULL, oti037c_available, oti_speed_changed, - oti_force_redraw, - oti067_config + oti_force_redraw }; const device_t oti067_device = @@ -410,6 +530,18 @@ const device_t oti067_device = oti067_config }; +const device_t oti067_ama932j_device = +{ + "Oak OTI-067 (AMA-932J)", + DEVICE_ISA, + 3, + oti_init, oti_close, NULL, + oti067_ama932j_available, + oti_speed_changed, + oti_force_redraw, + oti067_ama932j_config +}; + const device_t oti077_device = { "Oak OTI-077", diff --git a/src/video/vid_oak_oti.h b/src/video/vid_oak_oti.h index 6a4d3cb1f..e59d6bcc7 100644 --- a/src/video/vid_oak_oti.h +++ b/src/video/vid_oak_oti.h @@ -4,4 +4,5 @@ extern const device_t oti037c_device; extern const device_t oti067_device; extern const device_t oti067_acer386_device; +extern const device_t oti067_ama932j_device; extern const device_t oti077_device; diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index 2342c353a..5333980de 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -10,13 +10,13 @@ * PC2086, PC3086 use PVGA1A * MegaPC uses W90C11A * - * Version: @(#)vid_paradise.c 1.0.7 2018/04/26 + * Version: @(#)vid_paradise.c 1.0.9 2019/03/23 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -25,6 +25,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -50,6 +51,9 @@ typedef struct paradise_t uint32_t read_bank[4], write_bank[4]; } paradise_t; +static video_timings_t timing_paradise_pvga1a = {VIDEO_ISA, 6, 8, 16, 6, 8, 16}; +static video_timings_t timing_paradise_wd90c = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; + void paradise_remap(paradise_t *paradise); @@ -280,7 +284,7 @@ static uint16_t paradise_readw(uint32_t addr, void *p) return svga_readw_linear(addr, ¶dise->svga); } -void *paradise_pvga1a_init(const device_t *info, uint32_t memsize) +void *paradise_init(const device_t *info, uint32_t memsize) { paradise_t *paradise = malloc(sizeof(paradise_t)); svga_t *svga = ¶dise->svga; @@ -288,98 +292,67 @@ void *paradise_pvga1a_init(const device_t *info, uint32_t memsize) io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); - svga_init(¶dise->svga, paradise, memsize, /*256kb*/ - NULL, - paradise_in, paradise_out, - NULL, - NULL); + if (info->local == PVGA1A) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_paradise_pvga1a); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_paradise_wd90c); - 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'; - svga->crtc[0x32] = 'D'; - svga->crtc[0x33] = '9'; - svga->crtc[0x34] = '0'; - svga->crtc[0x35] = 'C'; - - svga->bpp = 8; - svga->miscout = 1; - - paradise->type = PVGA1A; - - return paradise; -} - -void *paradise_wd90c11_init(const device_t *info) -{ - paradise_t *paradise = malloc(sizeof(paradise_t)); - svga_t *svga = ¶dise->svga; - memset(paradise, 0, sizeof(paradise_t)); - - io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); - - svga_init(¶dise->svga, paradise, 1 << 19, /*512kb*/ - paradise_recalctimings, - paradise_in, paradise_out, - NULL, - NULL); + switch(info->local) { + case PVGA1A: + svga_init(¶dise->svga, paradise, memsize, /*256kb*/ + NULL, + paradise_in, paradise_out, + NULL, + NULL); + break; + case WD90C11: + svga_init(¶dise->svga, paradise, 1 << 19, /*512kb*/ + paradise_recalctimings, + paradise_in, paradise_out, + NULL, + NULL); + break; + case WD90C30: + svga_init(¶dise->svga, paradise, memsize, + paradise_recalctimings, + paradise_in, paradise_out, + NULL, + NULL); + break; + } 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'; - svga->crtc[0x32] = 'D'; - svga->crtc[0x33] = '9'; - svga->crtc[0x34] = '0'; - svga->crtc[0x35] = 'C'; - svga->crtc[0x36] = '1'; - svga->crtc[0x37] = '1'; + /* Common to all three types. */ + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + + switch(info->local) { + case WD90C11: + svga->crtc[0x36] = '1'; + svga->crtc[0x37] = '1'; + break; + case WD90C30: + svga->crtc[0x36] = '3'; + svga->crtc[0x37] = '0'; + break; + } svga->bpp = 8; svga->miscout = 1; - paradise->type = WD90C11; - - return paradise; -} - -void *paradise_wd90c30_init(const device_t *info, uint32_t memsize) -{ - paradise_t *paradise = malloc(sizeof(paradise_t)); - svga_t *svga = ¶dise->svga; - memset(paradise, 0, sizeof(paradise_t)); - - io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); - - svga_init(¶dise->svga, paradise, memsize, - paradise_recalctimings, - paradise_in, paradise_out, - 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'; - svga->crtc[0x32] = 'D'; - svga->crtc[0x33] = '9'; - svga->crtc[0x34] = '0'; - svga->crtc[0x35] = 'C'; - svga->crtc[0x36] = '3'; - svga->crtc[0x37] = '0'; - - svga->bpp = 8; - svga->miscout = 1; - - paradise->type = WD90C11; + paradise->type = info->local; return paradise; } static void *paradise_pvga1a_pc2086_init(const device_t *info) { - paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18); + paradise_t *paradise = paradise_init(info, 1 << 18); if (paradise) rom_init(¶dise->bios_rom, L"roms/machines/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); @@ -388,7 +361,7 @@ static void *paradise_pvga1a_pc2086_init(const device_t *info) } static void *paradise_pvga1a_pc3086_init(const device_t *info) { - paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18); + paradise_t *paradise = paradise_init(info, 1 << 18); if (paradise) rom_init(¶dise->bios_rom, L"roms/machines/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); @@ -404,7 +377,7 @@ static void *paradise_pvga1a_standalone_init(const device_t *info) memory = device_get_config_int("memory"); memory <<= 10; - paradise = paradise_pvga1a_init(info, memory); + paradise = paradise_init(info, memory); if (paradise) rom_init(¶dise->bios_rom, L"roms/video/pvga1a/BIOS.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); @@ -419,7 +392,7 @@ static int paradise_pvga1a_standalone_available(void) static void *paradise_wd90c11_megapc_init(const device_t *info) { - paradise_t *paradise = paradise_wd90c11_init(info); + paradise_t *paradise = paradise_init(info, 0); if (paradise) rom_init_interleaved(¶dise->bios_rom, @@ -432,7 +405,7 @@ static void *paradise_wd90c11_megapc_init(const device_t *info) static void *paradise_wd90c11_standalone_init(const device_t *info) { - paradise_t *paradise = paradise_wd90c11_init(info); + paradise_t *paradise = paradise_init(info, 0); if (paradise) rom_init(¶dise->bios_rom, L"roms/video/wd90c11/WD90C11.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); @@ -453,7 +426,7 @@ static void *paradise_wd90c30_standalone_init(const device_t *info) memory = device_get_config_int("memory"); memory <<= 10; - paradise = paradise_wd90c30_init(info, memory); + paradise = paradise_init(info, memory); if (paradise) rom_init(¶dise->bios_rom, L"roms/video/wd90c30/90C30-LR.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); @@ -494,7 +467,7 @@ const device_t paradise_pvga1a_pc2086_device = { "Paradise PVGA1A (Amstrad PC2086)", 0, - 0, + PVGA1A, paradise_pvga1a_pc2086_init, paradise_close, NULL, @@ -507,7 +480,7 @@ const device_t paradise_pvga1a_pc3086_device = { "Paradise PVGA1A (Amstrad PC3086)", 0, - 0, + PVGA1A, paradise_pvga1a_pc3086_init, paradise_close, NULL, @@ -545,7 +518,7 @@ const device_t paradise_pvga1a_device = { "Paradise PVGA1A", DEVICE_ISA, - 0, + PVGA1A, paradise_pvga1a_standalone_init, paradise_close, NULL, @@ -558,7 +531,7 @@ const device_t paradise_wd90c11_megapc_device = { "Paradise WD90C11 (Amstrad MegaPC)", 0, - 0, + WD90C11, paradise_wd90c11_megapc_init, paradise_close, NULL, @@ -571,7 +544,7 @@ const device_t paradise_wd90c11_device = { "Paradise WD90C11-LR", DEVICE_ISA, - 0, + WD90C11, paradise_wd90c11_standalone_init, paradise_close, NULL, @@ -606,7 +579,7 @@ const device_t paradise_wd90c30_device = { "Paradise WD90C30-LR", DEVICE_ISA, - 0, + WD90C30, paradise_wd90c30_standalone_init, paradise_close, NULL, diff --git a/src/video/vid_pgc.c b/src/video/vid_pgc.c new file mode 100644 index 000000000..e8ccbee4b --- /dev/null +++ b/src/video/vid_pgc.c @@ -0,0 +1,2711 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * 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 behavior + * with a separate thread. + * + * **NOTE** This driver is not finished yet: + * + * - cursor will blink at very high speed if used on a machine + * with clock greater than 4.77MHz. We should "scale down" + * this speed, to become relative to a 4.77MHz-based system. + * + * - pgc_plot() should be overloaded by clones if they support + * modes other than WRITE and INVERT, like the IM-1024. + * + * - test it with the Windows 1.x driver? + * + * This is expected to be done shortly. + * + * Version: @(#)vid_pgc.c 1.0.5 2019/11/04 + * + * Authors: Fred N. van Kempen, + * John Elliott, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 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. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../pit.h" +#include "../plat.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_pgc.h" + + +#define PGC_CGA_WIDTH 640 +#define PGC_CGA_HEIGHT 400 + +#define HWORD(u) ((u) >> 16) +#define LWORD(u) ((u) & 0xffff) + +#define WAKE_DELAY (TIMER_USEC * 500) + + +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" +}; + + +/* Initial palettes */ +static const uint32_t init_palette[6][256] = { +#include "vid_pgc_palette.h" +}; + + +static video_timings_t timing_pgc = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + + +#ifdef ENABLE_PGC_LOG +int pgc_do_log = ENABLE_PGC_LOG; + + +static void +pgc_log(const char *fmt, ...) +{ + va_list ap; + + if (pgc_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pgc_log(fmt, ...) +#endif + + +static inline int +is_whitespace(char ch) +{ + return (ch != 0 && strchr(" \r\n\t,;()+-", ch) != NULL); +} + + +/* + * 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. + */ +static int +output_byte(pgc_t *dev, uint8_t val) +{ + /* If output buffer full, wait for it to empty. */ + while (!dev->stopped && dev->mapram[0x302] == (uint8_t)(dev->mapram[0x303] - 1)) { + pgc_log("PGC: output buffer state: %02x %02x Sleeping\n", + dev->mapram[0x302], dev->mapram[0x303]); + dev->waiting_output_fifo = 1; + pgc_sleep(dev); + } + + if (dev->mapram[0x3ff]) { + /* Reset triggered. */ + pgc_reset(dev); + return 0; + } + + dev->mapram[0x100 + dev->mapram[0x302]] = val; + dev->mapram[0x302]++; + + pgc_log("PGC: output %02x: new state: %02x %02x\n", val, + dev->mapram[0x302], dev->mapram[0x303]); + + return 1; +} + + +/* Helper to write an entire string to the output buffer. */ +static int +output_string(pgc_t *dev, const char *s) +{ + while (*s) { + if (! output_byte(dev, *s)) return 0; + s++; + } + + return 1; +} + + +/* As output_byte, for the error buffer. */ +static int +error_byte(pgc_t *dev, uint8_t val) +{ + /* If error buffer full, wait for it to empty. */ + while (!dev->stopped && dev->mapram[0x304] == dev->mapram[0x305] - 1) { + dev->waiting_error_fifo = 1; + pgc_sleep(dev); + } + + if (dev->mapram[0x3ff]) { + /* Reset triggered. */ + pgc_reset(dev); + return 0; + } + + dev->mapram[0x200 + dev->mapram[0x304]] = val; + dev->mapram[0x304]++; + + return 1; +} + + +/* As output_string, for the error buffer. */ +static int +error_string(pgc_t *dev, const char *s) +{ + while (*s) { + if (! error_byte(dev, *s)) return 0; + s++; + } + + return 1; +} + + +/* + * Read 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. + */ +static int +input_byte(pgc_t *dev, uint8_t *result) +{ + /* If input buffer empty, wait for it to fill. */ + while (!dev->stopped && (dev->mapram[0x300] == dev->mapram[0x301])) { + dev->waiting_input_fifo = 1; + pgc_sleep(dev); + } + + if (dev->stopped) + return 0; + + if (dev->mapram[0x3ff]) { + /* Reset triggered. */ + pgc_reset(dev); + return 0; + } + + *result = dev->mapram[dev->mapram[0x301]]; + dev->mapram[0x301]++; + + return 1; +} + + +/* + * Read a byte and interpret as ASCII. + * + * Ignore control characters other than CR, LF or tab. + */ +static int +input_char(pgc_t *dev, char *result) +{ + uint8_t ch; + + while (1) { + if (! dev->inputbyte(dev, &ch)) return 0; + + ch &= 0x7f; + if (ch == '\r' || ch == '\n' || ch == '\t' || ch >= ' ') { + *result = toupper(ch); + return 1; + } + } +} + + +/* + * Read in the next command. + * + * This can be either as hex (1 byte) or ASCII (up to 6 characters). + */ +static int +read_command(pgc_t *dev) +{ + if (dev->stopped) + return 0; + + if (dev->clcur) + return pgc_clist_byte(dev, &dev->hex_command); + + if (dev->ascii_mode) { + char ch; + int count = 0; + + while (count < 7) { + if (dev->stopped) return 0; + + if (! input_char(dev, &ch)) return 0; + + if (is_whitespace(ch)) { + /* Pad to 6 characters */ + while (count < 6) + dev->asc_command[count++] = ' '; + dev->asc_command[6] = 0; + + return 1; + } + dev->asc_command[count++] = toupper(ch); + } + + return 1; + } + + return dev->inputbyte(dev, &dev->hex_command); +} + + +/* Read in the next command and parse it. */ +static int +parse_command(pgc_t *dev, const pgc_cmd_t **pcmd) +{ + const pgc_cmd_t *cmd; + char match[7]; + + *pcmd = NULL; + dev->hex_command = 0; + memset(dev->asc_command, ' ', 6); + dev->asc_command[6] = 0; + + if (! read_command(dev)) { + /* PGC has been reset. */ + return 0; + } + + /* + * Scan the list of valid commands. + * + * dev->commands may be a subclass list (terminated with '*') + * or the core list (terminated with '@') + */ + for (cmd = dev->commands; cmd->ascii[0] != '@'; cmd++) { + /* End of subclass command list, chain to core. */ + if (cmd->ascii[0] == '*') + cmd = dev->master; + + /* If in ASCII mode match on the ASCII command. */ + if (dev->ascii_mode && !dev->clcur) { + sprintf(match, "%-6.6s", cmd->ascii); + if (! strncmp(match, dev->asc_command, 6)) { + *pcmd = cmd; + dev->hex_command = cmd->hex; + break; + } + } else { + /* Otherwise match on the hex command. */ + if (cmd->hex == dev->hex_command) { + sprintf(dev->asc_command, "%-6.6s", cmd->ascii); + *pcmd = cmd; + break; + } + } + } + + 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_t *dev) +{ + const pgc_cmd_t *cmd; + uint8_t param = 0; + pgc_cl_t cl; + + if (! pgc_param_byte(dev, ¶m)) return; + pgc_log("PGC: CLBEG(%i)\n", param); + + memset(&cl, 0x00, sizeof(pgc_cl_t)); + + while (1) { + if (! parse_command(dev, &cmd)) { + /* PGC has been reset. */ + return; + } + if (!cmd) { + pgc_error(dev, PGC_ERROR_OPCODE); + return; + } else if (dev->hex_command == 0x71) { + /* CLEND */ + dev->clist[param] = cl; + return; + } else { + if (! pgc_cl_append(&cl, dev->hex_command)) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return; + } + + if (cmd->parser) { + if (! (*cmd->parser)(dev, &cl, cmd->p)) + return; + } + } + } +} + + +static void +hndl_clend(pgc_t *dev) +{ + /* Should not 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_t *dev) +{ + pgc_cl_t *clprev = dev->clcur; + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + dev->clcur = &dev->clist[param]; + dev->clcur->rdptr = 0; + dev->clcur->repeat = 1; + dev->clcur->chain = clprev; +} + + +/* Execute a command list multiple times. */ +static void +hndl_cloop(pgc_t *dev) +{ + pgc_cl_t *clprev = dev->clcur; + uint8_t param = 0; + int16_t repeat = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + if (! pgc_param_word(dev, &repeat)) return; + + dev->clcur = &dev->clist[param]; + dev->clcur->rdptr = 0; + dev->clcur->repeat = repeat; + dev->clcur->chain = clprev; +} + + +/* Read back a command list. */ +static void +hndl_clread(pgc_t *dev) +{ + uint8_t param = 0; + uint32_t n; + + if (! pgc_param_byte(dev, ¶m)) return; + + for (n = 0; n < dev->clist[param].wrptr; n++) { + if (! pgc_result_byte(dev, dev->clist[param].list[n])) + return; + } +} + + +/* Delete a command list. */ +static void +hndl_cldel(pgc_t *dev) +{ + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + memset(&dev->clist[param], 0, sizeof(pgc_cl_t)); +} + + +/* Clear the screen to a specified color. */ +static void +hndl_clears(pgc_t *dev) +{ + uint8_t param = 0; + uint32_t y; + + if (! pgc_param_byte(dev, ¶m)) return; + + for (y = 0; y < dev->screenh; y++) + memset(dev->vram + y * dev->maxw, param, dev->screenw); +} + + +/* Select drawing color. */ +static void +hndl_color(pgc_t *dev) +{ + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + pgc_log("PGC: COLOR(%i)\n", param); + dev->color = param; +} + + +/* + * Set drawing mode. + * + * 0 => Draw + * 1 => Invert + */ +static void +hndl_linfun(pgc_t *dev) +{ + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + pgc_log("PGC: LINFUN(%i)\n", param); + if (param < 2) + dev->draw_mode = param; + else + pgc_error(dev, PGC_ERROR_RANGE); +} + + +/* Set the line drawing pattern. */ +static void +hndl_linpat(pgc_t *dev) +{ + uint16_t param = 0; + + if (! pgc_param_word(dev, (int16_t *)¶m)) return; + + pgc_log("PGC: LINPAT(0x%04x)\n", param); + dev->line_pattern = param; +} + + +/* Set the polygon fill mode (0=hollow, 1=filled, 2=fast fill). */ +static void +hndl_prmfil(pgc_t *dev) +{ + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + pgc_log("PGC: PRMFIL(%i)\n", param); + if (param < 3) + dev->fill_mode = param; + else + pgc_error(dev, PGC_ERROR_RANGE); +} + + +/* Set the 2D drawing position. */ +static void +hndl_move(pgc_t *dev) +{ + int32_t x = 0, y = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + + pgc_log("PCG: MOVE %x.%04x,%x.%04x\n", + HWORD(x), LWORD(x), HWORD(y), LWORD(y)); + dev->x = x; + dev->y = y; +} + + +/* Set the 3D drawing position. */ +static void +hndl_move3(pgc_t *dev) +{ + int32_t x = 0, y = 0, z = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + if (! pgc_param_coord(dev, &z)) return; + + dev->x = x; + dev->y = y; + dev->z = z; +} + + +/* Relative move (2D). */ +static void +hndl_mover(pgc_t *dev) +{ + int32_t x = 0, y = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + + dev->x += x; + dev->y += y; +} + + +/* Relative move (3D). */ +static void +hndl_mover3(pgc_t *dev) +{ + int32_t x = 0, y = 0, z = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + if (! pgc_param_coord(dev, &z)) return; + + dev->x += x; + dev->y += y; + dev->z += z; +} + + +/* Given raster coordinates, find the matching address in PGC video RAM. */ +uint8_t * +pgc_vram_addr(pgc_t *dev, int16_t x, int16_t y) +{ + int offset; + + /* We work from the bottom left-hand corner. */ + if (y < 0 || (uint32_t)y >= dev->maxh || + x < 0 || (uint32_t)x >= dev->maxw) return NULL; + + offset = (dev->maxh - 1 - y) * (dev->maxw) + x; + pgc_log("PGC: vram_addr(x=%i,y=%i) = %i\n", x, y, offset); + + if (offset < 0 || (uint32_t)offset >= (dev->maxw * dev->maxh)) + return NULL; + + return &dev->vram[offset]; +} + + +/* + * Write a screen pixel. + * X and Y are raster coordinates, ink is the value to write. + */ +void +pgc_write_pixel(pgc_t *dev, uint16_t x, uint16_t y, uint8_t ink) +{ + uint8_t *vram; + + /* Suppress out-of-range writes; clip to viewport. */ + if (x < dev->vp_x1 || x > dev->vp_x2 || x >= dev->maxw || + y < dev->vp_y1 || y > dev->vp_y2 || y >= dev->maxh) { + pgc_log("PGC: write_pixel clipped: (%i,%i) " + "vp_x1=%i vp_y1=%i vp_x2=%i vp_y2=%i " + "ink=0x%02x\n", + x, y, dev->vp_x1, dev->vp_y1, dev->vp_x2, dev->vp_y2, ink); + return; + } + + vram = pgc_vram_addr(dev, x, y); + if (vram) + *vram = ink; +} + + +/* Read a screen pixel (x and y are raster coordinates). */ +uint8_t +pgc_read_pixel(pgc_t *dev, uint16_t x, uint16_t y) +{ + uint8_t *vram; + + /* Suppress out-of-range reads. */ + if (x >= dev->maxw || y >= dev->maxh) + return 0; + + vram = pgc_vram_addr(dev, x, y); + if (vram) + return *vram; + + return 0; +} + + +/* + * Plot a point in the current color and draw mode. Raster coordinates. + * + * FIXME: this should be overloaded by clones if they support + * modes other than WRITE and INVERT, like the IM-1024. + */ +void +pgc_plot(pgc_t *dev, uint16_t x, uint16_t y) +{ + uint8_t *vram; + + /* Only allow plotting within the current viewport. */ + if (x < dev->vp_x1 || x > dev->vp_x2 || x >= dev->maxw || + y < dev->vp_y1 || y > dev->vp_y2 || y >= dev->maxh) { + pgc_log("PGC: plot clipped: (%i,%i) %i <= x <= %i; %i <= y <= %i; " + "mode=%i ink=0x%02x\n", x, y, + dev->vp_x1, dev->vp_x2, dev->vp_y1, dev->vp_y2, + dev->draw_mode, dev->color); + return; + } + + vram = pgc_vram_addr(dev, x, y); + if (! vram) return; + + /* TODO: Does not implement the PGC plane mask (set by MASK). */ + switch (dev->draw_mode) { + default: + case 0: /* WRITE */ + *vram = dev->color; + break; + + case 1: /* INVERT */ + *vram ^= 0xff; + break; + + case 2: /* XOR color */ + //FIXME: see notes + *vram ^= dev->color; + break; + + case 3: /* AND color */ + //FIXME: see notes + *vram &= dev->color; + break; + } +} + + +/* + * Draw a line (using raster coordinates). + * + * Bresenham's Algorithm from: + * + * + * The line pattern mask to use is passed in. Return value is the + * line pattern mask, rotated by the number of points drawn. + */ +uint16_t +pgc_draw_line_r(pgc_t *dev, 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(dev, 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 line (using PGC fixed-point coordinates). */ +uint16_t +pgc_draw_line(pgc_t *dev, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint16_t linemask) +{ + pgc_log("pgc_draw_line: (%i,%i) to (%i,%i)\n", + x0 >> 16, y0 >> 16, x1 >> 16, y1 >> 16); + + /* Convert from PGC fixed-point to device coordinates */ + x0 >>= 16; + y0 >>= 16; + pgc_ito_raster(dev, &x0, &y0); + + x1 >>= 16; + y1 >>= 16; + pgc_ito_raster(dev, &x1, &y1); + + return pgc_draw_line_r(dev, x0, y0, x1, y1, linemask); +} + + +/* + * Draw a horizontal line in the current fill pattern + * (using raster coordinates). + */ +void +pgc_fill_line_r(pgc_t *dev, int32_t x0, int32_t x1, int32_t y0) +{ + int32_t mask = 0x8000 >> (x0 & 0x0f); + int32_t x; + + if (x0 > x1) { + x = x1; + x1 = x0; + x0 = x; + } + + for (x = x0; x <= x1; x++) { + if (dev->fill_pattern[y0 & 0x0F] & mask) + pgc_plot(dev, 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_t *dev, unsigned corners, int32_t *x, int32_t *y) +{ + double *nodex; + double *dx; + double *dy; + unsigned n, nodes, i, j; + double ymin, ymax, ypos; + + pgc_log("PGC: fill_polygon(%i corners)\n", corners); + + if (corners < 2) return; /* Degenerate polygon */ + + nodex = (double *)malloc(corners * sizeof(double)); + dx = (double *)malloc(corners * sizeof(double)); + dy = (double *)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); + + /* And fill between them. */ + for (i = 0; i < nodes; i += 2) { + int16_t x1 = (int16_t)nodex[i], x2 = (int16_t)nodex[i + 1], + y1 = (int16_t)ypos, y2 = (int16_t)ypos; + pgc_sto_raster(dev, &x1, &y1); + pgc_sto_raster(dev, &x2, &y2); + pgc_fill_line_r(dev, x1, x2, y1); + } + } + + free(nodex); + free(dx); + free(dy); +} + + +/* Draw a filled ellipse (using PGC fixed-point coordinates). */ +void +pgc_draw_ellipse(pgc_t *dev, 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 = dev->y / 65536.0; + double x0 = dev->x / 65536.0; + double ypos, xpos; + double x1; + double xlast = 0.0; + int16_t linemask = dev->line_pattern; + + pgc_log("PGC: ellipse(color=%i drawmode=%i fill=%i)\n", + dev->color, dev->draw_mode, dev->fill_mode); + + pgc_dto_raster(dev, &x0, &y0); + + for (ypos = 0; ypos <= h; ypos++) { + if (ypos == 0) { + if (dev->fill_mode) + pgc_fill_line_r(dev, (uint16_t)(x0 - w), + (uint16_t)(x0 + w), (uint16_t)y0); + if (linemask & 0x8000) { + pgc_plot(dev, (uint16_t)(x0 + w), (uint16_t)y0); + pgc_plot(dev, (uint16_t)(x0 - w), (uint16_t)y0); + linemask = (linemask << 1) | 1; + } else + linemask = linemask << 1; + + xlast = w; + } else { + x1 = sqrt((h * h) - (ypos * ypos)) * w / h; + + if (dev->fill_mode) { + pgc_fill_line_r(dev, (uint16_t)(x0 - x1), + (uint16_t)(x0 + x1), + (uint16_t)(y0 + ypos)); + pgc_fill_line_r(dev, (uint16_t)(x0 - x1), + (uint16_t)(x0 + x1), + (uint16_t)(y0 - ypos)); + } + + /* Draw border. */ + for (xpos = xlast; xpos >= x1; xpos--) { + if (linemask & 0x8000) { + pgc_plot(dev, (uint16_t)(x0 + xpos), + (uint16_t)(y0 + ypos)); + pgc_plot(dev, (uint16_t)(x0 - xpos), + (uint16_t)(y0 + ypos)); + pgc_plot(dev, (uint16_t)(x0 + xpos), + (uint16_t)(y0 - ypos)); + pgc_plot(dev, (uint16_t)(x0 - xpos), + (uint16_t)(y0 - ypos)); + linemask = (linemask << 1) | 1; + } else + linemask = linemask << 1; + } + + xlast = x1; + } + } +} + + +/* Handle the ELIPSE (sic) command. */ +static void +hndl_ellipse(pgc_t *dev) +{ + int32_t x = 0, y = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + + pgc_draw_ellipse(dev, x, y); +} + + +/* Handle the POLY command. */ +static void +hndl_poly(pgc_t *dev) +{ + uint8_t count; + int32_t x[256]; + int32_t y[256]; + int32_t n; + + if (! pgc_param_byte(dev, &count)) return; + + pgc_log("PGC: POLY (%i)\n", count); + for (n = 0; n < count; n++) { + if (! pgc_param_coord(dev, &x[n])) return; + if (! pgc_param_coord(dev, &y[n])) return; + } +} + + +/* Parse but don't execute a POLY command (for adding to a command list) */ +static int +parse_poly(pgc_t *dev, pgc_cl_t *cl, int c) +{ + uint8_t count; + +#ifdef ENABLE_PGC_LOG + pgc_log("PCG: parse_poly\n"); +#endif + if (! pgc_param_byte(dev, &count)) return 0; + pgc_log("PCG: parse_poly: count=%02x\n", count); + + if (! pgc_cl_append(cl, count)) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return 0; + } + pgc_log("PCG: parse_poly: parse %i coords\n", 2 * count); + + return pgc_parse_coords(dev, cl, 2 * count); +} + + +/* Handle the DISPLAY command. */ +static void +hndl_display(pgc_t *dev) +{ + uint8_t param; + + if (! pgc_param_byte(dev, ¶m)) return; + + pgc_log("PGC: DISPLAY(%i)\n", param); + + if (param > 1) + pgc_error(dev, PGC_ERROR_RANGE); + else + pgc_setdisplay(dev, param); +} + + +/* Handle the IMAGEW command (memory to screen blit). */ +static void +hndl_imagew(pgc_t *dev) +{ + int16_t row, col1, col2; + uint8_t v1, v2; + + if (! pgc_param_word(dev, &row)) return; + if (! pgc_param_word(dev, &col1)) return; + if (! pgc_param_word(dev, &col2)) return; + + if ((uint32_t)row >= dev->screenh || + (uint32_t)col1 >= dev->maxw || (uint32_t)col2 >= dev->maxw) { + pgc_error(dev, PGC_ERROR_RANGE); + return; + } + + /* In ASCII mode, what is written is a stream of bytes. */ + if (dev->ascii_mode) { + while (col1 <= col2) { + if (! pgc_param_byte(dev, &v1)) return; + pgc_write_pixel(dev, col1, row, v1); + col1++; + } + + return; + } + + /* In hex mode, it's RLE compressed. */ + while (col1 <= col2) { + if (! pgc_param_byte(dev, &v1)) return; + + if (v1 & 0x80) { + /* Literal run. */ + v1 -= 0x7f; + while (col1 <= col2 && v1 != 0) { + if (! pgc_param_byte(dev, &v2)) return; + pgc_write_pixel(dev, col1, row, v2); + col1++; + v1--; + } + } else { + /* Repeated run. */ + if (! pgc_param_byte(dev, &v2)) return; + + v1++; + while (col1 <= col2 && v1 != 0) { + pgc_write_pixel(dev, col1, row, v2); + col1++; + v1--; + } + } + } +} + + +/* Select one of the built-in palettes. */ +static void +init_lut(pgc_t *dev, int param) +{ + if (param >= 0 && param < 6) + memcpy(dev->palette, init_palette[param], sizeof(dev->palette)); + else if (param == 0xff) + memcpy(dev->palette, dev->userpal, sizeof(dev->palette)); + else + pgc_error(dev, PGC_ERROR_RANGE); +} + + +/* Save the current palette. */ +static void +hndl_lutsav(pgc_t *dev) +{ + memcpy(dev->userpal, dev->palette, sizeof(dev->palette)); +} + + +/* Handle LUTINT (select palette). */ +static void +hndl_lutint(pgc_t *dev) +{ + uint8_t param; + + if (! pgc_param_byte(dev, ¶m)) return; + + init_lut(dev, param); +} + + +/* Handle LUTRD (read palette register). */ +static void +hndl_lutrd(pgc_t *dev) +{ + uint8_t param; + uint32_t col; + + if (! pgc_param_byte(dev, ¶m)) return; + + col = dev->palette[param]; + + pgc_result_byte(dev, (col >> 20) & 0x0f); + pgc_result_byte(dev, (col >> 12) & 0x0f); + pgc_result_byte(dev, (col >> 4) & 0x0f); +} + + +/* Handle LUT (write palette register). */ +static void +hndl_lut(pgc_t *dev) +{ + uint8_t param[4]; + int n; + + for (n = 0; n < 4; n++) { + if (! pgc_param_byte(dev, ¶m[n])) return; + if (n > 0 && param[n] > 15) { + pgc_error(dev, PGC_ERROR_RANGE); + param[n] &= 0x0f; + } + } + + dev->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_t *dev) +{ + uint8_t param; + uint32_t col; + + if (! pgc_param_byte(dev, ¶m)) return; + + col = dev->palette[param]; + + pgc_result_byte(dev, (col >> 16) & 0xff); + pgc_result_byte(dev, (col >> 8) & 0xff); + pgc_result_byte(dev, col & 0xff); +} + + +void +pgc_hndl_lut8(pgc_t *dev) +{ + uint8_t param[4]; + int n; + + for (n = 0; n < 4; n++) + if (! pgc_param_byte(dev, ¶m[n])) return; + + dev->palette[param[0]] = makecol((param[1]), (param[2]), (param[3])); +} + + +/* Handle AREAPT (set 16x16 fill pattern). */ +static void +hndl_areapt(pgc_t *dev) +{ + int16_t pat[16]; + int n; + + for (n = 0; n < 16; n++) + if (! pgc_param_word(dev, &pat[n])) return; + + pgc_log("PGC: AREAPT(%04x %04x %04x %04x...)\n", + pat[0] & 0xffff, pat[1] & 0xffff, pat[2] & 0xffff, pat[3] & 0xffff); + + memcpy(dev->fill_pattern, pat, sizeof(dev->fill_pattern)); +} + + +/* Handle CA (select ASCII mode). */ +static void +hndl_ca(pgc_t *dev) +{ + dev->ascii_mode = 1; +} + + +/* Handle CX (select hex mode). */ +static void +hndl_cx(pgc_t *dev) +{ + dev->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_t *dev) +{ + uint8_t param; + + if (! dev->inputbyte(dev, ¶m)) return; + + if (param == 'A') + dev->ascii_mode = 1; + + if (param == 'X') + dev->ascii_mode = 0; +} + + +/* RESETF resets the PGC. */ +static void +hndl_resetf(pgc_t *dev) +{ + pgc_reset(dev); +} + + +/* TJUST sets text justify settings. */ +static void +hndl_tjust(pgc_t *dev) +{ + uint8_t param[2]; + + if (! dev->inputbyte(dev, ¶m[0])) return; + if (! dev->inputbyte(dev, ¶m[1])) return; + + if (param[0] >= 1 && param[0] <= 3 && param[1] >= 1 && param[1] <= 3) { + dev->tjust_h = param[0]; + dev->tjust_v = param[1]; + } else + pgc_error(dev, PGC_ERROR_RANGE); +} + + +/* TSIZE controls text horizontal spacing. */ +static void +hndl_tsize(pgc_t *pgc) +{ + int32_t param = 0; + + if (! pgc_param_coord(pgc, ¶m)) return; + + pgc_log("PGC: TSIZE %i\n", param); + pgc->tsize = 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_t *dev) +{ + int16_t x1, x2, y1, y2; + + if (! pgc_param_word(dev, &x1)) return; + if (! pgc_param_word(dev, &x2)) return; + if (! pgc_param_word(dev, &y1)) return; + if (! pgc_param_word(dev, &y2)) return; + + pgc_log("PGC: VWPORT %i,%i,%i,%i\n", x1,x2,y1,y2); + dev->vp_x1 = x1; + dev->vp_x2 = x2; + dev->vp_y1 = y1; + dev->vp_y2 = y2; +} + + +/* WINDOW defines the coordinate system in use. */ +static void +hndl_window(pgc_t *dev) +{ + int16_t x1, x2, y1, y2; + + if (! pgc_param_word(dev, &x1)) return; + if (! pgc_param_word(dev, &x2)) return; + if (! pgc_param_word(dev, &y1)) return; + if (! pgc_param_word(dev, &y2)) return; + + pgc_log("PGC: WINDOW %i,%i,%i,%i\n", x1,x2,y1,y2); + dev->win_x1 = x1; + dev->win_x2 = x2; + dev->win_y1 = y1; + dev->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_cmd_t pgc_commands[] = { + { "AREAPT", 0xe7, hndl_areapt, pgc_parse_words, 16 }, + { "AP", 0xe7, hndl_areapt, pgc_parse_words, 16 }, + { "~~~~~~", 0x43, hndl_c, NULL, 0 }, + { "CA", 0xd2, hndl_ca, NULL, 0 }, + { "CLBEG", 0x70, hndl_clbeg, NULL, 0 }, + { "CB", 0x70, hndl_clbeg, NULL, 0 }, + { "CLDEL", 0x74, hndl_cldel, pgc_parse_bytes, 1 }, + { "CD", 0x74, hndl_cldel, pgc_parse_bytes, 1 }, + { "CLEND", 0x71, hndl_clend, NULL, 0 }, + { "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, NULL, 0 }, + { "CL", 0x73, hndl_cloop, NULL, 0 }, + { "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, NULL, 0 }, + { "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, NULL, 0 }, + { "IW", 0xd9, hndl_imagew, NULL, 0 }, + { "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, 0 }, + { "P", 0x30, hndl_poly, parse_poly, 0 }, + { "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, NULL, 0 } +}; + + +/* When the wake timer expires, that's when the drawing thread is actually + * woken */ +static void +wake_timer(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: woke up\n"); +#endif + + thread_set_event(dev->pgc_wake_thread); +} + + +/* + * The PGC drawing thread main loop. + * + * Read in commands and execute them ad infinitum. + */ +static void +pgc_thread(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + const pgc_cmd_t *cmd; + +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: thread begins\n"); +#endif + + for (;;) { + if (! parse_command(dev, &cmd)) { + /* Are we shutting down? */ + if (dev->stopped) { +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: Thread stopping...\n"); +#endif + dev->stopped = 0; + break; + } + + /* Nope, just a reset. */ + continue; + } + + pgc_log("PGC: Command: [%02x] '%s' found = %i\n", + dev->hex_command, dev->asc_command, (cmd != NULL)); + + if (cmd) { + dev->result_count = 0; + (*cmd->handler)(dev); + } else + pgc_error(dev, PGC_ERROR_OPCODE); + } + +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: thread stopped\n"); +#endif +} + + +/* Parameter passed is not a number: abort. */ +static int +err_digit(pgc_t *dev) +{ + uint8_t asc; + + do { + /* Swallow everything until the next separator */ + if (! dev->inputbyte(dev, &asc)) return 0; + } while (! is_whitespace(asc)); + + pgc_error(dev, PGC_ERROR_DIGIT); + + return 0; +} + + +/* Output a byte, either as hex or ASCII depending on the mode. */ +int +pgc_result_byte(pgc_t *dev, uint8_t val) +{ + char buf[20]; + + if (! dev->ascii_mode) + return output_byte(dev, val); + + if (dev->result_count) { + if (! output_byte(dev, ',')) return 0; + } + sprintf(buf, "%i", val); + dev->result_count++; + + return output_string(dev, buf); +} + + +/* Output a word, either as hex or ASCII depending on the mode. */ +int +pgc_result_word(pgc_t *dev, int16_t val) +{ + char buf[20]; + + if (! dev->ascii_mode) { + if (! output_byte(dev, val & 0xFF)) return 0; + return output_byte(dev, val >> 8); + } + + if (dev->result_count) { + if (! output_byte(dev, ',')) return 0; + } + sprintf(buf, "%i", val); + dev->result_count++; + + return output_string(dev, buf); +} + + +/* Report an error, either in ASCII or in hex. */ +int +pgc_error(pgc_t *dev, int err) +{ + if (dev->mapram[0x307]) { + /* Errors enabled? */ + if (dev->ascii_mode) { + if (err >= PGC_ERROR_RANGE && err <= PGC_ERROR_MISSING) + return error_string(dev, pgc_err_msgs[err]); + return error_string(dev, "Unknown error\r"); + } else { + return error_byte(dev, err); + } + } + + return 1; +} + + +/* Initialize RAM and registers to default values. */ +void +pgc_reset(pgc_t *dev) +{ + int n; + + memset(dev->mapram, 0x00, sizeof(dev->mapram)); + + /* The 'CGA disable' jumper is not currently implemented. */ + dev->mapram[0x30b] = dev->cga_enabled = 1; + dev->mapram[0x30c] = dev->cga_enabled; + dev->mapram[0x30d] = dev->cga_enabled; + + dev->mapram[0x3f8] = 0x03; /* minor version */ + dev->mapram[0x3f9] = 0x01; /* minor version */ + dev->mapram[0x3fb] = 0xa5; /* } */ + dev->mapram[0x3fc] = 0x5a; /* PGC self-test passed */ + dev->mapram[0x3fd] = 0x55; /* } */ + dev->mapram[0x3fe] = 0x5a; /* } */ + + dev->ascii_mode = 1; /* start off in ASCII mode */ + dev->line_pattern = 0xffff; + memset(dev->fill_pattern, 0xff, sizeof(dev->fill_pattern)); + dev->color = 0xff; + dev->tjust_h = 1; + dev->tjust_v = 1; + + /* Reset panning. */ + dev->pan_x = 0; + dev->pan_y = 0; + + /* Reset clipping. */ + dev->vp_x1 = 0; + dev->vp_y1 = 0; + dev->vp_x2 = dev->visw - 1; + dev->vp_y2 = dev->vish - 1; + + /* Empty command lists. */ + for (n = 0; n < 256; n++) { + dev->clist[n].wrptr = 0; + dev->clist[n].rdptr = 0; + dev->clist[n].repeat = 0; + dev->clist[n].chain = 0; + } + dev->clcur = NULL; + + /* Select CGA display. */ + dev->cga_selected = -1; + pgc_setdisplay(dev, dev->cga_enabled); + + /* Default palette is 0. */ + init_lut(dev, 0); + hndl_lutsav(dev); +} + + +/* Switch between CGA mode (DISPLAY 1) and native mode (DISPLAY 0). */ +void +pgc_setdisplay(pgc_t *dev, int cga) +{ + pgc_log("PGC: setdisplay(%i): cga_selected=%i cga_enabled=%i\n", + cga, dev->cga_selected, dev->cga_enabled); + + if (dev->cga_selected != (dev->cga_enabled && cga)) { + dev->cga_selected = (dev->cga_enabled && cga); + dev->displine = 0; + + if (dev->cga_selected) { + mem_mapping_enable(&dev->cga_mapping); + dev->screenw = PGC_CGA_WIDTH; + dev->screenh = PGC_CGA_HEIGHT; + } else { + mem_mapping_disable(&dev->cga_mapping); + dev->screenw = dev->visw; + dev->screenh = dev->vish; + } + + pgc_recalctimings(dev); + } +} + + +/* + * 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. + */ +void +pgc_wake(pgc_t *dev) +{ + if (!timer_is_enabled(&dev->wake_timer)) + timer_set_delay_u64(&dev->wake_timer, WAKE_DELAY); +} + + +/* Wait for more input data, or for output to drain. */ +void +pgc_sleep(pgc_t *dev) +{ + uint8_t *n = NULL; + pgc_log("PGC: sleeping on %i %i %i %i 0x%02x 0x%02x\n", + dev->stopped, + dev->waiting_input_fifo, dev->waiting_output_fifo, + dev->waiting_error_fifo, dev->mapram[0x300], dev->mapram[0x301]); + + /* Avoid entering waiting state. */ + if (dev->stopped) { + dev->waiting_input_fifo = 0; + dev->waiting_output_fifo = 0; + *n = 0; + return; + } + + /* Race condition: If host wrote to the PGC during the that + * won't be noticed */ + if (dev->waiting_input_fifo && + dev->mapram[0x300] != dev->mapram[0x301]) { + dev->waiting_input_fifo = 0; + return; + } + + /* Same if they read. */ + if (dev->waiting_output_fifo && + dev->mapram[0x302] != (uint8_t)(dev->mapram[0x303] - 1)) { + dev->waiting_output_fifo = 0; + return; + } + + thread_wait_event(dev->pgc_wake_thread, -1); + thread_reset_event(dev->pgc_wake_thread); +} + + +/* Pull the next byte from the current command list. */ +int +pgc_clist_byte(pgc_t *dev, uint8_t *val) +{ + if (dev->clcur == NULL) return 0; + + if (dev->clcur->rdptr < dev->clcur->wrptr) + *val = dev->clcur->list[dev->clcur->rdptr++]; + else + *val = 0; + + /* If we've reached the end, reset to the beginning and + * (if repeating) run the repeat */ + if (dev->clcur->rdptr >= dev->clcur->wrptr) { + dev->clcur->rdptr = 0; + dev->clcur->repeat--; + if (dev->clcur->repeat == 0) + dev->clcur = dev->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_t *dev, uint8_t *val) +{ + int32_t c; + + if (dev->clcur) + return pgc_clist_byte(dev, val); + + if (! dev->ascii_mode) + return dev->inputbyte(dev, val); + + if (! pgc_param_coord(dev, &c)) return 0; + + c = (c >> 16); /* drop fractional part */ + if (c > 255) { + pgc_error(dev, 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_t *dev, int16_t *val) +{ + uint8_t lo, hi; + int32_t c; + + if (dev->clcur) { + if (! pgc_clist_byte(dev, &lo)) return 0; + if (! pgc_clist_byte(dev, &hi)) return 0; + *val = (((int16_t)hi) << 8) | lo; + + return 1; + } + + if (! dev->ascii_mode) { + if (! dev->inputbyte(dev, &lo)) return 0; + if (! dev->inputbyte(dev, &hi)) return 0; + *val = (((int16_t)hi) << 8) | lo; + + return 1; + } + + if (! pgc_param_coord(dev, &c)) return 0; + + c = (c >> 16); + if (c > 0x7fff || c < -0x7fff) { + pgc_error(dev, PGC_ERROR_RANGE); + return 0; + } + *val = (int16_t)c; + + return 1; +} + + +typedef enum { + 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_t *dev, 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 (dev->clcur) { + for (n = 0; n < 4; n++) + if (! pgc_clist_byte(dev, &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 (! dev->ascii_mode) { + for (n = 0; n < 4; n++) + if (! dev->inputbyte(dev, &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 (! dev->inputbyte(dev, &asc)) return 0; + if (asc == '-') sign = -1; + } while (is_whitespace(asc)); + + /* There had better be a digit next. */ + if (! isdigit(asc)) { + pgc_error(dev, 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 (! dev->inputbyte(dev, &asc)) return 0; + state = PS_FRACTION; + continue; + } else { + pgc_error(dev, PGC_ERROR_MISSING); + return err_digit(dev); + } + break; + + /* Scientific notation. */ + case 'd': + case 'D': + case 'e': + case 'E': + esign = 1; + if (! dev->inputbyte(dev, &asc)) return 0; + if (asc == '-') { + sign = -1; + if (! dev->inputbyte(dev, &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(dev, PGC_ERROR_MISSING); + return err_digit(dev); + } + asc -= '0'; /* asc is digit */ + + switch (state) { + case PS_MAIN: + integer = (integer * 10)+asc; + if (integer & 0x8000) { + /* Overflow */ + pgc_error(dev, 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 (! dev->inputbyte(dev, &asc)) return 0; + } while (! is_whitespace(asc)); + + res = (frac << 16) / dp; + pgc_log("PGC: integer=%u frac=%u exponent=%u dp=%i res=0x%08lx\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; +} + + +/* + * Add a byte to a command list. + * + * We allow command lists to be arbitrarily large. + */ +int +pgc_cl_append(pgc_cl_t *list, uint8_t v) +{ + uint8_t *buf; + + if (list->listmax == 0 || list->list == NULL) { + list->list = (uint8_t *)malloc(4096); + if (!list->list) { +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: out of memory initializing command list\n"); +#endif + return 0; + } + list->listmax = 4096; + } + + while (list->wrptr >= list->listmax) { + buf = (uint8_t *)realloc(list->list, 2 * list->listmax); + if (!buf) { +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: out of memory growing command list\n"); +#endif + return 0; + } + list->list = buf; + list->listmax *= 2; + } + + list->list[list->wrptr++] = v; + + return 1; +} + + +/* Parse but don't execute a command with a fixed number of byte parameters. */ +int +pgc_parse_bytes(pgc_t *dev, pgc_cl_t *cl, int count) +{ + uint8_t *param = (uint8_t *)malloc(count); + int n; + + if (! param) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return 0; + } + + for (n = 0; n < count; n++) { + if (! pgc_param_byte(dev, ¶m[n])) { + free(param); + return 0; + } + + if (! pgc_cl_append(cl, param[n])) { + pgc_error(dev, 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_t *dev, pgc_cl_t *cl, int count) +{ + int16_t *param = (int16_t *)malloc(count * sizeof(int16_t)); + int n; + + if (! param) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return 0; + } + + for (n = 0; n < count; n++) { + if (! pgc_param_word(dev, ¶m[n])) return 0; + + if (!pgc_cl_append(cl, param[n] & 0xff) || + !pgc_cl_append(cl, param[n] >> 8)) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + free(param); + return 0; + } + } + + free(param); + + return 1; +} + + +/* Parse but don't execute a command with a fixed number of coord parameters */ +int +pgc_parse_coords(pgc_t *dev, pgc_cl_t *cl, int count) +{ + int32_t *param = (int32_t *)malloc(count * sizeof(int32_t)); + int n; + + if (! param) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return 0; + } + + for (n = 0; n < count; n++) + if (! pgc_param_coord(dev, ¶m[n])) return 0; + + /* Here is how the real PGC serializes 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++) { + /* Serialize integer part. */ + if (!pgc_cl_append(cl, (param[n] >> 16) & 0xff) || + !pgc_cl_append(cl, (param[n] >> 24) & 0xff) || + + /* Serialize fraction part. */ + !pgc_cl_append(cl, (param[n] ) & 0xff) || + !pgc_cl_append(cl, (param[n] >> 8) & 0xff)) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + free(param); + return 0; + } + } + + free(param); + + return 1; +} + + +/* Convert coordinates based on the current window / viewport to raster + * coordinates. */ +void +pgc_dto_raster(pgc_t *dev, double *x, double *y) +{ +#ifdef ENABLE_PGC_LOG + double x0 = *x, y0 = *y; +#endif + + *x += (dev->vp_x1 - dev->win_x1); + *y += (dev->vp_y1 - dev->win_y1); + + pgc_log("PGC: coords to raster: (%f, %f) -> (%f, %f)\n", x0, y0, *x, *y); +} + + +/* Overloads that take ints. */ +void +pgc_sto_raster(pgc_t *dev, int16_t *x, int16_t *y) +{ + double xd = *x, yd = *y; + + pgc_dto_raster(dev, &xd, &yd); + *x = (int16_t)xd; + *y = (int16_t)yd; +} + + +void +pgc_ito_raster(pgc_t *dev, int32_t *x, int32_t *y) +{ + double xd = *x, yd = *y; + + pgc_dto_raster(dev, &xd, &yd); + *x = (int32_t)xd; + *y = (int32_t)yd; +} + + +void +pgc_recalctimings(pgc_t *dev) +{ + double disptime, _dispontime, _dispofftime; + double pixel_clock = (cpuclock * (double)(1ull << 32)) / (dev->cga_selected ? 25175000.0 : dev->native_pixel_clock); + + /* Use a fixed 640x400 display. */ + disptime = dev->screenw + 11; + _dispontime = dev->screenw * pixel_clock; + _dispofftime = (disptime - dev->screenw) * pixel_clock; + dev->dispontime = (uint64_t)(_dispontime); + dev->dispofftime = (uint64_t)(_dispofftime); +} + + +/* Write to CGA registers are copied into the transfer memory buffer. */ +void +pgc_out(uint16_t addr, uint8_t val, void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + + pgc_log("PGC: out(%04x, %02x)\n", addr, val); + + switch(addr) { + case 0x03d0: /* CRTC Index register */ + case 0x03d2: + case 0x03d4: + case 0x03d6: + dev->mapram[0x03d0] = val; + break; + + case 0x03d1: /* CRTC Data register */ + case 0x03d3: + case 0x03d5: + case 0x03d7: + if (dev->mapram[0x03d0] < 18) + dev->mapram[0x03e0 + dev->mapram[0x03d0]] = val; + break; + + case 0x03d8: /* CRTC Mode Control register */ + dev->mapram[0x03d8] = val; + break; + + case 0x03d9: /* CRTC Color Select register */ + dev->mapram[0x03d9] = val; + break; + } +} + + +/* Read back the CGA registers. */ +uint8_t +pgc_in(uint16_t addr, void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + uint8_t ret = 0xff; + + switch(addr) { + case 0x03d0: /* CRTC Index register */ + case 0x03d2: + case 0x03d4: + case 0x03d6: + ret = dev->mapram[0x03d0]; + break; + + case 0x03d1: /* CRTC Data register */ + case 0x03d3: + case 0x03d5: + case 0x03d7: + if (dev->mapram[0x03d0] < 18) + ret = dev->mapram[0x03e0 + dev->mapram[0x03d0]]; + break; + + case 0x03d8: /* CRTC Mode Control register */ + ret = dev->mapram[0x03d8]; + break; + + case 0x03d9: /* CRTC Color Select register */ + ret = dev->mapram[0x03d9]; + break; + + case 0x03da: /* CRTC Status register */ + ret = dev->mapram[0x03da]; + break; + } + + pgc_log("PGC: in(%04x) = %02x\n", addr, ret); + + return ret; +} + + +/* Memory write to the transfer buffer. */ +/* TODO: Check the CGA mapping repeat stuff. */ +void +pgc_write(uint32_t addr, uint8_t val, void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + + /* + * 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 (dev->mapram[addr] != val) { + dev->mapram[addr] = val; + + switch (addr) { + case 0x300: /* input write pointer */ + if (dev->waiting_input_fifo && + dev->mapram[0x300] != dev->mapram[0x301]) { + dev->waiting_input_fifo = 0; + pgc_wake(dev); + } + break; + + case 0x303: /* output read pointer */ + if (dev->waiting_output_fifo && + dev->mapram[0x302] != (uint8_t)(dev->mapram[0x303] - 1)) { + dev->waiting_output_fifo = 0; + pgc_wake(dev); + } + break; + + case 0x305: /* error read pointer */ + if (dev->waiting_error_fifo && + dev->mapram[0x304] != (uint8_t)(dev->mapram[0x305] - 1)) { + dev->waiting_error_fifo = 0; + pgc_wake(dev); + } + break; + + case 0x306: /* cold start flag */ + /* XXX This should be in IM-1024 specific code */ + dev->mapram[0x306] = 0; + break; + + case 0x30c: /* display type */ + pgc_setdisplay(priv, dev->mapram[0x30c]); + dev->mapram[0x30d] = dev->mapram[0x30c]; + break; + + case 0x3ff: /* reboot the PGC */ + pgc_wake(dev); + break; + } + } + } + + if (addr >= 0xb8000 && addr < 0xc0000 && dev->cga_selected) { + addr &= 0x3fff; + dev->cga_vram[addr] = val; + } +} + + +/* TODO: Check the CGA mapping repeat stuff. */ +uint8_t +pgc_read(uint32_t addr, void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + uint8_t ret = 0xff; + + if (addr >= 0xc6000 && addr < 0xc6800) { + addr &= 0x7ff; + ret = dev->mapram[addr]; + } else if (addr >= 0xb8000 && addr < 0xc0000 && dev->cga_selected) { + addr &= 0x3fff; + ret = dev->cga_vram[addr]; + } + + return ret; +} + + +/* Draw the display in CGA (640x400) text mode. */ +void +pgc_cga_text(pgc_t *dev, int w) +{ + int x, c; + uint8_t chr, attr; + int drawcursor = 0; + uint32_t cols[2]; + int pitch = (dev->mapram[0x3e9] + 1) * 2; + uint16_t sc = (dev->displine & 0x0f) % pitch; + uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; + uint16_t ca = (dev->mapram[0x3ef] | (dev->mapram[0x3ee] << 8)) & 0x3fff; + uint8_t *addr; + uint32_t val; + int cw = (w == 80) ? 8 : 16; + + addr = &dev->cga_vram[((ma + ((dev->displine / pitch) * w)) * 2) & 0x3ffe]; + ma += (dev->displine / pitch) * w; + + for (x = 0; x < w; x++) { + chr = *addr++; + attr = *addr++; + + /* Cursor enabled? */ + if (ma == ca && (dev->cgablink & 8) && + (dev->mapram[0x3ea] & 0x60) != 0x20) { + drawcursor = ((dev->mapram[0x3ea] & 0x1f) <= (sc >> 1)) && + ((dev->mapram[0x3eb] & 0x1f) >= (sc >> 1)); + } else + drawcursor = 0; + + if (dev->mapram[0x3d8] & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((dev->cgablink & 8) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + + for (c = 0; c < cw; c++) { + if (drawcursor) + val = cols[(fontdatm[chr + dev->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; + else + val = cols[(fontdatm[chr + dev->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[dev->displine][(x * cw) + c] = val; + } + + ma++; + } +} + + +/* Draw the display in CGA (320x200) graphics mode. */ +void +pgc_cga_gfx40(pgc_t *dev) +{ + int x, c; + uint32_t cols[4]; + int col; + uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; + uint8_t *addr; + uint16_t dat; + + cols[0] = (dev->mapram[0x3d9] & 15) + 16; + col = ((dev->mapram[0x3d9] & 16) ? 8 : 0) + 16; + + /* From John Elliott's site: + On a real CGA, if bit 2 of port 03D8h and bit 5 of port 03D9h are both set, + the palette used in graphics modes is red/cyan/white. On a PGC, it's + magenta/cyan/white. You still get red/cyan/white if bit 5 of port 03D9h is + not set. This is a firmware issue rather than hardware. */ + if (dev->mapram[0x3d9] & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else if (dev->mapram[0x3d8] & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + + for (x = 0; x < 40; x++) { + addr = &dev->cga_vram[(ma + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; + dat = (addr[0] << 8) | addr[1]; + dev->ma++; + for (c = 0; c < 8; c++) { + buffer32->line[dev->displine][(x << 4) + (c << 1)] = + buffer32->line[dev->displine][(x << 4) + (c << 1) + 1] = cols[dat >> 14]; + dat <<= 2; + } + } +} + + +/* Draw the display in CGA (640x200) graphics mode. */ +void +pgc_cga_gfx80(pgc_t *dev) +{ + int x, c; + uint32_t cols[2]; + uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; + uint8_t *addr; + uint16_t dat; + + cols[0] = 16; + cols[1] = (dev->mapram[0x3d9] & 15) + 16; + + for (x = 0; x < 40; x++) { + addr = &dev->cga_vram[(ma + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; + dat = (addr[0] << 8) | addr[1]; + dev->ma++; + for (c = 0; c < 16; c++) { + buffer32->line[dev->displine][(x << 4) + c] = cols[dat >> 15]; + dat <<= 1; + } + } +} + + +/* Draw the screen in CGA mode. */ +void +pgc_cga_poll(pgc_t *dev) +{ + uint32_t cols[2]; + + if (! dev->linepos) { + timer_advance_u64(&dev->timer, dev->dispofftime); + dev->mapram[0x03da] |= 1; + dev->linepos = 1; + + if (dev->cgadispon) { + if (dev->displine == 0) + video_wait_for_buffer(); + + if ((dev->mapram[0x03d8] & 0x12) == 0x12) + pgc_cga_gfx80(dev); + else if (dev->mapram[0x03d8] & 0x02) + pgc_cga_gfx40(dev); + else if (dev->mapram[0x03d8] & 0x01) + pgc_cga_text(dev, 80); + else + pgc_cga_text(dev, 40); + } else { + cols[0] = ((dev->mapram[0x03d8] & 0x12) == 0x12) ? 0 : ((dev->mapram[0x03d9] & 15) + 16); + hline(buffer32, 0, dev->displine, PGC_CGA_WIDTH, cols[0]); + } + + if (++dev->displine == PGC_CGA_HEIGHT) { + dev->mapram[0x3da] |= 8; + dev->cgadispon = 0; + } + if (dev->displine == PGC_CGA_HEIGHT + 32) { + dev->mapram[0x3da] &= ~8; + dev->cgadispon = 1; + dev->displine = 0; + } + } else { + if (dev->cgadispon) + dev->mapram[0x3da] &= ~1; + timer_advance_u64(&dev->timer, dev->dispontime); + dev->linepos = 0; + + if (dev->displine == PGC_CGA_HEIGHT) { + if (PGC_CGA_WIDTH != xsize || PGC_CGA_HEIGHT != ysize) { + xsize = PGC_CGA_WIDTH; + ysize = PGC_CGA_HEIGHT; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen_8(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 (dev->mapram[0x3d8] & 0x12) { + case 0x12: + video_bpp = 1; + break; + + case 0x02: + video_bpp = 2; + break; + + default: + video_bpp = 0; + break; + } + dev->cgablink++; + } + } +} + + +/* Draw the screen in CGA or native mode. */ +void +pgc_poll(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + uint32_t x, y; + + if (dev->cga_selected) { + pgc_cga_poll(dev); + return; + } + + /* Not CGA, so must be native mode. */ + if (! dev->linepos) { + timer_advance_u64(&dev->timer, dev->dispofftime); + dev->mapram[0x3da] |= 1; + dev->linepos = 1; + if (dev->cgadispon && (uint32_t)dev->displine < dev->maxh) { + if (dev->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 = dev->displine - 2 * dev->pan_y; + for (x = 0; x < dev->screenw; x++) { + if (x + dev->pan_x < dev->maxw) + buffer32->line[dev->displine][x] = dev->palette[dev->vram[y * dev->maxw + x]]; + else + buffer32->line[dev->displine][x] = dev->palette[0]; + } + } else { + hline(buffer32, 0, dev->displine, dev->screenw, dev->palette[0]); + } + + if (++dev->displine == dev->screenh) { + dev->mapram[0x3da] |= 8; + dev->cgadispon = 0; + } + + if (dev->displine == dev->screenh + 32) { + dev->mapram[0x3da] &= ~8; + dev->cgadispon = 1; + dev->displine = 0; + } + } else { + if (dev->cgadispon) + dev->mapram[0x3da] &= ~1; + timer_advance_u64(&dev->timer, dev->dispontime); + dev->linepos = 0; + + if (dev->displine == dev->screenh) { + if (dev->screenw != xsize || dev->screenh != ysize) { + xsize = dev->screenw; + ysize = dev->screenh; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + frames++; + + video_res_x = dev->screenw; + video_res_y = dev->screenh; + video_bpp = 8; + dev->cgablink++; + } + } +} + + +void +pgc_speed_changed(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + + pgc_recalctimings(dev); +} + + +void +pgc_close(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + + /* + * Close down the worker thread by setting a + * flag, and then simulating a reset so it + * stops reading data. + */ +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: telling thread to stop...\n"); +#endif + dev->stopped = 1; + dev->mapram[0x3ff] = 1; + if (dev->waiting_input_fifo || dev->waiting_output_fifo) { + /* Do an immediate wake-up. */ + wake_timer(priv); + } + + /* Wait for thread to stop. */ +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: waiting for thread to stop...\n"); +#endif + // while (dev->stopped); + thread_wait(dev->pgc_thread, -1); +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: thread stopped, closing up.\n"); +#endif + + if (dev->cga_vram) + free(dev->cga_vram); + if (dev->vram) + free(dev->vram); + + free(dev); +} + + +/* + * Initialization 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_init(pgc_t *dev, int maxw, int maxh, int visw, int vish, + int (*inpbyte)(pgc_t *, uint8_t *), double npc) +{ + int i; + + /* Make it a 16k mapping at C4000 (will be C4000-C7FFF), + because of the emulator's granularity - the original + mapping will conflict with hard disk controller BIOS'es. */ + mem_mapping_add(&dev->mapping, 0xc4000, 16384, + pgc_read,NULL,NULL, pgc_write,NULL,NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_add(&dev->cga_mapping, 0xb8000, 32768, + pgc_read,NULL,NULL, pgc_write,NULL,NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + + io_sethandler(0x03d0, 16, + pgc_in,NULL,NULL, pgc_out,NULL,NULL, dev); + + dev->maxw = maxw; + dev->maxh = maxh; + dev->visw = visw; + dev->vish = vish; + + dev->vram = (uint8_t *)malloc(maxw * maxh); + memset(dev->vram, 0x00, maxw * maxh); + dev->cga_vram = (uint8_t *)malloc(16384); + memset(dev->cga_vram, 0x00, 16384); + + /* Create and initialize command lists. */ + dev->clist = (pgc_cl_t *)malloc(256 * sizeof(pgc_cl_t)); + memset(dev->clist, 0x00, 256 * sizeof(pgc_cl_t)); + for (i = 0; i < 256; i++) { + dev->clist[i].list = NULL; + dev->clist[i].listmax = 0; + dev->clist[i].wrptr = 0; + dev->clist[i].rdptr = 0; + dev->clist[i].repeat = 0; + dev->clist[i].chain = NULL; + } + dev->clcur = NULL; + dev->native_pixel_clock = npc; + + pgc_reset(dev); + + dev->inputbyte = inpbyte; + dev->master = dev->commands = pgc_commands; + dev->pgc_wake_thread = thread_create_event(); + dev->pgc_thread = thread_create(pgc_thread, dev); + + timer_add(&dev->timer, pgc_poll, dev, 1); + + timer_add(&dev->wake_timer, wake_timer, dev, 0); +} + + +static void * +pgc_standalone_init(const device_t *info) +{ + pgc_t *dev; + + dev = (pgc_t *)malloc(sizeof(pgc_t)); + memset(dev, 0x00, sizeof(pgc_t)); + dev->type = info->local; + + /* Framebuffer and screen are both 640x480. */ + pgc_init(dev, 640, 480, 640, 480, input_byte, 25175000.0); + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_pgc); + + return(dev); +} + + +const device_t pgc_device = { + "PGC", + DEVICE_ISA, 0, + pgc_standalone_init, + pgc_close, + NULL, + NULL, + pgc_speed_changed, + NULL, + NULL +}; diff --git a/src/video/vid_pgc.h b/src/video/vid_pgc.h new file mode 100644 index 000000000..82ef899ea --- /dev/null +++ b/src/video/vid_pgc.h @@ -0,0 +1,187 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the PGC driver. + * + * Version: @(#)vid_pgc.h 1.0.2 2019/03/03 + * + * Authors: Fred N. van Kempen, + * John Elliott, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 2019 John Elliott. + */ +#ifndef VID_PGC_H +# define VID_PGC_H + + +#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 + + +struct pgc; + +typedef struct pgc_cl { + uint8_t *list; + uint32_t listmax; + uint32_t wrptr; + uint32_t rdptr; + uint32_t repeat; + struct pgc_cl *chain; +} pgc_cl_t; + +typedef struct pgc_cmd { + char ascii[6]; + uint8_t hex; + void (*handler)(struct pgc *); + int (*parser) (struct pgc *, pgc_cl_t *, int); + int p; +} pgc_cmd_t; + +typedef struct pgc { + int8_t type; /* board type */ + int8_t cga_enabled; + int8_t cga_selected; + volatile int8_t stopped; + + mem_mapping_t mapping; + mem_mapping_t cga_mapping; + + pgc_cl_t *clist, + *clcur; + const pgc_cmd_t *master, + *commands; + + 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 color; + uint8_t tjust_h; /* hor alignment 1=left 2=ctr 3=right*/ + uint8_t tjust_v; /* vert alignment 1=bottom 2=ctr 3=top*/ + int32_t tsize; /* horizontal spacing */ + + int32_t x, y, z; /* drawing position */ + + thread_t *pgc_thread; + event_t *pgc_wake_thread; + pc_timer_t wake_timer; + + int waiting_input_fifo; + int waiting_output_fifo; + int waiting_error_fifo; + 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; + double native_pixel_clock; + + int drawcursor; + + int (*inputbyte)(struct pgc *, uint8_t *result); +} pgc_t; + + +/* I/O functions and worker thread handlers. */ +extern void pgc_out(uint16_t addr, uint8_t val, void *priv); +extern uint8_t pgc_in(uint16_t addr, void *priv); +extern void pgc_write(uint32_t addr, uint8_t val, void *priv); +extern uint8_t pgc_read(uint32_t addr, void *priv); +extern void pgc_recalctimings(pgc_t *); +extern void pgc_poll(void *priv); +extern void pgc_reset(pgc_t *); +extern void pgc_wake(pgc_t *); +extern void pgc_sleep(pgc_t *); +extern void pgc_setdisplay(pgc_t *, int cga); +extern void pgc_speed_changed(void *priv); +extern void pgc_close(void *priv); +extern void pgc_init(pgc_t *, + int maxw, int maxh, int visw, int vish, + int (*inpbyte)(pgc_t *, uint8_t *), double npc); + +/* Misc support functions. */ +extern void pgc_sto_raster(pgc_t *, int16_t *x, int16_t *y); +extern void pgc_ito_raster(pgc_t *, int32_t *x, int32_t *y); +extern void pgc_dto_raster(pgc_t *, double *x, double *y); +//extern int pgc_input_byte(pgc_t *, uint8_t *val); +//extern int pgc_output_byte(pgc_t *, uint8_t val); +extern int pgc_output_string(pgc_t *, const char *val); +//extern int pgc_error_byte(pgc_t *, uint8_t val); +extern int pgc_error_string(pgc_t *, const char *val); +extern int pgc_error(pgc_t *, int err); + +/* Graphics functions. */ +extern uint8_t *pgc_vram_addr(pgc_t *, int16_t x, int16_t y); +extern void pgc_write_pixel(pgc_t *, uint16_t x, uint16_t y, uint8_t ink); +extern uint8_t pgc_read_pixel(pgc_t *, uint16_t x, uint16_t y); +extern void pgc_plot(pgc_t *, uint16_t x, uint16_t y); +extern uint16_t pgc_draw_line_r(pgc_t *, int32_t x1, int32_t y1, + int32_t x2, int32_t y2, uint16_t linemask); +extern void pgc_fill_line_r(pgc_t *, int32_t x0, int32_t x1, int32_t y); +extern uint16_t pgc_draw_line(pgc_t *, int32_t x1, int32_t y1, + int32_t x2, int32_t y2, uint16_t linemask); +extern void pgc_draw_ellipse(pgc_t *, int32_t x, int32_t y); +extern void pgc_fill_polygon(pgc_t *, + unsigned corners, int32_t *x, int32_t *y); + +/* Command and parameter handling functions. */ +extern int pgc_clist_byte(pgc_t *, uint8_t *val); +extern int pgc_cl_append(pgc_cl_t *, uint8_t v); +extern int pgc_parse_bytes(pgc_t *, pgc_cl_t *, int p); +extern int pgc_parse_words(pgc_t *, pgc_cl_t *, int p); +extern int pgc_parse_coords(pgc_t *, pgc_cl_t *, int p); +extern int pgc_param_byte(pgc_t *, uint8_t *val); +extern int pgc_param_word(pgc_t *, int16_t *val); +extern int pgc_param_coord(pgc_t *, int32_t *val); +extern int pgc_result_byte(pgc_t *, uint8_t val); +extern int pgc_result_word(pgc_t *, int16_t val); +extern int pgc_result_coord(pgc_t *, int32_t val); + +/* Special overload functions for non-IBM implementations. */ +extern void pgc_hndl_lut8(pgc_t *); +extern void pgc_hndl_lut8rd(pgc_t *); + + +extern const device_t pgc_device; + + +#endif /*VID_PGC_H*/ diff --git a/src/video/vid_pgc_palette.h b/src/video/vid_pgc_palette.h new file mode 100644 index 000000000..dd89a58dc --- /dev/null +++ b/src/video/vid_pgc_palette.h @@ -0,0 +1,1579 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Palette definitions for the PGC core. + * + * Version: @(#)vid_pgc_palette.h 1.0.1 2019/03/01 + * + * Authors: Fred N. van Kempen, + * John Elliott, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 2019 John Elliott. + */ +#ifndef VID_PGC_PALETTE_H +# define VID_PGC_PALETTE_H + + +/* 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), + }, + + +#endif /*VID_PGC_PALETTE_H*/ diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 164220c96..7915e5544 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -8,13 +8,13 @@ * * S3 emulation. * - * Version: @(#)vid_s3.c 1.0.11 2018/07/16 + * Version: @(#)vid_s3.c 1.0.28 2019/10/31 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -24,6 +24,7 @@ #include "../86box.h" #include "../device.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../pci.h" #include "../rom.h" @@ -33,21 +34,68 @@ #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_sdac_ramdac.h" +#include "vid_att20c49x_ramdac.h" +#include "vid_bt48x_ramdac.h" +#include "vid_av9194.h" +#include "vid_icd2061.h" +#include "../cpu/cpu.h" + +#define ROM_ORCHID_86C911 L"roms/video/s3/BIOS.BIN" +#define ROM_METHEUS_86C928 L"roms/video/s3/928.vbi" +#define ROM_V7MIRAGE_86C801 L"roms/video/s3/v7mirage.vbi" +#define ROM_PHOENIX_86C805 L"roms/video/s3/805.vbi" +#define ROM_PARADISE_BAHAMAS64 L"roms/video/s3/bahamas64.bin" +#define ROM_PHOENIX_VISION864 L"roms/video/s3/86c864p.bin" +#define ROM_DIAMOND_STEALTH64_964 L"roms/video/s3/964_107h.rom" +#define ROM_PHOENIX_TRIO32 L"roms/video/s3/86c732p.bin" +#define ROM_NUMBER9_9FX L"roms/video/s3/s3_764.bin" +#define ROM_PHOENIX_TRIO64 L"roms/video/s3/86c764x1.bin" +#define ROM_DIAMOND_STEALTH64_764 L"roms/video/s3/stealt64.bin" enum { - S3_VISION864, - S3_TRIO32, - S3_TRIO64 + S3_NUMBER9_9FX, + S3_PARADISE_BAHAMAS64, + S3_DIAMOND_STEALTH64_964, + S3_PHOENIX_TRIO32, + S3_PHOENIX_TRIO64, + S3_PHOENIX_TRIO64_ONBOARD, + S3_PHOENIX_VISION864, + S3_DIAMOND_STEALTH64_764, + S3_V7MIRAGE_86C801, + S3_PHOENIX_86C805, + S3_ORCHID_86C911, + S3_METHEUS_86C928 }; enum { - VRAM_4MB = 0, - VRAM_8MB = 3, - VRAM_2MB = 4, - VRAM_1MB = 6, - VRAM_512KB = 7 + S3_86C801, + S3_86C805, + S3_86C928, + S3_86C911, + S3_VISION864, + S3_VISION964, + S3_TRIO32, + S3_TRIO64 +}; + +static video_timings_t timing_s3_86c911 = {VIDEO_ISA, 4, 4, 5, 20, 20, 35}; +static video_timings_t timing_s3_86c801 = {VIDEO_ISA, 4, 4, 5, 20, 20, 35}; +static video_timings_t timing_s3_86c805 = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; +static video_timings_t timing_s3_stealth64 = {VIDEO_BUS, 2, 2, 4, 26, 26, 42}; +static video_timings_t timing_s3_vision864 = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; +static video_timings_t timing_s3_vision964 = {VIDEO_BUS, 2, 2, 4, 20, 20, 35}; +static video_timings_t timing_s3_trio32 = {VIDEO_BUS, 4, 3, 5, 26, 26, 42}; +static video_timings_t timing_s3_trio64 = {VIDEO_BUS, 3, 2, 4, 25, 25, 40}; + +enum +{ + VRAM_4MB = 0, + VRAM_8MB = 3, + VRAM_2MB = 4, + VRAM_1MB = 6, + VRAM_512KB = 7 }; #define FIFO_SIZE 65536 @@ -63,112 +111,111 @@ enum enum { - FIFO_INVALID = (0x00 << 24), - FIFO_WRITE_BYTE = (0x01 << 24), - FIFO_WRITE_WORD = (0x02 << 24), - FIFO_WRITE_DWORD = (0x03 << 24), - FIFO_OUT_BYTE = (0x04 << 24), - FIFO_OUT_WORD = (0x05 << 24), - FIFO_OUT_DWORD = (0x06 << 24) + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24), + FIFO_OUT_BYTE = (0x04 << 24), + FIFO_OUT_WORD = (0x05 << 24), + FIFO_OUT_DWORD = (0x06 << 24) }; typedef struct { - uint32_t addr_type; - uint32_t val; + uint32_t addr_type; + uint32_t val; } fifo_entry_t; typedef struct s3_t { - mem_mapping_t linear_mapping; - mem_mapping_t mmio_mapping; - + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + uint8_t has_bios; - rom_t bios_rom; + rom_t bios_rom; - svga_t svga; - sdac_ramdac_t ramdac; + svga_t svga; - uint8_t bank; - uint8_t ma_ext; - int width; - int bpp; + uint8_t bank; + uint8_t ma_ext; + int width, bpp; - int chip, pci; - - uint8_t id, id_ext, id_ext_pci; - - uint8_t int_line; - - int packed_mmio; + int chip; + int pci, vlb; + + 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 linear_base, linear_size; - - uint8_t pci_regs[256]; - int card; + uint32_t vram_mask; + uint8_t status_9ae8; + uint8_t data_available; + + struct + { + uint16_t subsys_cntl; + uint16_t setup_md; + uint8_t advfunc_cntl; + 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, err_term2; + int16_t maj_axis_pcnt, maj_axis_pcnt2; + uint16_t cmd; + uint16_t short_stroke; + uint32_t bkgd_color; + uint32_t frgd_color; + uint32_t wrt_mask; + uint32_t rd_mask; + uint32_t color_cmp; + uint8_t bkgd_mix; + uint8_t frgd_mix; + uint16_t multifunc_cntl; + uint16_t multifunc[16]; + uint8_t pix_trans[4]; + + int cx, cy; + int sx, sy; + int dx, dy; + uint32_t src, dest, pattern; + int pix_trans_count; - uint32_t vram_mask; - uint8_t status_9ae8; - - float (*getclock)(int clock, void *p); - void *getclock_p; + 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; - struct - { - uint16_t subsys_cntl; - uint16_t setup_md; - uint8_t advfunc_cntl; - 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, err_term2; - int16_t maj_axis_pcnt, maj_axis_pcnt2; - uint16_t cmd; - uint16_t short_stroke; - uint32_t bkgd_color; - uint32_t frgd_color; - uint32_t wrt_mask; - uint32_t rd_mask; - uint32_t color_cmp; - uint8_t bkgd_mix; - uint8_t frgd_mix; - uint16_t multifunc_cntl; - uint16_t multifunc[16]; - uint8_t pix_trans[4]; - - int cx, cy; - int sx, sy; - int dx, dy; - uint32_t src, dest, pattern; - int pix_trans_count; + uint32_t dat_buf; + int dat_count; + } accel; - 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; + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; - uint32_t dat_buf; - int dat_count; - } accel; + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + + uint8_t subsys_cntl, subsys_stat; + + uint32_t hwc_fg_col, hwc_bg_col; + int hwc_col_stack_pos; - fifo_entry_t fifo[FIFO_SIZE]; - volatile int fifo_read_idx, fifo_write_idx; - - thread_t *fifo_thread; - event_t *wake_fifo_thread; - event_t *fifo_not_full_event; - - int blitter_busy; - uint64_t blitter_time; - uint64_t status_time; - - uint8_t subsys_cntl, subsys_stat; - - uint32_t hwc_fg_col, hwc_bg_col; - int hwc_col_stack_pos; + int translate; } s3_t; #define INT_VSY (1 << 0) @@ -183,19 +230,29 @@ void s3_accel_write(uint32_t addr, uint8_t val, void *p); void s3_accel_write_w(uint32_t addr, uint16_t val, void *p); void s3_accel_write_l(uint32_t addr, uint32_t val, void *p); uint8_t s3_accel_read(uint32_t addr, void *p); +uint16_t s3_accel_read_w(uint32_t addr, void *p); +uint32_t s3_accel_read_l(uint32_t addr, void *p); + +void s3_out(uint16_t addr, uint8_t val, void *p); +uint8_t s3_in(uint16_t addr, void *p); + +void s3_accel_out(uint16_t port, uint8_t val, void *p); +void s3_accel_out_w(uint16_t port, uint16_t val, void *p); +void s3_accel_out_l(uint16_t port, uint32_t val, void *p); +uint8_t s3_accel_in(uint16_t port, void *p); static inline void wake_fifo_thread(s3_t *s3) { - thread_set_event(s3->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ + thread_set_event(s3->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ } static void s3_wait_fifo_idle(s3_t *s3) { - while (!FIFO_EMPTY) - { - wake_fifo_thread(s3); - thread_wait_event(s3->fifo_not_full_event, 1); - } + while (!FIFO_EMPTY) + { + wake_fifo_thread(s3); + thread_wait_event(s3->fifo_not_full_event, 1); + } } static void s3_update_irqs(s3_t *s3) @@ -205,3042 +262,3805 @@ static void s3_update_irqs(s3_t *s3) return; } - if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) - pci_set_irq(s3->card, PCI_INTA); - else - pci_clear_irq(s3->card, PCI_INTA); + 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) \ - { \ - 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; \ - } +#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; \ + } + +int s3_cpu_src(s3_t *s3) +{ + if (!(s3->accel.cmd & 0x100)) + return 0; + + if (s3->chip > S3_86C911) + return 1; + + if (s3->accel.cmd & 1) + return 1; + + return 0; +} + +int s3_cpu_dest(s3_t *s3) +{ + if (!(s3->accel.cmd & 0x100)) + return 0; + + if (s3->chip > S3_86C911) + return 0; + + if (s3->accel.cmd & 1) + return 0; + + return 1; +} static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) { - switch (port) - { - case 0x82e8: - s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; - 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.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.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: - s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val; - break; - case 0x92e9: - s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8); - if (val & 0x20) - s3->accel.err_term |= ~0x3fff; - break; - case 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; + switch (port) + { + case 0x8148: case 0x82e8: + s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; + s3->accel.poly_cy = s3->accel.cur_y; + break; + case 0x8149: case 0x82e9: + s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy = s3->accel.cur_y; + break; + case 0x814a: case 0x82ea: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xf00) | val; + s3->accel.poly_cy2 = s3->accel.cur_y2; + break; + case 0x814b: case 0x82eb: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy2 = s3->accel.cur_y2; + break; + + case 0x8548: 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 0x8549: 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 0x854a: case 0x86ea: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xf00) | val; + s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; + break; + case 0x854b: 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 0x8948: case 0x8ae8: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val; + s3->accel.point_1_updated = 1; + break; + case 0x8949: case 0x8ae9: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.desty_axstp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x894a: case 0x8aea: + s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0x3f00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x849b: 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 0x8d48: case 0x8ee8: + s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; + s3->accel.point_1_updated = 1; + break; + case 0x8d49: case 0x8ee9: + s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.destx_distp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x8d4a: case 0x8eea: + s3->accel.x2 = (s3->accel.x2 & 0xf00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x8d4b: case 0x8eeb: + s3->accel.x2 = (s3->accel.x2 & 0xff) | ((val & 0xf) << 8); + s3->accel.point_2_updated = 1; + break; + + case 0x9148: case 0x92e8: + s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val; + break; + case 0x9149: case 0x92e9: + s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.err_term |= ~0x3fff; + break; + case 0x914a: case 0x92ea: + s3->accel.err_term2 = (s3->accel.err_term2 & 0x3f00) | val; + break; + case 0x914b: 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; - break; - case 0x96e9: - s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); - if (val & 0x08) - s3->accel.maj_axis_pcnt |= ~0x0fff; - break; - case 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 0x9548: case 0x96e8: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val; + break; + case 0x9459: case 0x96e9: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3->accel.maj_axis_pcnt |= ~0x0fff; + break; + case 0x954a: case 0x96ea: + s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xf00) | val; + break; + case 0x954b: 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; - break; - case 0x9ae9: - s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); - s3_accel_start(-1, 0, 0xffffffff, 0, s3); - s3->accel.pix_trans_count = 0; - s3->accel.multifunc[0xe] &= ~0x10; /*hack*/ - break; + case 0x9948: case 0x9ae8: + s3->accel.cmd = (s3->accel.cmd & 0xff00) | val; + s3->data_available = 0; + break; + case 0x9949: case 0x9ae9: + s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); + s3_accel_start(-1, 0, 0xffffffff, 0, s3); + s3->accel.pix_trans_count = 0; + s3->accel.multifunc[0xe] &= ~0x10; /*hack*/ + break; - case 0x9ee8: - s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; - break; - case 0x9ee9: - s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); - break; + case 0x9d48: case 0x9ee8: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; + break; + case 0x9d49: case 0x9ee9: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); + break; - case 0xa2e8: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); - else - s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; - break; - case 0xa2e9: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); - else - s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); - if (!(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.multifunc[0xe] ^= 0x10; - break; - case 0xa2ea: - if (s3->accel.multifunc[0xe] & 0x200) - s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); - 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 0xa148: case 0xa2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; + break; + case 0xa149: case 0xa2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa14a: 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 0xa14b: 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: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); - else - s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; - break; - case 0xa6e9: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); - else - s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); - if (!(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.multifunc[0xe] ^= 0x10; - break; - case 0xa6ea: - if (s3->accel.multifunc[0xe] & 0x200) - s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); - 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 0xa548: case 0xa6e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; + break; + case 0xa549: case 0xa6e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa54a: 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 0xa54b: 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: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); - else - s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; - break; - case 0xaae9: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); - else - s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); - if (!(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.multifunc[0xe] ^= 0x10; - break; - case 0xaaea: - if (s3->accel.multifunc[0xe] & 0x200) - s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); - 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 0xa948: case 0xaae8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; + break; + case 0xa949: case 0xaae9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa94a: 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 0xa94b: 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: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); - else - s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; - break; - case 0xaee9: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); - else - s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); - if (!(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.multifunc[0xe] ^= 0x10; - break; - case 0xaeea: - if (s3->accel.multifunc[0xe] & 0x200) - s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); - 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 0xad48: case 0xaee8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; + break; + case 0xad49: case 0xaee9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xad4a: 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 0xad4b: 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: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); - else - s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; - break; - case 0xb2e9: - if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); - else - s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); - if (!(s3->accel.multifunc[0xe] & 0x200)) - s3->accel.multifunc[0xe] ^= 0x10; - break; - case 0xb2ea: - if (s3->accel.multifunc[0xe] & 0x200) - s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); - 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 0xb148: case 0xb2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; + break; + case 0xb149: case 0xb2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xb14a: 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 0xb14b: 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: - s3->accel.bkgd_mix = val; - break; + case 0xb548: case 0xb6e8: + s3->accel.bkgd_mix = val; + break; - case 0xbae8: - s3->accel.frgd_mix = val; - break; - - case 0xbee8: - s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val; - break; - case 0xbee9: - s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8); - s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; - break; + case 0xb948: case 0xbae8: + s3->accel.frgd_mix = val; + break; + + case 0xbd48: case 0xbee8: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val; + break; + case 0xbd49: case 0xbee9: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8); + s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; + break; - case 0xe2e8: - s3->accel.pix_trans[0] = val; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) - s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); - else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); - break; - case 0xe2e9: - s3->accel.pix_trans[1] = val; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) - { - if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); - else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); - } - else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) - { - if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); - else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); - } - break; - case 0xe2ea: - s3->accel.pix_trans[2] = val; - break; - case 0xe2eb: - s3->accel.pix_trans[3] = val; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 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); - break; - } + case 0xe148: case 0xe2e8: + if (s3_cpu_dest(s3)) + break; + s3->accel.pix_trans[0] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + break; + case 0xe149: case 0xe2e9: + if (s3_cpu_dest(s3)) + break; + s3->accel.pix_trans[1] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); + else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + break; + case 0xe14a: case 0xe2ea: + if (s3_cpu_dest(s3)) + break; + s3->accel.pix_trans[2] = val; + break; + case 0xe14b: case 0xe2eb: + if (s3_cpu_dest(s3)) + break; + s3->accel.pix_trans[3] = val; + 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); + break; + } } static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - if (s3->accel.cmd & 0x1000) - 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 - { - 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); - } - } + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + 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 + { + 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); + } + } } static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - 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); - } - else - { - 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); - } - } - else - { - 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 >> 16, s3); - } - else - { - s3_accel_start(1, 1, 0xffffffff, val, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); - } - } - } + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + 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); + } + else + { + 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); + } + } + else + { + 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 >> 16, s3); + } + else + { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + } + } + } } static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) { - if (s3->packed_mmio) - { - int addr_lo = addr & 1; - switch (addr & 0xfffe) - { - case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ - case 0x8102: addr = 0x86e8; break; - - case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/ - case 0x8106: addr = 0x86ea; break; - - case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/ - case 0x810a: addr = 0x8ee8; break; - - case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/ - case 0x810e: addr = 0x8eea; break; + if (s3->packed_mmio) + { + int addr_lo = addr & 1; + switch (addr & 0xfffe) + { + case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ + case 0x8102: addr = 0x86e8; break; + + case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/ + case 0x8106: addr = 0x86ea; break; + + case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/ + case 0x810a: addr = 0x8ee8; break; + + case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/ + case 0x810e: addr = 0x8eea; break; - case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/ - case 0x8112: addr = 0x92ee; break; + case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/ + case 0x8112: addr = 0x92ee; break; - case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/ - case 0x811a: addr = 0x9aea; break; - - case 0x811c: addr = 0x9ee8; break; /*SHORT_STROKE*/ - - case 0x8120: case 0x8122: /*BKGD_COLOR*/ - WRITE8(addr, s3->accel.bkgd_color, val); - return; - - case 0x8124: case 0x8126: /*FRGD_COLOR*/ - WRITE8(addr, s3->accel.frgd_color, val); - return; + case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/ + case 0x811a: addr = 0x9aea; break; + + case 0x811c: addr = 0x9ee8; break; /*SHORT_STROKE*/ + + case 0x8120: case 0x8122: /*BKGD_COLOR*/ + WRITE8(addr, s3->accel.bkgd_color, val); + return; + + case 0x8124: case 0x8126: /*FRGD_COLOR*/ + WRITE8(addr, s3->accel.frgd_color, val); + return; - case 0x8128: case 0x812a: /*WRT_MASK*/ - WRITE8(addr, s3->accel.wrt_mask, val); - return; + case 0x8128: case 0x812a: /*WRT_MASK*/ + WRITE8(addr, s3->accel.wrt_mask, val); + return; - case 0x812c: case 0x812e: /*RD_MASK*/ - WRITE8(addr, s3->accel.rd_mask, val); - return; + case 0x812c: case 0x812e: /*RD_MASK*/ + WRITE8(addr, s3->accel.rd_mask, val); + return; - case 0x8130: case 0x8132: /*COLOR_CMP*/ - WRITE8(addr, s3->accel.color_cmp, val); - return; + case 0x8130: case 0x8132: /*COLOR_CMP*/ + WRITE8(addr, s3->accel.color_cmp, val); + return; - case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/ - case 0x8136: addr = 0xbae8; break; - - case 0x8138: /*SCISSORS_T*/ - WRITE8(addr & 1, s3->accel.multifunc[1], val); - return; - case 0x813a: /*SCISSORS_L*/ - WRITE8(addr & 1, s3->accel.multifunc[2], val); - return; - case 0x813c: /*SCISSORS_B*/ - WRITE8(addr & 1, s3->accel.multifunc[3], val); - return; - case 0x813e: /*SCISSORS_R*/ - WRITE8(addr & 1, s3->accel.multifunc[4], val); - return; + case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/ + case 0x8136: addr = 0xbae8; break; + + case 0x8138: /*SCISSORS_T*/ + WRITE8(addr & 1, s3->accel.multifunc[1], val); + return; + case 0x813a: /*SCISSORS_L*/ + WRITE8(addr & 1, s3->accel.multifunc[2], val); + return; + case 0x813c: /*SCISSORS_B*/ + WRITE8(addr & 1, s3->accel.multifunc[3], val); + return; + case 0x813e: /*SCISSORS_R*/ + WRITE8(addr & 1, s3->accel.multifunc[4], val); + return; - case 0x8140: /*PIX_CNTL*/ - WRITE8(addr & 1, s3->accel.multifunc[0xa], val); - return; - case 0x8142: /*MULT_MISC2*/ - WRITE8(addr & 1, s3->accel.multifunc[0xd], val); - return; - case 0x8144: /*MULT_MISC*/ - WRITE8(addr & 1, s3->accel.multifunc[0xe], val); - return; - case 0x8146: /*READ_SEL*/ - WRITE8(addr & 1, s3->accel.multifunc[0xf], val); - return; + case 0x8140: /*PIX_CNTL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xa], val); + return; + case 0x8142: /*MULT_MISC2*/ + WRITE8(addr & 1, s3->accel.multifunc[0xd], val); + return; + case 0x8144: /*MULT_MISC*/ + WRITE8(addr & 1, s3->accel.multifunc[0xe], val); + return; + case 0x8146: /*READ_SEL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xf], val); + return; - case 0x8148: /*ALT_PCNT*/ - WRITE8(addr & 1, s3->accel.multifunc[0], val); - return; - case 0x814a: addr = 0x96e8; break; - case 0x814c: addr = 0x96ea; break; + case 0x8148: /*ALT_PCNT*/ + WRITE8(addr & 1, s3->accel.multifunc[0], val); + return; + case 0x814a: addr = 0x96e8; break; + case 0x814c: addr = 0x96ea; break; - case 0x8168: addr = 0xeae8; break; - case 0x816a: addr = 0xeaea; break; - } - addr |= addr_lo; - } - + case 0x8168: addr = 0xeae8; break; + case 0x816a: addr = 0xeaea; break; + } + addr |= addr_lo; + } + - if (addr & 0x8000) - { - s3_accel_out_fifo(s3, addr & 0xffff, val); - } - else - { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); - else - s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); - } - } + if (addr & 0x8000) + { + s3_accel_out_fifo(s3, addr & 0xffff, val); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } + } } static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) { - if (addr & 0x8000) - { - s3_accel_write_fifo(s3, addr, val); - s3_accel_write_fifo(s3, addr + 1, val >> 8); - } - else - { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - if (s3->accel.cmd & 0x1000) - val = (val >> 8) | (val << 8); - 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 - { - 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); - } - } - } + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + 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 + { + 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); + } + } + } } static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) { - if (addr & 0x8000) - { - s3_accel_write_fifo(s3, addr, val); - s3_accel_write_fifo(s3, addr + 1, val >> 8); - s3_accel_write_fifo(s3, addr + 2, val >> 16); - s3_accel_write_fifo(s3, addr + 3, val >> 24); - } - else - { - if (s3->accel.cmd & 0x100) - { - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) - { - if ((s3->accel.cmd & 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); - } - else - { - 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); - } - } - else - { - 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 >> 16, s3); - } - else - { - s3_accel_start(1, 1, 0xffffffff, val, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); - } - } - } - } + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + s3_accel_write_fifo(s3, addr + 2, val >> 16); + s3_accel_write_fifo(s3, addr + 3, val >> 24); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if ((s3->accel.cmd & 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); + } + else + { + 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); + } + } + else + { + 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 >> 16, s3); + } + else + { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + } + } + } + } } static void fifo_thread(void *param) { - s3_t *s3 = (s3_t *)param; - - while (1) - { - thread_set_event(s3->fifo_not_full_event); - thread_wait_event(s3->wake_fifo_thread, -1); - thread_reset_event(s3->wake_fifo_thread); - s3->blitter_busy = 1; - while (!FIFO_EMPTY) - { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; - fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK]; + s3_t *s3 = (s3_t *)param; + + while (1) + { + thread_set_event(s3->fifo_not_full_event); + thread_wait_event(s3->wake_fifo_thread, -1); + thread_reset_event(s3->wake_fifo_thread); + s3->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK]; - switch (fifo->addr_type & FIFO_TYPE) - { - case FIFO_WRITE_BYTE: - s3_accel_write_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_WRITE_WORD: - s3_accel_write_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_WRITE_DWORD: - s3_accel_write_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_OUT_BYTE: - s3_accel_out_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_OUT_WORD: - s3_accel_out_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - case FIFO_OUT_DWORD: - s3_accel_out_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); - break; - } - - s3->fifo_read_idx++; - fifo->addr_type = FIFO_INVALID; + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + s3_accel_write_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + s3_accel_write_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + s3_accel_write_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_BYTE: + s3_accel_out_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_WORD: + s3_accel_out_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_DWORD: + s3_accel_out_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + s3->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; - if (FIFO_ENTRIES > 0xe000) - thread_set_event(s3->fifo_not_full_event); + if (FIFO_ENTRIES > 0xe000) + thread_set_event(s3->fifo_not_full_event); - end_time = plat_timer_read(); - s3->blitter_time += end_time - start_time; - } - s3->blitter_busy = 0; - s3->subsys_stat |= INT_FIFO_EMP; - s3_update_irqs(s3); - } + end_time = plat_timer_read(); + 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_t *s3 = (s3_t *)svga->p; - s3->subsys_stat |= INT_VSY; - s3_update_irqs(s3); + 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]; + fifo_entry_t *fifo = &s3->fifo[s3->fifo_write_idx & FIFO_MASK]; - if (FIFO_FULL) - { - thread_reset_event(s3->fifo_not_full_event); - if (FIFO_FULL) - { - thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ - } - } - - fifo->val = val; - fifo->addr_type = (addr & FIFO_ADDR) | type; - - s3->fifo_write_idx++; - - if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) - wake_fifo_thread(s3); -} - -void s3_out(uint16_t addr, uint8_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - svga_t *svga = &s3->svga; - uint8_t old; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - switch (addr) - { - case 0x3c5: - if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) - { - svga->seqregs[svga->seqaddr] = val; - switch (svga->seqaddr) - { - case 0x12: case 0x13: - svga_recalctimings(svga); - return; - } - } - if (svga->seqaddr == 4) /*Chain-4 - update banking*/ - { - if (val & 8) - svga->write_bank = svga->read_bank = s3->bank << 16; - else - svga->write_bank = svga->read_bank = s3->bank << 14; - } - break; - - case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - 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: - svga->crtcreg = val & 0x7f; - 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 >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) return; - old = svga->crtc[svga->crtcreg]; - svga->crtc[svga->crtcreg] = val; - switch (svga->crtcreg) - { - case 0x31: - s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4); - break; - case 0x32: - svga->vram_display_mask = (val & 0x40) ? 0x3ffff : s3->vram_mask; - break; - - case 0x50: - switch (svga->crtc[0x50] & 0xc1) - { - case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; - case 0x01: s3->width = 1152; break; - case 0x40: s3->width = 640; break; - case 0x80: s3->width = 800; break; - case 0x81: s3->width = 1600; break; - case 0xc0: s3->width = 1280; break; - } - s3->bpp = (svga->crtc[0x50] >> 4) & 3; - break; - case 0x69: - s3->ma_ext = val & 0x1f; - break; - - case 0x35: - s3->bank = (s3->bank & 0x70) | (val & 0xf); - if (svga->chain4) - svga->write_bank = svga->read_bank = s3->bank << 16; - else - svga->write_bank = svga->read_bank = s3->bank << 14; - break; - case 0x51: - s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); - if (svga->chain4) - svga->write_bank = svga->read_bank = s3->bank << 16; - else - svga->write_bank = svga->read_bank = s3->bank << 14; - s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); - break; - case 0x6a: - s3->bank = val; - if (svga->chain4) - svga->write_bank = svga->read_bank = s3->bank << 16; - else - svga->write_bank = svga->read_bank = s3->bank << 14; - break; - - case 0x3a: - if (val & 0x10) - svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ - break; - - case 0x45: - svga->hwcursor.ena = val & 1; - break; - case 0x48: - svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; - if (svga->bpp == 32) svga->hwcursor.x >>= 1; - svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; - svga->hwcursor.xoff = svga->crtc[0x4e] & 63; - svga->hwcursor.yoff = svga->crtc[0x4f] & 63; - svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); - if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) - svga->hwcursor.x <<= 1; - break; - - case 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: - s3_updatemapping(s3); - break; - - case 0x67: - if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) - { - switch (val >> 4) - { - case 3: svga->bpp = 15; break; - case 5: svga->bpp = 16; break; - case 7: svga->bpp = 24; break; - case 13: svga->bpp = 32; break; - default: svga->bpp = 8; break; - } - } - break; - } - if (old != val) - { - if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) - { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } - break; - } - svga_out(addr, val, svga); -} - -uint8_t s3_in(uint16_t addr, void *p) -{ - s3_t *s3 = (s3_t *)p; - svga_t *svga = &s3->svga; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) - addr ^= 0x60; - - switch (addr) - { - case 0x3c1: - if (svga->attraddr > 0x14) - return 0xff; - break; - - case 0x3c5: - if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) - return svga->seqregs[svga->seqaddr]; - break; - - case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: - 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; - case 0x3d5: - switch (svga->crtcreg) - { - case 0x2d: return 0x88; /*Extended chip ID*/ - case 0x2e: return s3->id_ext; /*New chip ID*/ - case 0x2f: return 0; /*Revision level*/ - case 0x30: return s3->id; /*Chip ID*/ - case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); - case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); - case 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; - } - return svga->crtc[svga->crtcreg]; - } - return svga_in(addr, svga); -} - -void s3_recalctimings(svga_t *svga) -{ - s3_t *s3 = (s3_t *)svga->p; - svga->hdisp = svga->hdisp_old; - - svga->ma_latch |= (s3->ma_ext << 16); - if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; - if (svga->crtc[0x5d] & 0x02) - { - svga->hdisp_time += 0x100; - svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); - } - if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; - if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; - if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; - if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; - if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; - if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; - else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; - if (!svga->rowoffset) svga->rowoffset = 256; - svga->interlace = svga->crtc[0x42] & 0x20; - svga->clock = cpuclock / s3->getclock((svga->miscout >> 2) & 3, s3->getclock_p); - - switch (svga->crtc[0x67] >> 4) - { - case 3: case 5: case 7: - svga->clock /= 2; - break; - } - - svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); - if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) - { - switch (svga->bpp) - { - case 8: - svga->render = svga_render_8bpp_highres; - break; - case 15: - svga->render = svga_render_15bpp_highres; - svga->hdisp /= 2; - break; - case 16: - svga->render = svga_render_16bpp_highres; - svga->hdisp /= 2; - break; - case 24: - svga->render = svga_render_24bpp_highres; - svga->hdisp /= 3; - break; - case 32: - svga->render = svga_render_32bpp_highres; - if (s3->chip != S3_TRIO32 && s3->chip != S3_TRIO64) - svga->hdisp /= 4; - break; - } - } -} - -void s3_updatemapping(s3_t *s3) -{ - svga_t *svga = &s3->svga; - - if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) - { - mem_mapping_disable(&svga->mapping); - mem_mapping_disable(&s3->linear_mapping); - mem_mapping_disable(&s3->mmio_mapping); - return; - } - - /*Banked framebuffer*/ - if (svga->crtc[0x31] & 0x08) /*Enhanced mode mappings*/ - { - /* Enhanced mode 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); - 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; - } - - if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ - { - mem_mapping_disable(&svga->mapping); - - s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); - switch (svga->crtc[0x58] & 3) - { - case 0: /*64k*/ - s3->linear_size = 0x10000; - break; - case 1: /*1mb*/ - s3->linear_size = 0x100000; - break; - case 2: /*2mb*/ - s3->linear_size = 0x200000; - break; - case 3: /*8mb*/ - s3->linear_size = 0x800000; - break; - } - s3->linear_base &= ~(s3->linear_size - 1); - if (s3->linear_base == 0xa0000) - { - mem_mapping_disable(&s3->linear_mapping); - if (!(svga->crtc[0x53] & 0x10)) - { - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - svga->banked_mask = 0xffff; - } - } - else - mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); - } - else - mem_mapping_disable(&s3->linear_mapping); - - if (svga->crtc[0x53] & 0x10) /*Memory mapped IO*/ - { - mem_mapping_disable(&svga->mapping); - mem_mapping_enable(&s3->mmio_mapping); - } - else - mem_mapping_disable(&s3->mmio_mapping); -} - -static float s3_trio64_getclock(int clock, void *p) -{ - s3_t *s3 = (s3_t *)p; - svga_t *svga = &s3->svga; - float t; - int m, n1, n2; - if (clock == 0) return 25175000.0; - if (clock == 1) return 28322000.0; - m = svga->seqregs[0x13] + 2; - n1 = (svga->seqregs[0x12] & 0x1f) + 2; - n2 = ((svga->seqregs[0x12] >> 5) & 0x07); - t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); - return t; -} - - -void s3_accel_out(uint16_t port, uint8_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - - if (port >= 0x8000) - { - s3_queue(s3, port, val, FIFO_OUT_BYTE); - } - else switch (port) - { - case 0x42e8: - s3->subsys_stat &= ~val; - s3_update_irqs(s3); - break; - case 0x42e9: - s3->subsys_cntl = val; - s3_update_irqs(s3); - break; - case 0x46e8: - s3->accel.setup_md = val; - break; - case 0x4ae8: - s3->accel.advfunc_cntl = val; - break; - } -} - -void s3_accel_out_w(uint16_t port, uint16_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - s3_queue(s3, port, val, FIFO_OUT_WORD); -} - -void s3_accel_out_l(uint16_t port, uint32_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - s3_queue(s3, port, val, FIFO_OUT_DWORD); -} - -uint8_t s3_accel_in(uint16_t port, void *p) -{ - s3_t *s3 = (s3_t *)p; - int temp; - switch (port) - { - case 0x42e8: - return s3->subsys_stat; - case 0x42e9: - return s3->subsys_cntl; - - case 0x82e8: - s3_wait_fifo_idle(s3); - return s3->accel.cur_y & 0xff; - case 0x82e9: - s3_wait_fifo_idle(s3); - return s3->accel.cur_y >> 8; - - case 0x86e8: - s3_wait_fifo_idle(s3); - return s3->accel.cur_x & 0xff; - case 0x86e9: - s3_wait_fifo_idle(s3); - return s3->accel.cur_x >> 8; - - case 0x8ae8: - s3_wait_fifo_idle(s3); - return s3->accel.desty_axstp & 0xff; - case 0x8ae9: - s3_wait_fifo_idle(s3); - return s3->accel.desty_axstp >> 8; - - case 0x8ee8: - s3_wait_fifo_idle(s3); - return s3->accel.destx_distp & 0xff; - case 0x8ee9: - s3_wait_fifo_idle(s3); - return s3->accel.destx_distp >> 8; - - case 0x92e8: - s3_wait_fifo_idle(s3); - return s3->accel.err_term & 0xff; - case 0x92e9: - s3_wait_fifo_idle(s3); - return s3->accel.err_term >> 8; - - case 0x96e8: - s3_wait_fifo_idle(s3); - return s3->accel.maj_axis_pcnt & 0xff; - case 0x96e9: - s3_wait_fifo_idle(s3); - return s3->accel.maj_axis_pcnt >> 8; - - case 0x9ae8: - if (!s3->blitter_busy) - wake_fifo_thread(s3); - if (FIFO_FULL) - return 0xff; /*FIFO full*/ - return 0; /*FIFO empty*/ - case 0x9ae9: - if (!s3->blitter_busy) - wake_fifo_thread(s3); - temp = 0; - if (!FIFO_EMPTY) - temp |= 0x02; /*Hardware busy*/ - else - temp |= s3->status_9ae8; /*FIFO empty*/ - if (FIFO_FULL) - temp |= 0xf8; /*FIFO full*/ - return temp; - - case 0xa2e8: - s3_wait_fifo_idle(s3); - return s3->accel.bkgd_color & 0xff; - case 0xa2e9: - s3_wait_fifo_idle(s3); - return s3->accel.bkgd_color >> 8; - case 0xa2ea: - s3_wait_fifo_idle(s3); - return s3->accel.bkgd_color >> 16; - case 0xa2eb: - s3_wait_fifo_idle(s3); - return s3->accel.bkgd_color >> 24; - - case 0xa6e8: - s3_wait_fifo_idle(s3); - return s3->accel.frgd_color & 0xff; - case 0xa6e9: - s3_wait_fifo_idle(s3); - return s3->accel.frgd_color >> 8; - case 0xa6ea: - s3_wait_fifo_idle(s3); - return s3->accel.frgd_color >> 16; - case 0xa6eb: - s3_wait_fifo_idle(s3); - return s3->accel.frgd_color >> 24; - - case 0xaae8: - s3_wait_fifo_idle(s3); - return s3->accel.wrt_mask & 0xff; - case 0xaae9: - s3_wait_fifo_idle(s3); - return s3->accel.wrt_mask >> 8; - case 0xaaea: - s3_wait_fifo_idle(s3); - return s3->accel.wrt_mask >> 16; - case 0xaaeb: - s3_wait_fifo_idle(s3); - return s3->accel.wrt_mask >> 24; - - case 0xaee8: - s3_wait_fifo_idle(s3); - return s3->accel.rd_mask & 0xff; - case 0xaee9: - s3_wait_fifo_idle(s3); - return s3->accel.rd_mask >> 8; - case 0xaeea: - s3_wait_fifo_idle(s3); - return s3->accel.rd_mask >> 16; - case 0xaeeb: - s3_wait_fifo_idle(s3); - return s3->accel.rd_mask >> 24; - - case 0xb2e8: - s3_wait_fifo_idle(s3); - return s3->accel.color_cmp & 0xff; - case 0xb2e9: - s3_wait_fifo_idle(s3); - return s3->accel.color_cmp >> 8; - case 0xb2ea: - s3_wait_fifo_idle(s3); - return s3->accel.color_cmp >> 16; - case 0xb2eb: - s3_wait_fifo_idle(s3); - return s3->accel.color_cmp >> 24; - - case 0xb6e8: - s3_wait_fifo_idle(s3); - return s3->accel.bkgd_mix; - - case 0xbae8: - s3_wait_fifo_idle(s3); - return s3->accel.frgd_mix; - - case 0xbee8: - s3_wait_fifo_idle(s3); - temp = s3->accel.multifunc[0xf] & 0xf; - switch (temp) - { - case 0x0: return s3->accel.multifunc[0x0] & 0xff; - case 0x1: return s3->accel.multifunc[0x1] & 0xff; - case 0x2: return s3->accel.multifunc[0x2] & 0xff; - case 0x3: return s3->accel.multifunc[0x3] & 0xff; - case 0x4: return s3->accel.multifunc[0x4] & 0xff; - case 0x5: return s3->accel.multifunc[0xa] & 0xff; - case 0x6: return s3->accel.multifunc[0xe] & 0xff; - case 0x7: return s3->accel.cmd & 0xff; - case 0x8: return s3->accel.subsys_cntl & 0xff; - case 0x9: return s3->accel.setup_md & 0xff; - case 0xa: return s3->accel.multifunc[0xd] & 0xff; - } - return 0xff; - case 0xbee9: - s3_wait_fifo_idle(s3); - temp = s3->accel.multifunc[0xf] & 0xf; - s3->accel.multifunc[0xf]++; - switch (temp) - { - case 0x0: return s3->accel.multifunc[0x0] >> 8; - case 0x1: return s3->accel.multifunc[0x1] >> 8; - case 0x2: return s3->accel.multifunc[0x2] >> 8; - case 0x3: return s3->accel.multifunc[0x3] >> 8; - case 0x4: return s3->accel.multifunc[0x4] >> 8; - case 0x5: return s3->accel.multifunc[0xa] >> 8; - case 0x6: return s3->accel.multifunc[0xe] >> 8; - case 0x7: return s3->accel.cmd >> 8; - case 0x8: return (s3->accel.subsys_cntl >> 8) & ~0xe000; - case 0x9: return (s3->accel.setup_md >> 8) & ~0xf000; - case 0xa: return s3->accel.multifunc[0xd] >> 8; - } - return 0xff; - - case 0xe2e8: case 0xe2e9: case 0xe2ea: case 0xe2eb: /*PIX_TRANS*/ - break; - } - return 0; -} - -void s3_accel_write(uint32_t addr, uint8_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE); -} -void s3_accel_write_w(uint32_t addr, uint16_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD); -} -void s3_accel_write_l(uint32_t addr, uint32_t val, void *p) -{ - s3_t *s3 = (s3_t *)p; - s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD); -} - -uint8_t s3_accel_read(uint32_t addr, void *p) -{ - if (addr & 0x8000) - return s3_accel_in(addr & 0xffff, p); - return 0; -} - -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; - - 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; - } -} - -#define READ_SRC(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)]; \ - if (vram_mask) \ - dat = ((dat & rd_mask) == rd_mask); - -#define READ_DST(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ - else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ - else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; - -#define MIX { \ - 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; \ - } \ - else if (s3->bpp == 1) \ - { \ - vram_w[(addr) & (s3->vram_mask >> 1)] = dest_dat; \ - svga->changedvram[((addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ - } \ - else \ - { \ - vram_l[(addr) & (s3->vram_mask >> 2)] = dest_dat; \ - svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ - } - -void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) -{ - svga_t *svga = &s3->svga; - uint32_t src_dat = 0, dest_dat; - int frgd_mix, bkgd_mix; - int clip_t = s3->accel.multifunc[1] & 0xfff; - int clip_l = s3->accel.multifunc[2] & 0xfff; - int clip_b = s3->accel.multifunc[3] & 0xfff; - int clip_r = s3->accel.multifunc[4] & 0xfff; - int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0; - uint32_t mix_mask = 0; - uint16_t *vram_w = (uint16_t *)svga->vram; - uint32_t *vram_l = (uint32_t *)svga->vram; - uint32_t compare = s3->accel.color_cmp; - int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; - uint32_t rd_mask = s3->accel.rd_mask; - int cmd = s3->accel.cmd >> 13; - - if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) - cmd |= 8; - - if (!cpu_input) s3->accel.dat_count = 0; - if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) - { - if (s3->bpp == 3 && count == 2) - { - if (s3->accel.dat_count) - { - cpu_dat = ((cpu_dat & 0xffff) << 16) | s3->accel.dat_buf; - count = 4; - s3->accel.dat_count = 0; - } - else - { - s3->accel.dat_buf = cpu_dat & 0xffff; - s3->accel.dat_count = 1; - } - } - if (s3->bpp == 1) count >>= 1; - if (s3->bpp == 3) count >>= 2; - } - - 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 = (s3->chip == S3_TRIO32) ? 0x80 : 0x80000000; break; - } - - if (s3->bpp == 0) compare &= 0xff; - if (s3->bpp == 1) compare &= 0xffff; - switch (cmd) - { - case 1: /*Draw line*/ - if (!cpu_input) /*!cpu_input is trigger to start operation*/ - { - s3->accel.cx = s3->accel.cur_x; - if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; - s3->accel.cy = s3->accel.cur_y; - if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; - - s3->accel.sy = s3->accel.maj_axis_pcnt; - } - - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) + if (FIFO_FULL) + { + thread_reset_event(s3->fifo_not_full_event); + if (FIFO_FULL) { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } + thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; - frgd_mix = (s3->accel.frgd_mix >> 5) & 3; - bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - - if (s3->accel.cmd & 8) /*Radial*/ - { - while (count-- && s3->accel.sy >= 0) - { - if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && - s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) - { - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) - { - case 0: src_dat = s3->accel.bkgd_color; break; - case 1: src_dat = s3->accel.frgd_color; break; - case 2: src_dat = cpu_dat; break; - case 3: src_dat = 0; break; - } - - if ((compare_mode == 2 && src_dat != compare) || - (compare_mode == 3 && src_dat == compare) || - compare_mode < 2) - { - READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); - - MIX - - WRITE((s3->accel.cy * s3->width) + s3->accel.cx); - } - } - - mix_dat <<= 1; - mix_dat |= 1; - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; - if (!s3->accel.sy) - break; - - switch (s3->accel.cmd & 0xe0) - { - case 0x00: s3->accel.cx++; break; - case 0x20: s3->accel.cx++; s3->accel.cy--; break; - case 0x40: s3->accel.cy--; break; - case 0x60: s3->accel.cx--; s3->accel.cy--; break; - case 0x80: s3->accel.cx--; break; - case 0xa0: s3->accel.cx--; s3->accel.cy++; break; - case 0xc0: s3->accel.cy++; break; - case 0xe0: s3->accel.cx++; s3->accel.cy++; break; - } - s3->accel.sy--; - } - s3->accel.cur_x = s3->accel.cx; - s3->accel.cur_y = s3->accel.cy; - } - else /*Bresenham*/ - { - while (count-- && s3->accel.sy >= 0) - { - if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && - s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) - { - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) - { - case 0: src_dat = s3->accel.bkgd_color; break; - case 1: src_dat = s3->accel.frgd_color; break; - case 2: src_dat = cpu_dat; break; - case 3: src_dat = 0; break; - } - - if ((compare_mode == 2 && src_dat != compare) || - (compare_mode == 3 && src_dat == compare) || - compare_mode < 2) - { - READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); - - MIX - - WRITE((s3->accel.cy * s3->width) + s3->accel.cx); - } - } - - mix_dat <<= 1; - mix_dat |= 1; - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; - - if (!s3->accel.sy) - break; - - if (s3->accel.err_term >= s3->accel.maj_axis_pcnt) - { - s3->accel.err_term += s3->accel.destx_distp; - /*Step minor axis*/ - switch (s3->accel.cmd & 0xe0) - { - case 0x00: s3->accel.cy--; break; - case 0x20: s3->accel.cy--; break; - case 0x40: s3->accel.cx--; break; - case 0x60: s3->accel.cx++; break; - case 0x80: s3->accel.cy++; break; - case 0xa0: s3->accel.cy++; break; - case 0xc0: s3->accel.cx--; break; - case 0xe0: s3->accel.cx++; break; - } - } - else - s3->accel.err_term += s3->accel.desty_axstp; - - /*Step major axis*/ - switch (s3->accel.cmd & 0xe0) - { - case 0x00: s3->accel.cx--; break; - case 0x20: s3->accel.cx++; break; - case 0x40: s3->accel.cy--; break; - case 0x60: s3->accel.cy--; break; - case 0x80: s3->accel.cx--; break; - case 0xa0: s3->accel.cx++; break; - case 0xc0: s3->accel.cy++; break; - case 0xe0: s3->accel.cy++; break; - } - s3->accel.sy--; - } - s3->accel.cur_x = s3->accel.cx; - s3->accel.cur_y = s3->accel.cy; - } - break; - - case 2: /*Rectangle fill*/ - if (!cpu_input) /*!cpu_input is trigger to start operation*/ - { - s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - s3->accel.sy = s3->accel.multifunc[0] & 0xfff; - s3->accel.cx = s3->accel.cur_x; - if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; - s3->accel.cy = s3->accel.cur_y; - if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; - - s3->accel.dest = s3->accel.cy * s3->width; - } - - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } - - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ - - frgd_mix = (s3->accel.frgd_mix >> 5) & 3; - bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - - while (count-- && s3->accel.sy >= 0) - { - if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && - s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) - { - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) - { - case 0: src_dat = s3->accel.bkgd_color; break; - case 1: src_dat = s3->accel.frgd_color; break; - case 2: src_dat = cpu_dat; break; - case 3: src_dat = 0; break; - } - - if ((compare_mode == 2 && src_dat != compare) || - (compare_mode == 3 && src_dat == compare) || - compare_mode < 2) - { - READ_DST(s3->accel.dest + s3->accel.cx, dest_dat); - - MIX - - WRITE(s3->accel.dest + s3->accel.cx); - } - } - - mix_dat <<= 1; - mix_dat |= 1; - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; - - if (s3->accel.cmd & 0x20) s3->accel.cx++; - else s3->accel.cx--; - s3->accel.sx--; - if (s3->accel.sx < 0) - { - if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; - else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; - s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - - if (s3->accel.cmd & 0x80) s3->accel.cy++; - else s3->accel.cy--; - - s3->accel.dest = s3->accel.cy * s3->width; - s3->accel.sy--; - - if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; - if (s3->accel.sy < 0) - { - s3->accel.cur_x = s3->accel.cx; - s3->accel.cur_y = s3->accel.cy; - return; - } - } - } - break; - - case 6: /*BitBlt*/ - if (!cpu_input) /*!cpu_input is trigger to start operation*/ - { - s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - s3->accel.sy = s3->accel.multifunc[0] & 0xfff; - - s3->accel.dx = s3->accel.destx_distp & 0xfff; - if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; - s3->accel.dy = s3->accel.desty_axstp & 0xfff; - if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; - - s3->accel.cx = s3->accel.cur_x & 0xfff; - if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; - s3->accel.cy = s3->accel.cur_y & 0xfff; - if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; - - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; - } - - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } - - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ - - if (s3->accel.sy < 0) - return; - - frgd_mix = (s3->accel.frgd_mix >> 5) & 3; - bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - - if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && - (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7 && - (s3->accel.bkgd_mix & 0xf) == 7) - { - while (1) - { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) - { - READ_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); - } - - s3->accel.cx++; - s3->accel.dx++; - s3->accel.sx--; - if (s3->accel.sx < 0) - { - s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; - s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; - s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - - s3->accel.cy++; - s3->accel.dy++; - - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; - - s3->accel.sy--; - - if (s3->accel.sy < 0) - { - return; - } - } - } - } - else - { - while (count-- && s3->accel.sy >= 0) - { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) - { - if (vram_mask) - { - READ_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) - { - 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 + s3->accel.cx, 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.dx, dest_dat); - - MIX - - WRITE(s3->accel.dest + s3->accel.dx); - } - } - - mix_dat <<= 1; - mix_dat |= 1; - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; - - if (s3->accel.cmd & 0x20) - { - s3->accel.cx++; - s3->accel.dx++; - } - else - { - s3->accel.cx--; - s3->accel.dx--; - } - s3->accel.sx--; - if (s3->accel.sx < 0) - { - if (s3->accel.cmd & 0x20) - { - s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; - s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; - } - else - { - s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; - s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; - } - s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - - if (s3->accel.cmd & 0x80) - { - s3->accel.cy++; - s3->accel.dy++; - } - else - { - s3->accel.cy--; - s3->accel.dy--; - } - - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; - - s3->accel.sy--; - - if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; - if (s3->accel.sy < 0) - { - return; - } - } - } - } - break; - - case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/ - if (!cpu_input) /*!cpu_input is trigger to start operation*/ - { - s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - s3->accel.sy = s3->accel.multifunc[0] & 0xfff; - - s3->accel.dx = s3->accel.destx_distp & 0xfff; - if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; - s3->accel.dy = s3->accel.desty_axstp & 0xfff; - if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; - - s3->accel.cx = s3->accel.cur_x & 0xfff; - if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; - s3->accel.cy = s3->accel.cur_y & 0xfff; - if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; - - /*Align source with destination*/ - s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx; - s3->accel.dest = s3->accel.dy * s3->width; - - s3->accel.cx = s3->accel.dx & 7; - s3->accel.cy = s3->accel.dy & 7; - - s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); - } - - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } - - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ - - frgd_mix = (s3->accel.frgd_mix >> 5) & 3; - bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - - while (count-- && s3->accel.sy >= 0) - { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) - { - if (vram_mask) - { - READ_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) - { - 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 + s3->accel.cx, 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.dx, dest_dat); - - MIX - - WRITE(s3->accel.dest + s3->accel.dx); - } - } - - mix_dat <<= 1; - mix_dat |= 1; - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; - - if (s3->accel.cmd & 0x20) - { - s3->accel.cx = ((s3->accel.cx + 1) & 7) | (s3->accel.cx & ~7); - s3->accel.dx++; - } - else - { - s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7); - s3->accel.dx--; - } - s3->accel.sx--; - if (s3->accel.sx < 0) - { - if (s3->accel.cmd & 0x20) - { - s3->accel.cx = ((s3->accel.cx - ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); - s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; - } - else - { - s3->accel.cx = ((s3->accel.cx + ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); - s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; - } - s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; - - if (s3->accel.cmd & 0x80) - { - s3->accel.cy = ((s3->accel.cy + 1) & 7) | (s3->accel.cy & ~7); - s3->accel.dy++; - } - else - { - s3->accel.cy = ((s3->accel.cy - 1) & 7) | (s3->accel.cy & ~7); - s3->accel.dy--; - } - - s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); - s3->accel.dest = s3->accel.dy * s3->width; - - s3->accel.sy--; - - if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; - if (s3->accel.sy < 0) - return; - } - } - break; - - case 3: /*Polygon Fill Solid (Trio64 only)*/ - { - int end_y1, end_y2; - - if (s3->chip != S3_TRIO64) - break; - - polygon_setup(s3); - - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } - - 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 = y * s3->width; - - while (x_count-- && count--) - { - if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && - s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= 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); - - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } - - 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 = s3->accel.pattern + ((y & 7) * s3->width); - s3->accel.dest = y * s3->width; - - while (x_count-- && count--) - { - int pat_x = s3->accel.poly_x & 7; - - if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && - s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= 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; - } + s3->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(s3); } 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; - int y_add, x_add; - uint32_t fg = 0, bg = 0; + int x; + uint16_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + uint32_t fg, bg; - y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; - x_add = (enable_overscan && !suppress_overscan) ? 8 : 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; + 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; - } + 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; + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; - for (x = 0; x < 64; x += 16) - { - dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; - dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; - for (xx = 0; xx < 16; xx++) - { - if (offset >= svga->hwcursor_latch.x) - { - if (!(dat[0] & 0x8000)) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; - else if (dat[1] & 0x8000) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; - } - - offset++; - dat[0] <<= 1; - dat[1] <<= 1; - } - svga->hwcursor_latch.addr += 4; - } - if (svga->interlace && !svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += 16; + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; + else if (dat[1] & 0x8000) + buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 4; + } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; } +static void s3_io_remove_alt(s3_t *s3) +{ + if (!s3->translate) + return; + + io_removehandler(0x4148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8d48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xad48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbd48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} static void s3_io_remove(s3_t *s3) { - io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); - - io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - 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_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + + s3_io_remove_alt(s3); +} + +void s3_io_set_alt(s3_t *s3) +{ + if (!s3->translate) + return; + + io_sethandler(0x4148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_TRIO64) + { + io_sethandler(0x8148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8d48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + else + { + io_sethandler(0x8148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + io_sethandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xad48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbd48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); } static void s3_io_set(s3_t *s3) { - s3_io_remove(s3); + s3_io_remove(s3); - io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); - - io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + 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); + io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + + s3_io_set_alt(s3); +} + +void s3_out(uint16_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + uint8_t old, mask; + int rs2, rs3; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: + if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + if (((val >> 2) & 3) != 3) + icd2061_write(svga->clock_gen, (val >> 2) & 3); + } + break; + + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + { + svga->seqregs[svga->seqaddr] = val; + switch (svga->seqaddr) + { + case 0x12: case 0x13: + svga_recalctimings(svga); + return; + } + } + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + if ((svga->crtc[0x55] & 0x03) == 0x00) + rs2 = !!(svga->crtc[0x43] & 0x02); + else + rs2 = (svga->crtc[0x55] & 0x01); + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + svga_out(addr, val, svga); + else if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + if (!(svga->crtc[0x45] & 0x20) || (s3->chip == S3_86C928)) + rs3 = !!(svga->crtc[0x55] & 0x02); + else + rs3 = 0; + bt48x_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); + } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805 || s3->chip == S3_86C911) + att49x_ramdac_out(addr, val, svga->ramdac, svga); + else + sdac_ramdac_out(addr, rs2, val, svga->ramdac, svga); + return; + + case 0x3D4: + svga->crtcreg = val & 0x7f; + 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 >= 0x20) && (svga->crtcreg < 0x40) && + (svga->crtcreg != 0x36) && (svga->crtcreg != 0x38) && + (svga->crtcreg != 0x39) && ((svga->crtc[0x38] & 0xcc) != 0x48)) + return; + if ((svga->crtcreg >= 0x40) && ((svga->crtc[0x39] & 0xe0) != 0xa0)) + return; + if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5)) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x31: + s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4); + break; + case 0x32: + svga->vram_display_mask = (val & 0x40) ? 0x3ffff : s3->vram_mask; + break; + + case 0x50: + mask = 0xc0; + if (s3->chip > S3_86C805) + mask |= 0x01; + switch (svga->crtc[0x50] & mask) + { + case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; + case 0x01: s3->width = 1152; break; + case 0x40: s3->width = 640; break; + case 0x80: s3->width = 800; break; + case 0x81: s3->width = 1600; break; + case 0xc0: s3->width = 1280; break; + } + s3->bpp = (svga->crtc[0x50] >> 4) & 3; + break; + case 0x69: + if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && + (s3->chip != S3_86C911) && (s3->chip != S3_86C928)) + s3->ma_ext = val & 0x1f; + break; + + case 0x35: + s3->bank = (s3->bank & 0x70) | (val & 0xf); + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + break; + case 0x51: + if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) + s3->bank = (s3->bank & 0x6f) | ((val & 0x4) << 2); + else + s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) + s3->ma_ext = (s3->ma_ext & ~0x4) | ((val & 1) << 2); + else + s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && + (s3->chip != S3_86C911) && (s3->chip != S3_86C928)) { + s3->bank = val; + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + } + break; + + case 0x3a: + if (val & 0x10) + svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + if (s3->chip == S3_VISION964) + break; + svga->hwcursor.ena = val & 1; + break; + case 0x48: + if (s3->chip == S3_VISION964) + break; + svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; + if (svga->bpp == 32) svga->hwcursor.x >>= 1; + svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x4e] & 63; + svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) + svga->hwcursor.x <<= 1; + else if ((s3->chip == S3_86C801 || s3->chip == S3_86C805 || s3->chip == S3_86C928) && (svga->bpp == 15 || svga->bpp == 16)) + 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: + if (s3->chip != S3_86C911) + s3_updatemapping(s3); + break; + + case 0x55: + if (s3->chip == S3_86C928) { + if (val & 0x08) { + svga->hwcursor_draw = NULL; + svga->dac_hwcursor_draw = bt48x_hwcursor_draw; + } else { + svga->hwcursor_draw = s3_hwcursor_draw; + svga->dac_hwcursor_draw = NULL; + } + } + break; + + case 0x42: + if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + if (((svga->miscout >> 2) & 3) == 3) + icd2061_write(svga->clock_gen, svga->crtc[0x42] & 0x0f); + } + break; + + case 0x43: + if (s3->chip == S3_86C801 || s3->chip == S3_86C805 || + s3->chip == S3_86C911 || s3->chip == S3_86C928) { + s3_io_remove_alt(s3); + s3->translate = !!(svga->crtc[0x43] & 0x10); + s3_io_set_alt(s3); + } + break; + + case 0x67: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + switch (val >> 4) + { + case 3: svga->bpp = 15; break; + case 5: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + case 13: svga->bpp = 32; break; + default: svga->bpp = 8; break; + } + } + break; + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t s3_in(uint16_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + int rs2, rs3; + uint8_t temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c1: + if (svga->attraddr > 0x14) + return 0xff; + break; + + case 0x3c2: + if (s3->chip == S3_86C911) + return svga_in(addr, svga) | 0x10; + break; + + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + return svga->seqregs[svga->seqaddr]; + break; + + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + rs2 = (svga->crtc[0x55] & 0x01) || !!(svga->crtc[0x43] & 2); + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + return svga_in(addr, svga); + else if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + rs3 = !!(svga->crtc[0x55] & 0x02); + return bt48x_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); + } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805 || s3->chip == S3_86C911) + return att49x_ramdac_in(addr, svga->ramdac, svga); + else + return sdac_ramdac_in(addr, rs2, svga->ramdac, svga); + break; + + case 0x3d4: + return svga->crtcreg; + case 0x3d5: + switch (svga->crtcreg) + { + case 0x2d: return 0x88; /*Extended chip ID*/ + case 0x2e: return s3->id_ext; /*New chip ID*/ + case 0x2f: return 0; /*Revision level*/ + case 0x30: return s3->id; /*Chip ID*/ + case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); + case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); + case 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 0x5c: /* General Output Port Register */ + temp = svga->crtc[svga->crtcreg] & 0xf0; + if (((svga->miscout >> 2) & 3) == 3) + temp |= svga->crtc[0x42] & 0x0f; + else + temp |= ((svga->miscout >> 2) & 3); + return temp; + case 0x69: return s3->ma_ext; + case 0x6a: return s3->bank; + /* Phoenix S3 video BIOS'es seem to expect CRTC registers 6B and 6C + to be mirrors of 59 and 5A. */ + case 0x6b: return svga->crtc[0x59]; + case 0x6c: return svga->crtc[0x5a] & 0x80; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void s3_recalctimings(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) svga->ramdac; + int clk_sel = (svga->miscout >> 2) & 3; + + svga->hdisp = svga->hdisp_old; + + svga->ma_latch |= (s3->ma_ext << 16); + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) + { + svga->hdisp_time += 0x100; + svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + } + if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; + if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + + if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + svga->interlace = ramdac->cmd_r2 & 0x08; + if (ramdac->cmd_r3 & 0x08) + svga->hdisp *= 2; /* x2 clock multiplier */ + } else + svga->interlace = svga->crtc[0x42] & 0x20; + + if ((((svga->miscout >> 2) & 3) == 3) && (s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64)) + clk_sel = svga->crtc[0x42] & 0x0f; + + svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock(clk_sel, svga->clock_gen); + + switch (svga->crtc[0x67] >> 4) + { + case 3: case 5: case 7: + svga->clock /= 2; + break; + } + + svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + if (s3->chip != S3_VISION964 && s3->chip != S3_86C801 && s3->chip != S3_86C928) + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + if (s3->chip != S3_VISION964 && s3->chip != S3_86C801) + { + if (s3->chip == S3_86C928) + svga->hdisp *= 2; + else + svga->hdisp /= 2; + } + break; + case 24: + svga->render = svga_render_24bpp_highres; + if (s3->chip != S3_86C801 && s3->chip != S3_86C805 && s3->chip != S3_86C928) + svga->hdisp /= 3; + else + svga->hdisp = (svga->hdisp * 2) / 3; + break; + case 32: + svga->render = svga_render_32bpp_highres; + if ((s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964) && (s3->chip != S3_86C928)) + svga->hdisp /= 4; + break; + } + } +} + +void s3_updatemapping(s3_t *s3) +{ + svga_t *svga = &s3->svga; + + if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&s3->linear_mapping); + mem_mapping_disable(&s3->mmio_mapping); + return; + } + + /*Banked framebuffer*/ + if (svga->crtc[0x31] & 0x08) /*Enhanced mode mappings*/ + { + /* Enhanced mode 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); + 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; + } + + if ((svga->crtc[0x58] & 0x10) || (s3->accel.advfunc_cntl & 0x10)) + { + /*Linear framebuffer*/ + mem_mapping_disable(&svga->mapping); + + s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805) || + (s3->chip == S3_86C911) || (s3->chip == S3_86C928)) { + if (s3->vlb) + s3->linear_base &= 0x03ffffff; + else + s3->linear_base &= 0x00ffffff; + } + switch (svga->crtc[0x58] & 3) + { + case 0: /*64k*/ + s3->linear_size = 0x10000; + break; + case 1: /*1mb*/ + s3->linear_size = 0x100000; + break; + case 2: /*2mb*/ + s3->linear_size = 0x200000; + break; + case 3: /*8mb*/ + switch (s3->chip) { + case S3_TRIO32: + case S3_TRIO64: + case S3_86C801: + case S3_86C805: + case S3_86C928: + s3->linear_size = 0x400000; + break; + default: + s3->linear_size = 0x800000; + break; + } + break; + } + s3->linear_base &= ~(s3->linear_size - 1); + if (s3->linear_base == 0xa0000) + { + mem_mapping_disable(&s3->linear_mapping); + if (!(svga->crtc[0x53] & 0x10)) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + } + } + else + mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); + } + else + mem_mapping_disable(&s3->linear_mapping); + + /* Memory mapped I/O. */ + if ((svga->crtc[0x53] & 0x10) || (s3->accel.advfunc_cntl & 0x20)) { + /* Old MMIO. */ + mem_mapping_disable(&svga->mapping); + mem_mapping_enable(&s3->mmio_mapping); + } else + mem_mapping_disable(&s3->mmio_mapping); +} + +static float s3_trio64_getclock(int clock, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + float t; + int m, n1, n2; + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + m = svga->seqregs[0x13] + 2; + n1 = (svga->seqregs[0x12] & 0x1f) + 2; + n2 = ((svga->seqregs[0x12] >> 5) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + return t; +} + + +int s3_enable_fifo(s3_t *s3) +{ +/* FIXME: See why the Windows 3.x drivers break in non-FIFO mode - maybe FIFO is not disablable there? */ +#if 0 + svga_t *svga = &s3->svga; + + if ((s3->chip == S3_TRIO32) || (s3->chip == S3_TRIO64) || + (s3->chip == S3_VISION864) || (s3->chip == S3_VISION964)) + return 1; /* FIFO always enabled on these chips. */ + + return !!((svga->crtc[0x40] & 0x08) || (s3->accel.advfunc_cntl & 0x40)); +#else + return 1; +#endif +} + + +void s3_accel_out(uint16_t port, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + + if (port >= 0x8000) + { + if (s3_enable_fifo(s3)) + s3_queue(s3, port, val, FIFO_OUT_BYTE); + else + s3_accel_out_fifo(s3, port, val); + } + else + { + switch (port) + { + case 0x4148: case 0x42e8: + s3->subsys_stat &= ~val; + s3_update_irqs(s3); + break; + case 0x4149: case 0x42e9: + s3->subsys_cntl = val; + s3_update_irqs(s3); + break; + case 0x4548: case 0x46e8: + s3->accel.setup_md = val; + break; + case 0x4948: case 0x4ae8: + s3->accel.advfunc_cntl = val; + s3_updatemapping(s3); + break; + } + } +} + +void s3_accel_out_w(uint16_t port, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + + if (s3_enable_fifo(s3)) + s3_queue(s3, port, val, FIFO_OUT_WORD); + else + s3_accel_out_fifo_w(s3, port, val); +} + +void s3_accel_out_l(uint16_t port, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + + if (s3_enable_fifo(s3)) + s3_queue(s3, port, val, FIFO_OUT_DWORD); + else + s3_accel_out_fifo_l(s3, port, val); +} + +uint8_t s3_accel_in(uint16_t port, void *p) +{ + s3_t *s3 = (s3_t *)p; + int temp; + + switch (port) + { + case 0x4148: case 0x42e8: + return s3->subsys_stat; + case 0x4149: case 0x42e9: + return s3->subsys_cntl; + + case 0x8148: case 0x82e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y & 0xff; + case 8149: case 0x82e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y >> 8; + + case 0x8548: case 0x86e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x & 0xff; + case 0x8549: case 0x86e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x >> 8; + + case 0x8948: case 0x8ae8: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp & 0xff; + case 0x8949: case 0x8ae9: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp >> 8; + + case 0x8d48: case 0x8ee8: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp & 0xff; + case 0x8d49: case 0x8ee9: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp >> 8; + + case 0x9148: case 0x92e8: + s3_wait_fifo_idle(s3); + return s3->accel.err_term & 0xff; + case 0x9149: case 0x92e9: + s3_wait_fifo_idle(s3); + return s3->accel.err_term >> 8; + + case 0x9548: case 0x96e8: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt & 0xff; + case 0x9549: case 0x96e9: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt >> 8; + + case 0x9948: case 0x9ae8: + temp = 0; /* FIFO empty */ + if (!s3->blitter_busy) + wake_fifo_thread(s3); + if (FIFO_FULL && s3->chip >= S3_VISION864) + temp = 0xff; /*FIFO full*/ + return temp; /*FIFO empty*/ + case 0x9949: case 0x9ae9: + if (!s3->blitter_busy) + wake_fifo_thread(s3); + temp = 0; + if (s3->chip < S3_VISION864) + { + if (!FIFO_EMPTY) + temp |= 0x02; + else + temp |= s3->status_9ae8; /*FIFO empty*/ + if (s3->data_available) { + temp |= 0x01; + s3->data_available = 0; /* Clear to avoid overblits. */ + } + } + else + { + if (!FIFO_EMPTY) + temp |= 0x02; /*Hardware busy*/ + else + temp |= s3->status_9ae8; /*FIFO empty*/ + if (FIFO_FULL) + temp |= 0xf8; /*FIFO full*/ + } + return temp; + + case 0xa148: case 0xa2e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color & 0xff; + case 0xa149: case 0xa2e9: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 8; + case 0xa14a: case 0xa2ea: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 16; + case 0xa14b: case 0xa2eb: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 24; + + case 0xa548: case 0xa6e8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color & 0xff; + case 0xa549: case 0xa6e9: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 8; + case 0xa54a: case 0xa6ea: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 16; + case 0xa54b: case 0xa6eb: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 24; + + case 0xa948: case 0xaae8: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask & 0xff; + case 0xa949: case 0xaae9: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 8; + case 0xa94a: case 0xaaea: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 16; + case 0xa94b: case 0xaaeb: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 24; + + case 0xad48: case 0xaee8: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask & 0xff; + case 0xad49: case 0xaee9: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 8; + case 0xad4a: case 0xaeea: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 16; + case 0xad4b: case 0xaeeb: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 24; + + case 0xb148: case 0xb2e8: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp & 0xff; + case 0xb149: case 0xb2e9: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 8; + case 0xb14a: case 0xb2ea: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 16; + case 0xb14b: case 0xb2eb: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 24; + + case 0xb548: case 0xb6e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_mix; + + case 0xb948: case 0xbae8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_mix; + + case 0xbd48: case 0xbee8: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] & 0xff; + case 0x1: return s3->accel.multifunc[0x1] & 0xff; + case 0x2: return s3->accel.multifunc[0x2] & 0xff; + case 0x3: return s3->accel.multifunc[0x3] & 0xff; + case 0x4: return s3->accel.multifunc[0x4] & 0xff; + case 0x5: return s3->accel.multifunc[0xa] & 0xff; + case 0x6: return s3->accel.multifunc[0xe] & 0xff; + case 0x7: return s3->accel.cmd & 0xff; + case 0x8: return s3->accel.subsys_cntl & 0xff; + case 0x9: return s3->accel.setup_md & 0xff; + case 0xa: return s3->accel.multifunc[0xd] & 0xff; + } + return 0xff; + case 0xbd49: case 0xbee9: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + s3->accel.multifunc[0xf]++; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] >> 8; + case 0x1: return s3->accel.multifunc[0x1] >> 8; + case 0x2: return s3->accel.multifunc[0x2] >> 8; + case 0x3: return s3->accel.multifunc[0x3] >> 8; + case 0x4: return s3->accel.multifunc[0x4] >> 8; + case 0x5: return s3->accel.multifunc[0xa] >> 8; + case 0x6: return s3->accel.multifunc[0xe] >> 8; + case 0x7: return s3->accel.cmd >> 8; + case 0x8: return (s3->accel.subsys_cntl >> 8) & ~0xe000; + case 0x9: return (s3->accel.setup_md >> 8) & ~0xf000; + case 0xa: return s3->accel.multifunc[0xd] >> 8; + } + return 0xff; + + case 0xe148: case 0xe2e8: + if (!s3_cpu_dest(s3)) + break; + temp = s3->accel.pix_trans[0]; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(8, 1, 0xffffffff, 0, s3); + else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(1, 1, 0xffffffff, 0xffffffff, s3); + return temp; + case 0xe149: case 0xe2e9: + if (!s3_cpu_dest(s3)) + break; + temp = s3->accel.pix_trans[1]; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, 0xffffffff, 0, s3); + else s3_accel_start(16, 1, 0xffffffff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, 0xffffffff, s3); + else s3_accel_start(2, 1, 0xffffffff, 0xffffffff, s3); + } + return temp; + case 0xe14a: case 0xe2ea: + if (!s3_cpu_dest(s3)) + break; + temp = s3->accel.pix_trans[2]; + return temp; + case 0xe14b: case 0xe2eb: + if (!s3_cpu_dest(s3)) + break; + temp = s3->accel.pix_trans[3]; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x400) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(32, 1, 0xffffffff, 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(4, 1, 0xffffffff, 0xffffffff, s3); + return temp; + } + return 0; +} + +void s3_accel_write(uint32_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE); +} +void s3_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD); +} +void s3_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD); +} + +uint8_t s3_accel_read(uint32_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + uint8_t temp = 0x00; + + if (addr & 0x8000) + { + temp = s3_accel_in(addr & 0xffff, p); + } + else if (s3_cpu_dest(s3)) + { + temp = s3->accel.pix_trans[addr & 3]; + + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + s3_accel_start(8, 1, 0xffffffff, 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, 0xffffffff, s3); + } + } + + return temp; +} + +uint16_t s3_accel_read_w(uint32_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + uint16_t temp = 0x0000; + + if (addr & 0x8000) + { + temp = s3_accel_read((addr & 0xfffe), p); + temp |= s3_accel_read((addr & 0xfffe) + 1, p) << 8; + } + else if (s3_cpu_dest(s3)) + { + temp = s3->accel.pix_trans[addr & 2]; + temp |= s3->accel.pix_trans[(addr & 2) + 1] << 8; + + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, 0xff, 0, s3); + s3_accel_start(8, 1, 0xff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, 0xffff, 0, s3); + else + s3_accel_start(16, 1, 0xffff, 0, s3); + } + else + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, 0xffffffff, s3); + else + s3_accel_start(2, 1, 0xffffffff, 0xffffffff, s3); + } + } + } + + return temp; +} + +uint32_t s3_accel_read_l(uint32_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + uint32_t temp = 0x00000000; + + if (addr & 0x8000) + { + temp = s3_accel_read((addr & 0xfffc), p); + temp |= s3_accel_read((addr & 0xfffc) + 1, p) << 8; + temp |= s3_accel_read((addr & 0xfffc) + 2, p) << 16; + temp |= s3_accel_read((addr & 0xfffc) + 3, p) << 24; + } + else if (s3_cpu_dest(s3)) + { + temp = s3->accel.pix_trans[0]; + temp |= s3->accel.pix_trans[1] << 8; + temp |= s3->accel.pix_trans[2] << 16; + temp |= s3->accel.pix_trans[3] << 24; + + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, 0xff, 0, s3); + s3_accel_start(8, 1, 0xff, 0, s3); + s3_accel_start(8, 1, 0xff, 0, s3); + s3_accel_start(8, 1, 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) + { + s3_accel_start(32, 1, 0xffffffff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(16, 1, 0xffff, 0, s3); + s3_accel_start(16, 1, 0xffff, 0, s3); + } + else + { + s3_accel_start(8, 1, 0xffff, 0, s3); + s3_accel_start(8, 1, 0xffff, 0, s3); + } + } + else + { + if (s3->accel.cmd & 0x400) + s3_accel_start(4, 1, 0xffffffff, 0xffffffff, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, 0xffff, s3); + s3_accel_start(2, 1, 0xffffffff, 0xffff, s3); + } + else + { + s3_accel_start(1, 1, 0xffffffff, 0xffff, s3); + s3_accel_start(1, 1, 0xffffffff, 0xffff, s3); + } + } + } + } + + return temp; +} + +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; + + 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; + } +} + +#define READ_SRC(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)]; \ + if (vram_mask) \ + dat = ((dat & rd_mask) == rd_mask); + +#define READ_DST(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; + +#define MIX_READ { \ + switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = ~0; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } \ + } + + +#define MIX { \ + uint32_t old_dest_dat = dest_dat; \ + MIX_READ \ + 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; \ + } \ + else if (s3->bpp == 1) \ + { \ + vram_w[(addr) & (s3->vram_mask >> 1)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ + } \ + else \ + { \ + vram_l[(addr) & (s3->vram_mask >> 2)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ + } + +int s3_accel_count(s3_t *s3) +{ + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + return 8; + else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + return 1; + else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && ((s3->accel.cmd & 0x600) == 0x200) && (s3->accel.cmd & 0x100)) + return 16; + else if (((s3->accel.cmd & 0x600) == 0x200) && (s3->accel.cmd & 0x100)) + return 2; + else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x100)) + return 32; + else if (s3->accel.cmd & 0x100) + return 4; + else + return -1; +} + +int s3_data_len(s3_t *s3) +{ + if (!(s3->accel.cmd & 0x600)) + return 1; + + if ((s3->accel.cmd & 0x600) == 0x200) + return 2; + + return 4; +} + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) +{ + svga_t *svga = &s3->svga; + uint32_t src_dat = 0, dest_dat; + int frgd_mix, bkgd_mix; + int clip_t = s3->accel.multifunc[1] & 0xfff; + int clip_l = s3->accel.multifunc[2] & 0xfff; + int clip_b = s3->accel.multifunc[3] & 0xfff; + int clip_r = s3->accel.multifunc[4] & 0xfff; + int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0; + uint32_t mix_mask = 0; + uint16_t *vram_w = (uint16_t *)svga->vram; + uint32_t *vram_l = (uint32_t *)svga->vram; + uint32_t compare = s3->accel.color_cmp; + int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; + uint32_t rd_mask = s3->accel.rd_mask; + int cmd = s3->accel.cmd >> 13; + int read = 0, byte_cnt = 0, i; + + if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) + cmd |= 8; + + if (!cpu_input) s3->accel.dat_count = 0; + if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) + { + if (s3->bpp == 3 && count == 2) + { + if (s3->accel.dat_count) + { + cpu_dat = ((cpu_dat & 0xffff) << 16) | s3->accel.dat_buf; + count = 4; + s3->accel.dat_count = 0; + } + else + { + s3->accel.dat_buf = cpu_dat & 0xffff; + s3->accel.dat_count = 1; + } + } + if (s3->bpp == 1) count >>= 1; + if (s3->bpp == 3) count >>= 2; + } + + 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 = (s3->chip == S3_TRIO32) ? 0x80 : 0x80000000; break; + } + + if (s3->bpp == 0) compare &= 0xff; + if (s3->bpp == 1) compare &= 0xffff; + + switch (cmd) + { + case 1: /*Draw line*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.sy = s3->accel.maj_axis_pcnt; + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if (s3_cpu_dest(s3)) + s3->data_available = 0; + + + if (s3_cpu_src(s3) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if (s3_cpu_src(s3) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (s3->accel.cmd & 8) /*Radial*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + if (!s3->accel.sy) + break; + + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx++; break; + case 0x20: s3->accel.cx++; s3->accel.cy--; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cx--; s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx--; s3->accel.cy++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cx++; s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + else /*Bresenham*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (!s3->accel.sy) + break; + + if (s3->accel.err_term >= s3->accel.maj_axis_pcnt) + { + s3->accel.err_term += s3->accel.destx_distp; + /*Step minor axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cy--; break; + case 0x20: s3->accel.cy--; break; + case 0x40: s3->accel.cx--; break; + case 0x60: s3->accel.cx++; break; + case 0x80: s3->accel.cy++; break; + case 0xa0: s3->accel.cy++; break; + case 0xc0: s3->accel.cx--; break; + case 0xe0: s3->accel.cx++; break; + } + } + else + s3->accel.err_term += s3->accel.desty_axstp; + + /*Step major axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx--; break; + case 0x20: s3->accel.cx++; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + break; + + case 2: /*Rectangle fill*/ + byte_cnt = s3_data_len(s3); + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + s3->data_available = 0; + + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.dest = s3->accel.cy * s3->width; + + if (s3_cpu_src(s3)) { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } else if (s3_cpu_dest(s3)) + count = s3_accel_count(s3); + } + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + s3->accel.pix_trans[0] = 0xff; + s3->accel.pix_trans[1] = 0xff; + s3->accel.pix_trans[2] = 0xff; + s3->accel.pix_trans[3] = 0xff; + + 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_cpu_dest(s3) && ((s3->accel.multifunc[0xa] & 0xc0) == 0x00)) + mix_dat = mix_mask; /* Mix data = forced to foreground register. */ + else if (s3_cpu_dest(s3) && vram_mask) { + /* Mix data = current video memory value. */ + READ_SRC(s3->accel.dest + s3->accel.cx, mix_dat); + mix_dat = mix_dat ? mix_mask : 0; + } + + if (s3_cpu_dest(s3)) { + READ_SRC(s3->accel.dest + s3->accel.cx, src_dat); + } else switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + if (s3_cpu_dest(s3)) + dest_dat = 0xffffffff; + else { + READ_DST(s3->accel.dest + s3->accel.cx, dest_dat); + } + + MIX + + if (s3_cpu_dest(s3)) { + for (i = 0; i <= s3->bpp; i++) + s3->accel.pix_trans[read + i] = (src_dat >> (i << 3)) & 0xff; + /* Yes, src_dat is correct, there is no mixing/ROP's done on PIX_TRANS reads. */ + } else + WRITE(s3->accel.dest + s3->accel.cx); + } + } + + if (s3_cpu_dest(s3)) { + read += (s3->bpp + 1); + if (read >= byte_cnt) + s3->data_available = 1; /* Read data available. */ + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) s3->accel.cx++; + else s3->accel.cx--; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) s3->accel.cy++; + else s3->accel.cy--; + + s3->accel.dest = s3->accel.cy * s3->width; + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) { + if (s3_cpu_dest(s3)) + s3->data_available = 1; + return; + } + if (s3->accel.sy < 0) + { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + if (s3_cpu_dest(s3)) + s3->data_available = 1; + return; + } + } + + if (s3_cpu_dest(s3) && s3->data_available) + return; + } + break; + + case 6: /*BitBlt*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + if (s3->accel.sy < 0) + return; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && + (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7 && + (s3->accel.bkgd_mix & 0xf) == 7) + { + while (1) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + READ_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); + } + + s3->accel.cx++; + s3->accel.dx++; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + s3->accel.cy++; + s3->accel.dy++; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (s3->accel.sy < 0) + { + return; + } + } + } + } + else + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ_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) + { + 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 + s3->accel.cx, 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.dx, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx++; + s3->accel.dx++; + } + else + { + s3->accel.cx--; + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy++; + s3->accel.dy++; + } + else + { + s3->accel.cy--; + s3->accel.dy--; + } + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + { + return; + } + } + } + } + break; + + case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + /*Align source with destination*/ + s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.cx = s3->accel.dx & 7; + s3->accel.cy = s3->accel.dy & 7; + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ_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) + { + 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 + s3->accel.cx, 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.dx, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx + 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx++; + } + else + { + s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx - ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx = ((s3->accel.cx + ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy = ((s3->accel.cy + 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy++; + } + else + { + s3->accel.cy = ((s3->accel.cy - 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy--; + } + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + return; + } + } + break; + + case 3: /*Polygon Fill Solid (Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64) + break; + + polygon_setup(s3); + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + 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 = y * s3->width; + + while (x_count-- && count--) + { + if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && + s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= 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); + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + 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 = s3->accel.pattern + ((y & 7) * s3->width); + s3->accel.dest = y * s3->width; + + while (x_count-- && count--) + { + int pat_x = s3->accel.poly_x & 7; + + if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && + s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= 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; + } } - uint8_t s3_pci_read(int func, int addr, void *p) { - s3_t *s3 = (s3_t *)p; - svga_t *svga = &s3->svga; - switch (addr) - { - case 0x00: return 0x33; /*'S3'*/ - case 0x01: return 0x53; - - case 0x02: return s3->id_ext_pci; - case 0x03: return 0x88; - - case PCI_REG_COMMAND: - return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + switch (addr) + { + case 0x00: return 0x33; /*'S3'*/ + case 0x01: return 0x53; + + case 0x02: return s3->id_ext_pci; + case 0x03: return 0x88; + + case PCI_REG_COMMAND: + return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ - case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ - - case 0x08: return 0; /*Revision ID*/ - case 0x09: return 0; /*Programming interface*/ - - case 0x0a: return 0x00; /*Supports VGA interface*/ - case 0x0b: return 0x03; - - case 0x10: return 0x00; /*Linear frame buffer address*/ - case 0x11: return 0x00; - case 0x12: return svga->crtc[0x5a] & 0x80; - case 0x13: return svga->crtc[0x59]; + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: + if ((s3->chip == S3_TRIO32) || (s3->chip == S3_TRIO64)) + return 0x00; /*Supports VGA interface*/ + else + return 0x01; + case 0x0b: + if ((s3->chip == S3_TRIO32) || (s3->chip == S3_TRIO64)) + return 0x03; + else + return 0x00; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return svga->crtc[0x5a] & 0x80; + case 0x13: return svga->crtc[0x59]; - case 0x30: return s3->has_bios ? (s3->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ - case 0x31: return 0x00; - case 0x32: return s3->has_bios ? s3->pci_regs[0x32] : 0x00; - case 0x33: return s3->has_bios ? s3->pci_regs[0x33] : 0x00; - - case 0x3c: return s3->int_line; - case 0x3d: return PCI_INTA; - } - return 0; + case 0x30: return s3->has_bios ? (s3->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return s3->has_bios ? s3->pci_regs[0x32] : 0x00; + case 0x33: return s3->has_bios ? s3->pci_regs[0x33] : 0x00; + + case 0x3c: return s3->int_line; + case 0x3d: return PCI_INTA; + } + return 0; } void s3_pci_write(int func, int addr, uint8_t val, void *p) { - s3_t *s3 = (s3_t *)p; - svga_t *svga = &s3->svga; - switch (addr) - { - case PCI_REG_COMMAND: - s3->pci_regs[PCI_REG_COMMAND] = val & 0x23; - if (val & PCI_COMMAND_IO) - s3_io_set(s3); - else - s3_io_remove(s3); - s3_updatemapping(s3); - break; - - case 0x12: - svga->crtc[0x5a] = val & 0x80; - s3_updatemapping(s3); - break; - case 0x13: - svga->crtc[0x59] = val; - s3_updatemapping(s3); - break; + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + switch (addr) + { + case PCI_REG_COMMAND: + s3->pci_regs[PCI_REG_COMMAND] = val & 0x23; + if (val & PCI_COMMAND_IO) + s3_io_set(s3); + else + s3_io_remove(s3); + s3_updatemapping(s3); + break; + + case 0x12: + svga->crtc[0x5a] = (svga->crtc[0x5a] & 0x7f) | (val & 0x80); + s3_updatemapping(s3); + break; + case 0x13: + svga->crtc[0x59] = val; + s3_updatemapping(s3); + break; - case 0x30: case 0x32: case 0x33: + case 0x30: case 0x32: case 0x33: if (!s3->has_bios) return; - s3->pci_regs[addr] = val; - if (s3->pci_regs[0x30] & 0x01) - { - uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24); - mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000); - } - else - { - mem_mapping_disable(&s3->bios_rom.mapping); - } - return; - - case 0x3c: - s3->int_line = val; - return; - } + s3->pci_regs[addr] = val; + if (s3->pci_regs[0x30] & 0x01) + { + uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24); + mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000); + } + else + { + mem_mapping_disable(&s3->bios_rom.mapping); + } + return; + + case 0x3c: + s3->int_line = val; + return; + } } static int vram_sizes[] = { - 7, /*512 kB*/ - 6, /*1 MB*/ - 4, /*2 MB*/ - 0, - 0, /*4 MB*/ - 0, - 0, - 0, - 3 /*8 MB*/ + 7, /*512 kB*/ + 6, /*1 MB*/ + 4, /*2 MB*/ + 0, + 0, /*4 MB*/ + 0, + 0, + 0, + 3 /*8 MB*/ }; -static void *s3_init(const device_t *info, wchar_t *bios_fn, int chip) +static void *s3_init(const device_t *info) { - s3_t *s3 = malloc(sizeof(s3_t)); - svga_t *svga = &s3->svga; - int vram; - uint32_t vram_size; - - memset(s3, 0, sizeof(s3_t)); - - vram = device_get_config_int("memory"); - if (vram) - vram_size = vram << 20; - else - vram_size = 512 << 10; - s3->vram_mask = vram_size - 1; + const wchar_t *bios_fn; + int chip, stepping; + s3_t *s3 = malloc(sizeof(s3_t)); + svga_t *svga = &s3->svga; + int vram; + uint32_t vram_size; - s3->has_bios = !info->local; + switch(info->local) { + case S3_ORCHID_86C911: + bios_fn = ROM_ORCHID_86C911; + chip = S3_86C911; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c911); + break; + case S3_V7MIRAGE_86C801: + bios_fn = ROM_V7MIRAGE_86C801; + chip = S3_86C801; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); + break; + case S3_PHOENIX_86C805: + bios_fn = ROM_PHOENIX_86C805; + chip = S3_86C805; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + break; + case S3_METHEUS_86C928: + bios_fn = ROM_METHEUS_86C928; + chip = S3_86C928; + if (info->flags & DEVICE_VLB) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); + break; + case S3_PARADISE_BAHAMAS64: + bios_fn = ROM_PARADISE_BAHAMAS64; + chip = S3_VISION864; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision864); + break; + case S3_PHOENIX_VISION864: + bios_fn = ROM_PHOENIX_VISION864; + chip = S3_VISION864; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision864); + break; + case S3_DIAMOND_STEALTH64_964: + bios_fn = ROM_DIAMOND_STEALTH64_964; + chip = S3_VISION964; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision964); + break; + case S3_PHOENIX_TRIO32: + bios_fn = ROM_PHOENIX_TRIO32; + chip = S3_TRIO32; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio32); + break; + case S3_PHOENIX_TRIO64: + bios_fn = ROM_PHOENIX_TRIO64; + chip = S3_TRIO64; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64); + break; + case S3_PHOENIX_TRIO64_ONBOARD: + bios_fn = NULL; + chip = S3_TRIO64; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64); + break; + case S3_DIAMOND_STEALTH64_764: + bios_fn = ROM_DIAMOND_STEALTH64_764; + chip = S3_TRIO64; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_stealth64); + break; + case S3_NUMBER9_9FX: + bios_fn = ROM_NUMBER9_9FX; + chip = S3_TRIO64; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio64); + break; + default: + free(s3); + return NULL; + } + + memset(s3, 0, sizeof(s3_t)); + + vram = device_get_config_int("memory"); + + if (vram) + vram_size = vram << 20; + else + vram_size = 512 << 10; + s3->vram_mask = vram_size - 1; + + s3->has_bios = (bios_fn != NULL); if (s3->has_bios) { - rom_init(&s3->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&s3->bios_rom, (wchar_t *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (info->flags & DEVICE_PCI) mem_mapping_disable(&s3->bios_rom.mapping); } s3->pci = !!(info->flags & DEVICE_PCI); + s3->vlb = !!(info->flags & DEVICE_VLB); - mem_mapping_add(&s3->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &s3->svga); - mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3); - mem_mapping_disable(&s3->mmio_mapping); + mem_mapping_add(&s3->linear_mapping, 0, 0, + svga_read_linear, svga_readw_linear, svga_readl_linear, + svga_write_linear, svga_writew_linear, svga_writel_linear, + NULL, MEM_MAPPING_EXTERNAL, &s3->svga); + mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, + s3_accel_read, s3_accel_read_w, s3_accel_read_l, + s3_accel_write, s3_accel_write_w, s3_accel_write_l, + NULL, MEM_MAPPING_EXTERNAL, s3); + mem_mapping_disable(&s3->mmio_mapping); + + if (chip == S3_VISION964) + svga_init(&s3->svga, s3, vram_size, + s3_recalctimings, + s3_in, s3_out, + NULL, + NULL); + else + svga_init(&s3->svga, s3, vram_size, + s3_recalctimings, + s3_in, s3_out, + s3_hwcursor_draw, + NULL); - svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/ - s3_recalctimings, - s3_in, s3_out, - s3_hwcursor_draw, - NULL); + if (chip == S3_VISION964) + svga->dac_hwcursor_draw = bt48x_hwcursor_draw; - 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; - case 8: /*4MB*/ - svga->vram_mask = (8 << 20) - 1; - svga->vram_max = 8 << 20; - break; - } - - if (info->flags & DEVICE_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; + if (s3->chip >= S3_VISION864) { + switch (vram) { + case 0: /* 512 kB */ + svga->vram_mask = (1 << 19) - 1; + svga->vram_max = 2 << 20; + break; + case 1: /* 1 MB */ + /* VRAM in first MB, mirrored in 2nd MB, 3rd and 4th MBs are open bus. - s3_io_set(s3); - - if (info->flags & DEVICE_PCI) - { - s3->card = pci_add_card(PCI_ADD_VIDEO, s3_pci_read, s3_pci_write, s3); + 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: /*2 MB */ + /* 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; + case 8: /*8MB*/ + svga->vram_mask = (8 << 20) - 1; + svga->vram_max = 8 << 20; + break; + } } - s3->pci_regs[0x04] = 7; - - s3->pci_regs[0x30] = 0x00; - s3->pci_regs[0x32] = 0x0c; - s3->pci_regs[0x33] = 0x00; - - s3->chip = chip; + if (info->flags & DEVICE_PCI) + svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + else if (info->flags & DEVICE_VLB) + svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + else + svga->crtc[0x36] = 3 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + svga->crtc[0x37] = 1 | (7 << 5); - 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; -} + svga->vblank_start = s3_vblank_start; -void *s3_vision864_init(const device_t *info, wchar_t *bios_fn) -{ - s3_t *s3 = s3_init(info, bios_fn, S3_VISION864); + s3_io_set(s3); - s3->id = 0xc1; /*Vision864P*/ - s3->id_ext = s3->id_ext_pci = 0xc1; - s3->packed_mmio = 0; - - s3->getclock = sdac_getclock; - s3->getclock_p = &s3->ramdac; - sdac_init(&s3->ramdac); + if (info->flags & DEVICE_PCI) + s3->card = pci_add_card(PCI_ADD_VIDEO, s3_pci_read, s3_pci_write, s3); - return s3; -} + s3->pci_regs[0x04] = 7; + s3->pci_regs[0x30] = 0x00; + s3->pci_regs[0x32] = 0x0c; + s3->pci_regs[0x33] = 0x00; + + s3->chip = chip; + + s3->wake_fifo_thread = thread_create_event(); + s3->fifo_not_full_event = thread_create_event(); + s3->fifo_thread = thread_create(fifo_thread, s3); + + s3->int_line = 0; + + switch(info->local) { + case S3_ORCHID_86C911: + svga->decode_mask = (1 << 20) - 1; + stepping = 0x81; /*86C911*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + s3->width = 1024; + + svga->ramdac = device_add(&att490_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + + case S3_V7MIRAGE_86C801: + svga->decode_mask = (2 << 20) - 1; + stepping = 0xa0; /*86C801/86C805*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&att490_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + + case S3_PHOENIX_86C805: + svga->decode_mask = (2 << 20) - 1; + stepping = 0xa0; /*86C801/86C805*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&att492_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + + case S3_METHEUS_86C928: + svga->decode_mask = (4 << 20) - 1; + stepping = 0x90; /*86C928*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&bt485_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + break; + + case S3_PARADISE_BAHAMAS64: + case S3_PHOENIX_VISION864: + svga->decode_mask = (8 << 20) - 1; + if (info->local == S3_PARADISE_BAHAMAS64) + stepping = 0xc0; /*Vision864*/ + else + stepping = 0xc1; /*Vision864P*/ + s3->id = stepping; + s3->id_ext = s3->id_ext_pci = stepping; + s3->packed_mmio = 0; + + svga->ramdac = device_add(&sdac_ramdac_device); + svga->clock_gen = svga->ramdac; + svga->getclock = sdac_getclock; + break; + + case S3_DIAMOND_STEALTH64_964: + svga->decode_mask = (8 << 20) - 1; + stepping = 0xd0; /*Vision964P*/ + s3->id = stepping; + s3->id_ext = s3->id_ext_pci = stepping; + s3->packed_mmio = 1; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&bt485_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + break; + + case S3_PHOENIX_TRIO32: + svga->decode_mask = (4 << 20) - 1; + s3->id = 0xe1; /*Trio32*/ + s3->id_ext = 0x10; + s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + svga->clock_gen = s3; + svga->getclock = s3_trio64_getclock; + break; + + case S3_PHOENIX_TRIO64: + case S3_PHOENIX_TRIO64_ONBOARD: + case S3_DIAMOND_STEALTH64_764: + if (device_get_config_int("memory") == 1) + s3->svga.vram_max = 1 << 20; /* Phoenix BIOS does not expect VRAM to be mirrored. */ + /* Fall over. */ + + case S3_NUMBER9_9FX: + svga->decode_mask = (4 << 20) - 1; + s3->id = 0xe1; /*Trio64*/ + s3->id_ext = s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + svga->clock_gen = s3; + svga->getclock = s3_trio64_getclock; + break; + + default: + return NULL; + } -static void *s3_bahamas64_init(const device_t *info) -{ - s3_t *s3 = s3_vision864_init(info, L"roms/video/s3/bahamas64.bin"); return s3; } -static void *s3_phoenix_vision864_init(const device_t *info) +static int s3_orchid_86c911_available(void) { - s3_t *s3 = s3_vision864_init(info, L"roms/video/s3/86c864p.bin"); - return s3; + return rom_present(ROM_ORCHID_86C911); +} + +static int s3_v7mirage_86c801_available(void) +{ + return rom_present(ROM_V7MIRAGE_86C801); +} + +static int s3_phoenix_86c805_available(void) +{ + return rom_present(ROM_PHOENIX_86C805); +} + +static int s3_metheus_86c928_available(void) +{ + return rom_present(ROM_METHEUS_86C928); } static int s3_bahamas64_available(void) { - return rom_present(L"roms/video/s3/bahamas64.bin"); + return rom_present(ROM_PARADISE_BAHAMAS64); } static int s3_phoenix_vision864_available(void) { - return rom_present(L"roms/video/s3/86c864p.bin"); + return rom_present(ROM_PHOENIX_VISION864); } -static void *s3_phoenix_trio32_init(const device_t *info) +static int s3_diamond_stealth64_964_available(void) { - s3_t *s3 = s3_init(info, L"roms/video/s3/86c732p.bin", S3_TRIO32); - - s3->id = 0xe1; /*Trio32*/ - s3->id_ext = 0x10; - s3->id_ext_pci = 0x11; - s3->packed_mmio = 1; - - s3->getclock = s3_trio64_getclock; - s3->getclock_p = s3; - - return s3; + return rom_present(ROM_DIAMOND_STEALTH64_964); } static int s3_phoenix_trio32_available(void) { - return rom_present(L"roms/video/s3/86c732p.bin"); -} - -static void *s3_trio64_init(const device_t *info, wchar_t *bios_fn) -{ - s3_t *s3 = s3_init(info, bios_fn, S3_TRIO64); - - s3->id = 0xe1; /*Trio64*/ - s3->id_ext = s3->id_ext_pci = 0x11; - s3->packed_mmio = 1; - - s3->getclock = s3_trio64_getclock; - s3->getclock_p = s3; - - return s3; -} - -static void *s3_9fx_init(const device_t *info) -{ - s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/s3_764.bin"); - return s3; -} - -static void *s3_phoenix_trio64_init(const device_t *info) -{ - s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/86c764x1.bin"); - if (device_get_config_int("memory") == 1) - s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ - return s3; -} - -static void *s3_phoenix_trio64_onboard_init(const device_t *info) -{ - s3_t *s3 = s3_trio64_init(info, NULL); - if (device_get_config_int("memory") == 1) - s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ - return s3; -} - -static void *s3_diamond_stealth64_init(const device_t *info) -{ - s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/stealt64.bin"); - if (device_get_config_int("memory") == 1) - s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ - return s3; + return rom_present(ROM_PHOENIX_TRIO32); } static int s3_9fx_available(void) { - return rom_present(L"roms/video/s3/s3_764.bin"); + return rom_present(ROM_NUMBER9_9FX); } static int s3_phoenix_trio64_available(void) { - return rom_present(L"roms/video/s3/86c764x1.bin"); + return rom_present(ROM_PHOENIX_TRIO64); } -static int s3_diamond_stealth64_available(void) +static int s3_diamond_stealth64_764_available(void) { - return rom_present(L"roms/video/s3/stealt64.bin"); + return rom_present(ROM_DIAMOND_STEALTH64_764); } static void s3_close(void *p) { - s3_t *s3 = (s3_t *)p; + s3_t *s3 = (s3_t *)p; - svga_close(&s3->svga); - - thread_kill(s3->fifo_thread); - thread_destroy_event(s3->wake_fifo_thread); - thread_destroy_event(s3->fifo_not_full_event); + svga_close(&s3->svga); + + thread_kill(s3->fifo_thread); + thread_destroy_event(s3->wake_fifo_thread); + thread_destroy_event(s3->fifo_not_full_event); - free(s3); + free(s3); } static void s3_speed_changed(void *p) { - s3_t *s3 = (s3_t *)p; - - svga_recalctimings(&s3->svga); + s3_t *s3 = (s3_t *)p; + + svga_recalctimings(&s3->svga); } static void s3_force_redraw(void *p) { - s3_t *s3 = (s3_t *)p; + s3_t *s3 = (s3_t *)p; - s3->svga.fullchange = changeframecount; + s3->svga.fullchange = changeframecount; } -static const device_config_t s3_bahamas64_config[] = +static const device_config_t s3_orchid_86c911_config[] = { - { - "memory", "Memory size", CONFIG_SELECTION, "", 4, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/ - { - "" - } - } - }, - { - "", "", -1 - } + { + "memory", "Memory size", CONFIG_SELECTION, "", 1, + { + { + "512 KB", 0 + }, + { + "1 MB", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } }; static const device_config_t s3_9fx_config[] = { - { - "memory", "Memory size", CONFIG_SELECTION, "", 2, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ - { - "" - } - } - }, - { - "is_pci", "Bus", CONFIG_SELECTION, "", 1, - { - { - "VLB", 0 - }, - { - "PCI", 1 - }, - { - "" - } - } - }, - { - "", "", -1 - } + { + "memory", "Memory size", CONFIG_SELECTION, "", 2, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ + { + "" + } + } + }, + { + "", "", -1 + } }; static const device_config_t s3_phoenix_trio32_config[] = { - { - "memory", "Memory size", CONFIG_SELECTION, "", 2, - { - { - "512 KB", 0 - }, - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "" - } - } - }, - { - "", "", -1 - } + { + "memory", "Memory size", CONFIG_SELECTION, "", 2, + { + { + "512 KB", 0 + }, + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "" + } + } + }, + { + "", "", -1 + } }; static const device_config_t s3_phoenix_trio64_onboard_config[] = { - { - "memory", "Video memory size", CONFIG_SELECTION, "", 4, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - { - "" - } - } - }, - { - "", "", -1 - } + { + "memory", "Video memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } }; -static const device_config_t s3_phoenix_trio64_config[] = +static const device_config_t s3_config[] = { - { - "memory", "Memory size", CONFIG_SELECTION, "", 4, - { - { - "1 MB", 1 - }, - { - "2 MB", 2 - }, - { - "4 MB", 4 - }, - { - "" - } - } - }, - { - "", "", -1 - } + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t s3_orchid_86c911_isa_device = +{ + "Orchid Fahrenheit 1280 (S3 86c911) ISA", + DEVICE_AT | DEVICE_ISA, + S3_ORCHID_86C911, + s3_init, + s3_close, + NULL, + s3_orchid_86c911_available, + s3_speed_changed, + s3_force_redraw, + s3_orchid_86c911_config +}; + +const device_t s3_v7mirage_86c801_isa_device = +{ + "SPEA V7 Mirage (S3 86c801) ISA", + DEVICE_AT | DEVICE_ISA, + S3_V7MIRAGE_86C801, + s3_init, + s3_close, + NULL, + s3_v7mirage_86c801_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config +}; + +const device_t s3_phoenix_86c805_vlb_device = +{ + "Phoenix S3 86c805 VLB", + DEVICE_VLB, + S3_PHOENIX_86C805, + s3_init, + s3_close, + NULL, + s3_phoenix_86c805_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config +}; + +const device_t s3_metheus_86c928_isa_device = +{ + "Metheus Premier 928 (S3 86c928) ISA", + DEVICE_AT | DEVICE_ISA, + S3_METHEUS_86C928, + s3_init, + s3_close, + NULL, + s3_metheus_86c928_available, + s3_speed_changed, + s3_force_redraw, + s3_config +}; + +const device_t s3_metheus_86c928_vlb_device = +{ + "Metheus Premier 928 (S3 86c928) VLB", + DEVICE_VLB, + S3_METHEUS_86C928, + s3_init, + s3_close, + NULL, + s3_metheus_86c928_available, + s3_speed_changed, + s3_force_redraw, + s3_config }; const device_t s3_bahamas64_vlb_device = { - "Paradise Bahamas 64 (S3 Vision864) VLB", - DEVICE_VLB, - 0, - s3_bahamas64_init, - s3_close, + "Paradise Bahamas 64 (S3 Vision864) VLB", + DEVICE_VLB, + S3_PARADISE_BAHAMAS64, + s3_init, + s3_close, NULL, - s3_bahamas64_available, - s3_speed_changed, - s3_force_redraw, - s3_bahamas64_config + s3_bahamas64_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config }; const device_t s3_bahamas64_pci_device = { - "Paradise Bahamas 64 (S3 Vision864) PCI", - DEVICE_PCI, - 0, - s3_bahamas64_init, - s3_close, + "Paradise Bahamas 64 (S3 Vision864) PCI", + DEVICE_PCI, + S3_PARADISE_BAHAMAS64, + s3_init, + s3_close, NULL, - s3_bahamas64_available, - s3_speed_changed, - s3_force_redraw, - s3_bahamas64_config + s3_bahamas64_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config +}; + +const device_t s3_diamond_stealth64_964_vlb_device = +{ + "S3 Vision964 (Diamond Stealth64 VRAM) VLB", + DEVICE_VLB, + S3_DIAMOND_STEALTH64_964, + s3_init, + s3_close, + NULL, + s3_diamond_stealth64_964_available, + s3_speed_changed, + s3_force_redraw, + s3_config +}; + +const device_t s3_diamond_stealth64_964_pci_device = +{ + "S3 Vision964 (Diamond Stealth64 VRAM) PCI", + DEVICE_PCI, + S3_DIAMOND_STEALTH64_964, + s3_init, + s3_close, + NULL, + s3_diamond_stealth64_964_available, + s3_speed_changed, + s3_force_redraw, + s3_config }; const device_t s3_9fx_vlb_device = { - "Number 9 9FX (S3 Trio64) VLB", - DEVICE_VLB, - 0, - s3_9fx_init, - s3_close, + "Number 9 9FX (S3 Trio64) VLB", + DEVICE_VLB, + S3_NUMBER9_9FX, + s3_init, + s3_close, NULL, - s3_9fx_available, - s3_speed_changed, - s3_force_redraw, - s3_9fx_config + s3_9fx_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config }; const device_t s3_9fx_pci_device = { - "Number 9 9FX (S3 Trio64) PCI", - DEVICE_PCI, - 0, - s3_9fx_init, - s3_close, + "Number 9 9FX (S3 Trio64) PCI", + DEVICE_PCI, + S3_NUMBER9_9FX, + s3_init, + s3_close, NULL, - s3_9fx_available, - s3_speed_changed, - s3_force_redraw, - s3_9fx_config + s3_9fx_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config }; const device_t s3_phoenix_trio32_vlb_device = { - "Phoenix S3 Trio32 VLB", - DEVICE_VLB, - 0, - s3_phoenix_trio32_init, - s3_close, + "Phoenix S3 Trio32 VLB", + DEVICE_VLB, + S3_PHOENIX_TRIO32, + s3_init, + s3_close, NULL, - s3_phoenix_trio32_available, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio32_config + s3_phoenix_trio32_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio32_config }; const device_t s3_phoenix_trio32_pci_device = { - "Phoenix S3 Trio32 PCI", - DEVICE_PCI, - 0, - s3_phoenix_trio32_init, - s3_close, + "Phoenix S3 Trio32 PCI", + DEVICE_PCI, + S3_PHOENIX_TRIO32, + s3_init, + s3_close, NULL, - s3_phoenix_trio32_available, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio32_config + s3_phoenix_trio32_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio32_config }; const device_t s3_phoenix_trio64_vlb_device = { - "Phoenix S3 Trio64 VLB", - DEVICE_VLB, - 0, - s3_phoenix_trio64_init, - s3_close, + "Phoenix S3 Trio64 VLB", + DEVICE_VLB, + S3_PHOENIX_TRIO64, + s3_init, + s3_close, NULL, - s3_phoenix_trio64_available, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio64_config + s3_phoenix_trio64_available, + s3_speed_changed, + s3_force_redraw, + s3_config }; const device_t s3_phoenix_trio64_onboard_pci_device = { - "Phoenix S3 Trio64 On-Board PCI", - DEVICE_PCI, - 1, - s3_phoenix_trio64_onboard_init, - s3_close, + "Phoenix S3 Trio64 On-Board PCI", + DEVICE_PCI, + S3_PHOENIX_TRIO64_ONBOARD, + s3_init, + s3_close, NULL, - NULL, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio64_onboard_config + NULL, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_onboard_config }; const device_t s3_phoenix_trio64_pci_device = { - "Phoenix S3 Trio64 PCI", - DEVICE_PCI, - 0, - s3_phoenix_trio64_init, - s3_close, + "Phoenix S3 Trio64 PCI", + DEVICE_PCI, + S3_PHOENIX_TRIO64, + s3_init, + s3_close, NULL, - s3_phoenix_trio64_available, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio64_config + s3_phoenix_trio64_available, + s3_speed_changed, + s3_force_redraw, + s3_config }; const device_t s3_phoenix_vision864_vlb_device = { - "Phoenix S3 Vision864 VLB", - DEVICE_VLB, - 0, - s3_phoenix_vision864_init, - s3_close, + "Phoenix S3 Vision864 VLB", + DEVICE_VLB, + S3_PHOENIX_VISION864, + s3_init, + s3_close, NULL, - s3_phoenix_vision864_available, - s3_speed_changed, - s3_force_redraw, - s3_bahamas64_config + s3_phoenix_vision864_available, + s3_speed_changed, + s3_force_redraw, + s3_config }; const device_t s3_phoenix_vision864_pci_device = { - "Phoenix S3 Vision864 PCI", - DEVICE_PCI, - 0, - s3_phoenix_vision864_init, - s3_close, + "Phoenix S3 Vision864 PCI", + DEVICE_PCI, + S3_PHOENIX_VISION864, + s3_init, + s3_close, NULL, - s3_phoenix_vision864_available, - s3_speed_changed, - s3_force_redraw, - s3_bahamas64_config + s3_phoenix_vision864_available, + s3_speed_changed, + s3_force_redraw, + s3_config }; const device_t s3_diamond_stealth64_vlb_device = { - "S3 Trio64 (Diamond Stealth64 DRAM) VLB", - DEVICE_PCI, - 0, - s3_diamond_stealth64_init, - s3_close, + "S3 Trio64 (Diamond Stealth64 DRAM) VLB", + DEVICE_PCI, + S3_DIAMOND_STEALTH64_764, + s3_init, + s3_close, NULL, - s3_diamond_stealth64_available, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio64_config + s3_diamond_stealth64_764_available, + s3_speed_changed, + s3_force_redraw, + s3_config }; const device_t s3_diamond_stealth64_pci_device = { - "S3 Trio64 (Diamond Stealth64 DRAM) PCI", - DEVICE_PCI, - 0, - s3_diamond_stealth64_init, - s3_close, + "S3 Trio64 (Diamond Stealth64 DRAM) PCI", + DEVICE_PCI, + S3_DIAMOND_STEALTH64_764, + s3_init, + s3_close, NULL, - s3_diamond_stealth64_available, - s3_speed_changed, - s3_force_redraw, - s3_phoenix_trio64_config + s3_diamond_stealth64_764_available, + s3_speed_changed, + s3_force_redraw, + s3_config }; diff --git a/src/video/vid_s3.h b/src/video/vid_s3.h index 04888acdb..a44d5cc27 100644 --- a/src/video/vid_s3.h +++ b/src/video/vid_s3.h @@ -9,7 +9,7 @@ * Emulation of the S3 Trio32, S3 Trio64, and S3 Vision864 * graphics cards. * - * Version: @(#)vid_s3.h 1.0.2 2018/03/18 + * Version: @(#)vid_s3.h 1.0.4 2019/01/12 * * Author: Sarah Walker, * Miran Grca, @@ -17,6 +17,11 @@ * Copyright 2016-2018 Miran Grca. */ +const device_t s3_orchid_86c911_isa_device; +const device_t s3_metheus_premier_86c928_isa_device; +const device_t s3_metheus_premier_86c928_vlb_device; +const device_t s3_v7mirage_86c801_isa_device; +const device_t s3_phoenix_86c805_vlb_device; const device_t s3_bahamas64_vlb_device; const device_t s3_bahamas64_pci_device; const device_t s3_9fx_vlb_device; @@ -30,4 +35,5 @@ const device_t s3_phoenix_vision864_pci_device; const device_t s3_phoenix_vision864_vlb_device; const device_t s3_diamond_stealth64_pci_device; const device_t s3_diamond_stealth64_vlb_device; -/* const device_t s3_miro_vision964_device; */ +const device_t s3_diamond_stealth64_964_pci_device; +const device_t s3_diamond_stealth64_964_vlb_device; diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 59a20b2bf..1e1bf4dad 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -8,7 +8,7 @@ * * S3 ViRGE emulation. * - * Version: @(#)vid_s3_virge.c 1.0.12 2018/07/16 + * Version: @(#)vid_s3_virge.c 1.0.17 2018/10/27 * * Authors: Sarah Walker, * Miran Grca, @@ -25,6 +25,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../pci.h" #include "../rom.h" @@ -65,6 +66,26 @@ static int dither[4][4] = #define FIFO_TYPE 0xff000000 #define FIFO_ADDR 0x00ffffff +#define ROM_DIAMOND_STEALTH3D_2000 L"roms/video/s3virge/s3virge.bin" +#define ROM_DIAMOND_STEALTH3D_3000 L"roms/video/s3virge/diamondstealth3000.vbi" +#define ROM_VIRGE_DX L"roms/video/s3virge/86c375_1.bin" +#define ROM_VIRGE_DX_VBE20 L"roms/video/s3virge/86c375_4.bin" + +enum +{ + S3_DIAMOND_STEALTH3D_2000, + S3_DIAMOND_STEALTH3D_3000, + S3_VIRGE_DX, + S3_VIRGE_DX_VBE20 +}; + +enum +{ + S3_VIRGE, + S3_VIRGEVX, + S3_VIRGEDX +}; + enum { FIFO_INVALID = (0x00 << 24), @@ -141,7 +162,7 @@ typedef struct virge_t int card; int pci; - int is_375; + int chip; int bilinear_enabled; int dithering_enabled; @@ -251,6 +272,10 @@ typedef struct virge_t uint8_t subsys_stat, subsys_cntl; } virge_t; +static video_timings_t timing_diamond_stealth3d_2000 = {VIDEO_BUS, 2, 2, 3, 28, 28, 45}; +static video_timings_t timing_diamond_stealth3d_3000 = {VIDEO_BUS, 2, 2, 4, 26, 26, 42}; +static video_timings_t timing_virge_dx = {VIDEO_BUS, 2, 2, 3, 28, 28, 45}; + static __inline void wake_fifo_thread(virge_t *virge) { thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ @@ -323,22 +348,22 @@ enum #ifdef ENABLE_S3_VIRGE_LOG int s3_virge_do_log = ENABLE_S3_VIRGE_LOG; -#endif static void -s3_virge_log(const char *format, ...) +s3_virge_log(const char *fmt, ...) { -#ifdef ENABLE_S3_VIRGE_LOG va_list ap; if (s3_virge_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define s3_virge_log(fmt, ...) +#endif static void s3_virge_update_irqs(virge_t *virge) @@ -481,7 +506,7 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) case 2: case 3: svga->bpp = 15; break; case 4: case 5: svga->bpp = 16; break; case 7: svga->bpp = 24; break; - case 13: svga->bpp = ((gfxcard == GFX_VIRGEVX_VLB) || (gfxcard == GFX_VIRGEVX_PCI)) ? 24 : 32; break; + case 13: svga->bpp = (virge->chip == S3_VIRGEVX) ? 24 : 32; break; default: svga->bpp = 8; break; } break; @@ -596,7 +621,7 @@ static void s3_virge_recalctimings(svga_t *svga) } } - if ((gfxcard != GFX_VIRGEVX_VLB) && (gfxcard != GFX_VIRGEVX_PCI)) + if (virge->chip != S3_VIRGEVX) { if ((svga->bpp == 15) || (svga->bpp == 16)) { @@ -660,11 +685,11 @@ static void s3_virge_recalctimings(svga_t *svga) if (((svga->miscout >> 2) & 3) == 3) { int n = svga->seqregs[0x12] & 0x1f; - int r = (svga->seqregs[0x12] >> 5) & ((virge->is_375 || ((gfxcard == GFX_VIRGEVX_VLB) || (gfxcard == GFX_VIRGEVX_PCI))) ? 7 : 3); + int r = (svga->seqregs[0x12] >> 5) & (((virge->chip == S3_VIRGEVX) || (virge->chip == S3_VIRGEDX)) ? 7 : 3); int m = svga->seqregs[0x13] & 0x7f; double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; - svga->clock = cpuclock / freq; + svga->clock = (cpuclock * (float)(1ull << 32)) / freq; } } @@ -740,21 +765,23 @@ static void s3_virge_updatemapping(virge_t *virge) } s3_virge_log("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x18); - if (svga->crtc[0x53] & 0x10) /*Old MMIO*/ - { - if (svga->crtc[0x53] & 0x20) - mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000); - else - mem_mapping_set_addr(&virge->mmio_mapping, 0xa0000, 0x10000); - } - else - mem_mapping_disable(&virge->mmio_mapping); - if (svga->crtc[0x53] & 0x08) /*New MMIO*/ - mem_mapping_set_addr(&virge->new_mmio_mapping, virge->linear_base + 0x1000000, 0x10000); - else - mem_mapping_disable(&virge->new_mmio_mapping); + /* Memory mapped I/O. */ + /* Old MMIO. */ + if (svga->crtc[0x53] & 0x10) { + if (svga->crtc[0x53] & 0x20) + mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000); + else + mem_mapping_set_addr(&virge->mmio_mapping, 0xa0000, 0x10000); + } else + mem_mapping_disable(&virge->mmio_mapping); + + /* New MMIO. */ + if (svga->crtc[0x53] & 0x08) /*New MMIO*/ + mem_mapping_set_addr(&virge->new_mmio_mapping, virge->linear_base + 0x1000000, 0x10000); + else + mem_mapping_disable(&virge->new_mmio_mapping); } static void s3_virge_vblank_start(svga_t *svga) @@ -2941,7 +2968,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; + uint8_t *vram = svga->vram; int x_dir = s3d_tri->tlr ? 1 : -1; @@ -2996,7 +3023,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; } dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); @@ -3039,7 +3066,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; @@ -3064,7 +3091,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; @@ -3089,6 +3116,9 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 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) { update = 1; @@ -3277,25 +3307,25 @@ static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) tex_sample = virge->bilinear_enabled ? tex_sample_normal_filter : tex_sample_normal; break; case (0 | 8): case (1 | 8): - if (virge->is_375) + if (virge->chip == S3_VIRGEDX) tex_sample = tex_sample_persp_mipmap_375; else tex_sample = tex_sample_persp_mipmap; break; case (2 | 8): case (3 | 8): - if (virge->is_375) + if (virge->chip == S3_VIRGEDX) tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter_375 : tex_sample_persp_mipmap_375; else tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter : tex_sample_persp_mipmap; break; case (4 | 8): case (5 | 8): - if (virge->is_375) + if (virge->chip == S3_VIRGEDX) tex_sample = tex_sample_persp_normal_375; else tex_sample = tex_sample_persp_normal; break; case (6 | 8): case (7 | 8): - if (virge->is_375) + if (virge->chip == S3_VIRGEDX) tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter_375 : tex_sample_persp_normal_375; else tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter : tex_sample_persp_normal; @@ -3377,12 +3407,8 @@ 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; - int y_add, x_add; uint32_t fg, bg; - y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; - x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; - if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; @@ -3421,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 + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; } offset++; @@ -3437,9 +3463,9 @@ 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 + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; else if (dat[1] & 0x8000) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; } offset++; @@ -3690,11 +3716,9 @@ static void s3_virge_overlay_draw(svga_t *svga, int displine) int x; uint32_t *p; uint8_t *src = &svga->vram[svga->overlay_latch.addr]; - int y_add = enable_overscan ? 16 : 0; - int x_add = enable_overscan ? 8 : 0; - - p = &((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add]; + p = &(buffer32->line[displine][offset + svga->x_add]); + if ((offset + virge->streams.sec_w) > virge->streams.pri_w) x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1; else @@ -3826,13 +3850,33 @@ static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) static void *s3_virge_init(const device_t *info) { + const wchar_t *bios_fn; virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); virge->bilinear_enabled = device_get_config_int("bilinear"); virge->dithering_enabled = device_get_config_int("dithering"); virge->memory_size = device_get_config_int("memory"); + switch(info->local) { + case S3_DIAMOND_STEALTH3D_2000: + bios_fn = ROM_DIAMOND_STEALTH3D_2000; + break; + case S3_DIAMOND_STEALTH3D_3000: + bios_fn = ROM_DIAMOND_STEALTH3D_3000; + break; + case S3_VIRGE_DX: + bios_fn = ROM_VIRGE_DX; + break; + case S3_VIRGE_DX_VBE20: + bios_fn = ROM_VIRGE_DX_VBE20; + break; + default: + free(virge); + return NULL; + } + svga_init(&virge->svga, virge, virge->memory_size << 20, s3_virge_recalctimings, s3_virge_in, s3_virge_out, @@ -3842,7 +3886,7 @@ static void *s3_virge_init(const device_t *info) virge->pci = !!(info->flags & DEVICE_PCI); - rom_init(&virge->bios_rom, L"roms/video/s3virge/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&virge->bios_rom, (wchar_t *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (info->flags & DEVICE_PCI) mem_mapping_disable(&virge->bios_rom.mapping); @@ -3853,7 +3897,7 @@ static void *s3_virge_init(const device_t *info) s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL, - 0, + MEM_MAPPING_EXTERNAL, virge); mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, s3_virge_mmio_read_w, @@ -3862,7 +3906,7 @@ static void *s3_virge_init(const device_t *info) s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL, - 0, + MEM_MAPPING_EXTERNAL, virge); mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, @@ -3871,7 +3915,7 @@ static void *s3_virge_init(const device_t *info) svga_writew_linear, svga_writel_linear, NULL, - 0, + MEM_MAPPING_EXTERNAL, &virge->svga); io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); @@ -3885,8 +3929,6 @@ static void *s3_virge_init(const device_t *info) virge->pci_regs[0x3e] = 4; virge->pci_regs[0x3f] = 0xff; - virge->virge_id_high = 0x56; - virge->virge_id_low = 0x31; virge->virge_rev = 0; virge->virge_id = 0xe1; @@ -3900,18 +3942,37 @@ static void *s3_virge_init(const device_t *info) virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); break; } - + virge->svga.crtc[0x37] = 1; virge->svga.crtc[0x53] = 1 << 3; virge->svga.crtc[0x59] = 0x70; - virge->is_375 = 0; - - if (info->flags & DEVICE_PCI) - { - virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + switch(info->local) { + case S3_DIAMOND_STEALTH3D_2000: + virge->svga.vblank_start = s3_virge_vblank_start; + virge->virge_id_high = 0x56; + virge->virge_id_low = 0x31; + virge->chip = S3_VIRGE; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_diamond_stealth3d_2000); + break; + case S3_DIAMOND_STEALTH3D_3000: + virge->virge_id_high = 0x88; + virge->virge_id_low = 0x3d; + virge->chip = S3_VIRGEVX; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_diamond_stealth3d_3000); + break; + default: + virge->svga.crtc[0x6c] = 0x01; + virge->virge_id_high = 0x8a; + virge->virge_id_low = 0x01; + virge->chip = S3_VIRGEDX; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_virge_dx); + break; } - + + if (info->flags & DEVICE_PCI) + virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + virge->wake_render_thread = thread_create_event(); virge->wake_main_thread = thread_create_event(); virge->not_full_event = thread_create_event(); @@ -3924,223 +3985,9 @@ static void *s3_virge_init(const device_t *info) return virge; } -static void *s3_virge_988_init(const device_t *info) -{ - virge_t *virge = malloc(sizeof(virge_t)); - memset(virge, 0, sizeof(virge_t)); - - virge->bilinear_enabled = device_get_config_int("bilinear"); - virge->dithering_enabled = device_get_config_int("dithering"); - virge->memory_size = device_get_config_int("memory"); - - svga_init(&virge->svga, virge, virge->memory_size << 20, - s3_virge_recalctimings, - s3_virge_in, s3_virge_out, - s3_virge_hwcursor_draw, - s3_virge_overlay_draw); - - virge->pci = !!(info->flags & DEVICE_PCI); - - rom_init(&virge->bios_rom, L"roms/video/s3virge/diamondstealth3000.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (info->flags & DEVICE_PCI) - mem_mapping_disable(&virge->bios_rom.mapping); - - mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, - s3_virge_mmio_read_w, - s3_virge_mmio_read_l, - s3_virge_mmio_write, - s3_virge_mmio_write_w, - s3_virge_mmio_write_l, - NULL, - 0, - virge); - mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, - s3_virge_mmio_read_w, - s3_virge_mmio_read_l, - s3_virge_mmio_write, - s3_virge_mmio_write_w, - s3_virge_mmio_write_l, - NULL, - 0, - virge); - mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - 0, - &virge->svga); - - io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); - - virge->pci_regs[4] = 3; - virge->pci_regs[5] = 0; - virge->pci_regs[6] = 0; - virge->pci_regs[7] = 2; - virge->pci_regs[0x32] = 0x0c; - virge->pci_regs[0x3d] = 1; - virge->pci_regs[0x3e] = 4; - virge->pci_regs[0x3f] = 0xff; - - virge->virge_id_high = 0x88; - virge->virge_id_low = 0x3d; - virge->virge_rev = 0; - virge->virge_id = 0xe1; - - switch (virge->memory_size) - { - case 2: - virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); - break; - case 4: - default: - virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); - break; - } - - virge->svga.crtc[0x37] = 1; - virge->svga.crtc[0x53] = 1 << 3; - virge->svga.crtc[0x59] = 0x70; - - virge->is_375 = 0; - - if (info->flags & DEVICE_PCI) - { - virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); - } - - virge->wake_render_thread = thread_create_event(); - virge->wake_main_thread = thread_create_event(); - virge->not_full_event = thread_create_event(); - virge->render_thread = thread_create(render_thread, virge); - - virge->wake_fifo_thread = thread_create_event(); - virge->fifo_not_full_event = thread_create_event(); - virge->fifo_thread = thread_create(fifo_thread, virge); - - return virge; -} - -static void *s3_virge_375_init(const device_t *info, wchar_t *romfn) -{ - virge_t *virge = malloc(sizeof(virge_t)); - memset(virge, 0, sizeof(virge_t)); - - virge->bilinear_enabled = device_get_config_int("bilinear"); - virge->dithering_enabled = device_get_config_int("dithering"); - virge->memory_size = device_get_config_int("memory"); - - svga_init(&virge->svga, virge, virge->memory_size << 20, - s3_virge_recalctimings, - s3_virge_in, s3_virge_out, - s3_virge_hwcursor_draw, - s3_virge_overlay_draw); - - virge->pci = !!(info->flags & DEVICE_PCI); - - rom_init(&virge->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (info->flags & DEVICE_PCI) - mem_mapping_disable(&virge->bios_rom.mapping); - - mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, - s3_virge_mmio_read_w, - s3_virge_mmio_read_l, - s3_virge_mmio_write, - s3_virge_mmio_write_w, - s3_virge_mmio_write_l, - NULL, - 0, - virge); - mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, - s3_virge_mmio_read_w, - s3_virge_mmio_read_l, - s3_virge_mmio_write, - s3_virge_mmio_write_w, - s3_virge_mmio_write_l, - NULL, - 0, - virge); - mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, - svga_readw_linear, - svga_readl_linear, - svga_write_linear, - svga_writew_linear, - svga_writel_linear, - NULL, - 0, - &virge->svga); - - io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); - - virge->pci_regs[4] = 3; - virge->pci_regs[5] = 0; - virge->pci_regs[6] = 0; - virge->pci_regs[7] = 2; - virge->pci_regs[0x32] = 0x0c; - virge->pci_regs[0x3d] = 1; - virge->pci_regs[0x3e] = 4; - virge->pci_regs[0x3f] = 0xff; - - virge->virge_id_high = 0x8a; - virge->virge_id_low = 0x01; - virge->virge_rev = 0; - virge->virge_id = 0xe1; - - switch (virge->memory_size) - { - case 2: - virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); - break; - case 4: - default: - virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); - break; - } - virge->svga.crtc[0x37] = 1; - virge->svga.crtc[0x53] = 1 << 3; - virge->svga.crtc[0x59] = 0x70; - - virge->svga.crtc[0x6c] = 0x01; - - virge->is_375 = 1; - - if (info->flags & DEVICE_PCI) - { - virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); - } - - virge->wake_render_thread = thread_create_event(); - virge->wake_main_thread = thread_create_event(); - virge->not_full_event = thread_create_event(); - virge->render_thread = thread_create(render_thread, virge); - - virge->wake_fifo_thread = thread_create_event(); - virge->fifo_not_full_event = thread_create_event(); - virge->fifo_thread = thread_create(fifo_thread, virge); - - return virge; -} - -static void *s3_virge_375_1_init(const device_t *info) -{ - return s3_virge_375_init(info, L"roms/video/s3virge/86c375_1.bin"); -} - -static void *s3_virge_375_4_init(const device_t *info) -{ - return s3_virge_375_init(info, L"roms/video/s3virge/86c375_4.bin"); -} - static void s3_virge_close(void *p) { virge_t *virge = (virge_t *)p; -#if 0 - FILE *f = fopen("vram.dmp", "wb"); - fwrite(virge->svga.vram, 4 << 20, 1, f); - fclose(f); -#endif thread_kill(virge->render_thread); thread_destroy_event(virge->not_full_event); @@ -4158,22 +4005,22 @@ static void s3_virge_close(void *p) static int s3_virge_available(void) { - return rom_present(L"roms/video/s3virge/s3virge.bin"); + return rom_present(ROM_DIAMOND_STEALTH3D_2000); } static int s3_virge_988_available(void) { - return rom_present(L"roms/video/s3virge/diamondstealth3000.vbi"); + return rom_present(ROM_DIAMOND_STEALTH3D_3000); } static int s3_virge_375_1_available(void) { - return rom_present(L"roms/video/s3virge/86c375_1.bin"); + return rom_present(ROM_VIRGE_DX); } static int s3_virge_375_4_available(void) { - return rom_present(L"roms/video/s3virge/86c375_4.bin"); + return rom_present(ROM_VIRGE_DX_VBE20); } static void s3_virge_speed_changed(void *p) @@ -4221,7 +4068,7 @@ const device_t s3_virge_vlb_device = { "Diamond Stealth 3D 2000 (S3 ViRGE) VLB", DEVICE_VLB, - 0, + S3_DIAMOND_STEALTH3D_2000, s3_virge_init, s3_virge_close, NULL, @@ -4235,7 +4082,7 @@ const device_t s3_virge_pci_device = { "Diamond Stealth 3D 2000 (S3 ViRGE) PCI", DEVICE_PCI, - 0, + S3_DIAMOND_STEALTH3D_2000, s3_virge_init, s3_virge_close, NULL, @@ -4249,8 +4096,8 @@ const device_t s3_virge_988_vlb_device = { "Diamond Stealth 3D 3000 (S3 ViRGE/VX) VLB", DEVICE_VLB, - 0, - s3_virge_988_init, + S3_DIAMOND_STEALTH3D_3000, + s3_virge_init, s3_virge_close, NULL, s3_virge_988_available, @@ -4263,8 +4110,8 @@ const device_t s3_virge_988_pci_device = { "Diamond Stealth 3D 3000 (S3 ViRGE/VX) PCI", DEVICE_PCI, - 0, - s3_virge_988_init, + S3_DIAMOND_STEALTH3D_3000, + s3_virge_init, s3_virge_close, NULL, s3_virge_988_available, @@ -4277,8 +4124,8 @@ const device_t s3_virge_375_vlb_device = { "S3 ViRGE/DX VLB", DEVICE_VLB, - 0, - s3_virge_375_1_init, + S3_VIRGE_DX, + s3_virge_init, s3_virge_close, NULL, s3_virge_375_1_available, @@ -4291,8 +4138,8 @@ const device_t s3_virge_375_pci_device = { "S3 ViRGE/DX PCI", DEVICE_PCI, - 0, - s3_virge_375_1_init, + S3_VIRGE_DX, + s3_virge_init, s3_virge_close, NULL, s3_virge_375_1_available, @@ -4305,8 +4152,8 @@ const device_t s3_virge_375_4_vlb_device = { "S3 ViRGE/DX (VBE 2.0) VLB", DEVICE_VLB, - 0, - s3_virge_375_4_init, + S3_VIRGE_DX_VBE20, + s3_virge_init, s3_virge_close, NULL, s3_virge_375_4_available, @@ -4319,8 +4166,8 @@ const device_t s3_virge_375_4_pci_device = { "S3 ViRGE/DX (VBE 2.0) PCI", DEVICE_PCI, - 0, - s3_virge_375_4_init, + S3_VIRGE_DX_VBE20, + s3_virge_init, s3_virge_close, NULL, s3_virge_375_4_available, diff --git a/src/video/vid_sc1502x_ramdac.c b/src/video/vid_sc1502x_ramdac.c index 18f78c8b0..75cb01995 100644 --- a/src/video/vid_sc1502x_ramdac.c +++ b/src/video/vid_sc1502x_ramdac.c @@ -10,102 +10,147 @@ * * Used by the TLIVESA1 driver for ET4000. * - * Version: @(#)vid_sc1502x_ramdac.c 1.0.2 2017/11/04 + * Version: @(#)vid_sc1502x_ramdac.c 1.0.3 2018/10/04 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "../86box.h" +#include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_sc1502x_ramdac.h" -void sc1502x_ramdac_out(uint16_t addr, uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga) +void +sc1502x_ramdac_out(uint16_t addr, uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga) { - int oldbpp = 0; - switch (addr) - { - case 0x3C6: - if (ramdac->state == 4) - { - ramdac->state = 0; - if (val == 0xFF) break; - ramdac->ctrl = val; - oldbpp = svga->bpp; - switch ((val&1)|((val&0xC0)>>5)) - { - case 0: - svga->bpp = 8; - break; - case 2: case 3: - switch (val & 0x20) - { - case 0x00: svga->bpp = 32; break; - case 0x20: svga->bpp = 24; break; - } - break; - case 4: case 5: - svga->bpp = 15; - break; - case 6: - svga->bpp = 16; - break; - case 7: - switch (val & 4) - { - case 4: - switch (val & 0x20) - { - case 0x00: svga->bpp = 32; break; - case 0x20: svga->bpp = 24; break; - } - break; - case 0: default: - svga->bpp = 16; - break; - } - case 1: default: + int oldbpp = 0; + + switch (addr) { + case 0x3C6: + if (ramdac->state == 4) { + ramdac->state = 0; + if (val == 0xFF) break; - } - if (oldbpp != svga->bpp) - { - svga_recalctimings(svga); + ramdac->ctrl = val; + oldbpp = svga->bpp; + switch ((val & 1) | ((val & 0xc0) >> 5)) { + case 0: + svga->bpp = 8; + break; + case 2: + case 3: + switch (val & 0x20) { + case 0x00: + svga->bpp = 32; + break; + case 0x20: + svga->bpp = 24; + break; + } + break; + case 4: + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 16; + break; + case 7: + if (val & 4) { + switch (val & 0x20) { + case 0x00: + svga->bpp = 32; + break; + case 0x20: + svga->bpp = 24; + break; + } + break; + } else { + svga->bpp = 16; + break; + } + break; } - return; - } - ramdac->state = 0; - break; - case 0x3C7: case 0x3C8: case 0x3C9: - ramdac->state = 0; - break; - } - svga_out(addr, val, svga); + if (oldbpp != svga->bpp) + svga_recalctimings(svga); + return; + } + ramdac->state = 0; + break; + case 0x3C7: + case 0x3C8: + case 0x3C9: + ramdac->state = 0; + break; + } + + svga_out(addr, val, svga); } -uint8_t sc1502x_ramdac_in(uint16_t addr, sc1502x_ramdac_t *ramdac, svga_t *svga) + +uint8_t +sc1502x_ramdac_in(uint16_t addr, sc1502x_ramdac_t *ramdac, svga_t *svga) { - switch (addr) - { - case 0x3C6: - if (ramdac->state == 4) - { - ramdac->state = 0; - return ramdac->ctrl; - } - ramdac->state++; - break; - case 0x3C7: case 0x3C8: case 0x3C9: - ramdac->state = 0; - break; - } - return svga_in(addr, svga); + uint8_t temp; + temp = svga_in(addr, svga); + + switch (addr) { + case 0x3C6: + if (ramdac->state == 4) { + ramdac->state = 0; + temp = ramdac->ctrl; + break; + } + ramdac->state++; + break; + case 0x3C7: + case 0x3C8: + case 0x3C9: + ramdac->state = 0; + break; + } + + return temp; } + + +static void * +sc1502x_ramdac_init(const device_t *info) +{ + sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) malloc(sizeof(sc1502x_ramdac_t)); + memset(ramdac, 0, sizeof(sc1502x_ramdac_t)); + + return ramdac; +} + + +static void +sc1502x_ramdac_close(void *priv) +{ + sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + + +const device_t sc1502x_ramdac_device = +{ + "Sierra SC1502x RAMDAC", + 0, 0, + sc1502x_ramdac_init, sc1502x_ramdac_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_sc1502x_ramdac.h b/src/video/vid_sc1502x_ramdac.h index 2aaccb391..a5dcd234c 100644 --- a/src/video/vid_sc1502x_ramdac.h +++ b/src/video/vid_sc1502x_ramdac.h @@ -1,11 +1,30 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ -typedef struct unk_ramdac_t +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header of the emulation of a Sierra SC1502X RAMDAC. + * + * Used by the TLIVESA1 driver for ET4000. + * + * Version: @(#)vid_sc1502x_ramdac.h 1.0.0 2018/10/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +typedef struct { - int state; - uint8_t ctrl; + int state; + uint8_t ctrl; } sc1502x_ramdac_t; -void sc1502x_ramdac_out(uint16_t addr, uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga); -uint8_t sc1502x_ramdac_in(uint16_t addr, sc1502x_ramdac_t *ramdac, svga_t *svga); +extern void sc1502x_ramdac_out(uint16_t addr, uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga); +extern uint8_t sc1502x_ramdac_in(uint16_t addr, sc1502x_ramdac_t *ramdac, svga_t *svga); + +extern const device_t sc1502x_ramdac_device; diff --git a/src/video/vid_sdac_ramdac.c b/src/video/vid_sdac_ramdac.c index 95742e26a..44fb8d752 100644 --- a/src/video/vid_sdac_ramdac.c +++ b/src/video/vid_sdac_ramdac.c @@ -8,176 +8,239 @@ * * 87C716 'SDAC' true colour RAMDAC emulation. * - * Version: @(#)vid_sdac_ramdac.c 1.0.3 2018/03/21 + * Version: @(#)vid_sdac_ramdac.c 1.0.6 2019/09/13 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include +#include #include #include #include "../86box.h" +#include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_sdac_ramdac.h" -static void sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val) -{ - ramdac->command = 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; - } +static void +sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val) +{ + ramdac->command = val; + switch (val >> 4) { + case 0x2: + case 0x3: + case 0xa: + case 0x8: + svga->bpp = 15; + break; + case 0x4: + case 0x9: + case 0xe: + svga->bpp = 24; + break; + case 0x5: + case 0x6: + case 0xc: + svga->bpp = 16; + break; + case 0x7: + svga->bpp = 32; + break; + case 0x0: + case 0x1: + default: + svga->bpp = 8; + break; + } } -static void sdac_reg_write(sdac_ramdac_t *ramdac, int reg, uint8_t val) + +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++; + 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; +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) -{ - 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); - } +void +sdac_ramdac_out(uint16_t addr, int rs2, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t rs = (addr & 0x03); + rs |= (!!rs2 << 8); + + if ((rs >= 0x04) || (ramdac->type == 7)) switch (rs) { + case 0x02: + if (ramdac->magic_count == 4) + sdac_control_write(ramdac, svga, val); + /* Fall through. */ + case 0x00: + case 0x01: + case 0x03: + ramdac->magic_count = 0; + break; + case 0x04: + ramdac->windex = val; + ramdac->reg_ff = 0; + break; + case 0x05: + sdac_reg_write(ramdac, ramdac->windex & 0xff, val); + break; + case 0x06: + sdac_control_write(ramdac, svga, val); + break; + case 0x07: + ramdac->rindex = val; + ramdac->reg_ff = 0; + break; + } + + svga_out(addr, val, svga); } -uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) -{ - uint8_t temp; - switch (addr) - { - case 2: - if (ramdac->magic_count < 5) - ramdac->magic_count++; - if (ramdac->magic_count == 4) - { - temp = 0x70; /*SDAC ID*/ - ramdac->rs2 = 1; - } - if (ramdac->magic_count == 5) - { - temp = ramdac->command; - ramdac->magic_count = 0; - } - return temp; - case 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; - } - if (!(addr & 4)) - { - if (addr < 2) - return svga_in(addr + 0x3c8, svga); - else - return svga_in(addr + 0x3c4, svga); - } - return 0xff; +uint8_t +sdac_ramdac_in(uint16_t addr, int rs2, sdac_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp = 0xff; + uint8_t rs = (addr & 0x03); + rs |= (!!rs2 << 8); + + if ((rs < 0x04) && (ramdac->type != 7)) + temp = svga_in(addr, svga); + else switch (rs) { + case 0x02: + if (ramdac->magic_count < 5) + ramdac->magic_count++; + if (ramdac->magic_count == 4) + temp = 0x70; /*SDAC ID*/ + else if (ramdac->magic_count == 5) { + temp = ramdac->command; + ramdac->magic_count = 0; + } else + temp = svga_in(addr, svga); + break; + case 0x00: + case 0x01: + case 0x03: + ramdac->magic_count = 0; + temp = svga_in(addr, svga); + break; + case 0x04: + temp = ramdac->windex; + break; + case 0x05: + temp = sdac_reg_read(ramdac, ramdac->rindex & 0xff); + break; + case 0x06: + temp = ramdac->command; + break; + case 0x07: + temp = ramdac->rindex; + break; + } + + return temp; } -float sdac_getclock(int clock, void *p) + +float +sdac_getclock(int clock, void *p) { - sdac_ramdac_t *ramdac = (sdac_ramdac_t *)p; - float t; - int m, n1, n2; - if (clock == 0) return 25175000.0; - if (clock == 1) return 28322000.0; - clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ - m = (ramdac->regs[clock] & 0x7f) + 2; - n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; - n2 = ((ramdac->regs[clock] >> 13) & 0x07); - t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); - return t; + 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; + + clock &= 7; + + if (clock == 0) + return 25175000.0; + if (clock == 1) + return 28322000.0; + + m = (ramdac->regs[clock] & 0x7f) + 2; + n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; + n2 = ((ramdac->regs[clock] >> 13) & 0x07); + n2 = (1 << n2); + t = (14318184.0f * (float)m) / (float)(n1 * n2); + + return t; } -void sdac_init(sdac_ramdac_t *ramdac) + +void * +sdac_ramdac_init(const device_t *info) { - ramdac->regs[0] = 0x6128; - ramdac->regs[1] = 0x623d; + sdac_ramdac_t *ramdac = (sdac_ramdac_t *) malloc(sizeof(sdac_ramdac_t)); + memset(ramdac, 0, sizeof(sdac_ramdac_t)); + + ramdac->type = info->local; + + ramdac->regs[0] = 0x6128; + ramdac->regs[1] = 0x623d; + + return ramdac; } + + +static void +sdac_ramdac_close(void *priv) +{ + sdac_ramdac_t *ramdac = (sdac_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + + +const device_t gendac_ramdac_device = +{ + "S3 GENDAC 86c708 RAMDAC", + 0, 0, + sdac_ramdac_init, sdac_ramdac_close, + NULL, NULL, NULL, NULL +}; + + +const device_t sdac_ramdac_device = +{ + "S3 SDAC 86c716 RAMDAC", + 0, 7, + sdac_ramdac_init, sdac_ramdac_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_sdac_ramdac.h b/src/video/vid_sdac_ramdac.h index 52d908599..e57d24519 100644 --- a/src/video/vid_sdac_ramdac.h +++ b/src/video/vid_sdac_ramdac.h @@ -1,19 +1,33 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * 87C716 'SDAC' true colour RAMDAC emulation header. + * + * Version: @(#)vid_sdac_ramdac.h 1.0.1 2019/09/13 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ typedef struct sdac_ramdac_t { - int magic_count; - uint8_t command; - int windex, rindex; - uint16_t regs[256]; - int reg_ff; - int rs2; + uint16_t regs[256]; + int magic_count, + windex, rindex, + reg_ff, rs2; + uint8_t type, command; } sdac_ramdac_t; -void sdac_init(sdac_ramdac_t *ramdac); +extern void sdac_ramdac_out(uint16_t addr, int rs2, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga); +extern uint8_t sdac_ramdac_in(uint16_t addr, int rs2, sdac_ramdac_t *ramdac, svga_t *svga); +extern float sdac_getclock(int clock, void *p); -void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga); -uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga); - -float sdac_getclock(int clock, void *p); +extern const device_t gendac_ramdac_device; +extern const device_t sdac_ramdac_device; diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c new file mode 100644 index 000000000..3ad4a2a54 --- /dev/null +++ b/src/video/vid_sigma.c @@ -0,0 +1,972 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Sigma Color 400 emulation. + * + * Version: @(#)vid_sigma.c 1.0.5 2019/11/08 + * + * Authors: John Elliott, + * + * Copyright 2018 John Elliott. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../timer.h" +#include "../pit.h" +#include "../mem.h" +#include "../nmi.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_sigma.h" + + +#define ROM_SIGMA_FONT L"roms/video/sigma/sigma400_font.rom" +#define ROM_SIGMA_BIOS L"roms/video/sigma/sigma400_bios.rom" + +/* 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, bios_ram; + rom_t bios_rom; + + uint8_t crtc[32]; /* CRTC: Real values */ + + 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 */ + + uint8_t sigmastat, /* Status register [0x2DA] */ + fake_stat; /* see sigma_in() for comment */ + + uint8_t sigmamode; /* Mode control register [0x2D8] */ + + uint16_t ma, maback; + + int crtcreg; /* CRTC: Real selected register */ + + int linepos, displine; + int sc, vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + int oddeven; + + uint64_t dispontime, dispofftime; + + int firstline, lastline; + + int drawcursor; + + pc_timer_t timer; + + 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 +}; + +static video_timings_t timing_sigma = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + + +static void sigma_recalctimings(sigma_t *cga); + +static void +sigma_out(uint16_t addr, uint8_t val, void *p) +{ + sigma_t *sigma = (sigma_t *)p; + uint8_t old; + + 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; + } + /* 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]; + if (old != val) { + if (sigma->crtcreg < 0xe || sigma->crtcreg > 0x10) { + fullchange = changeframecount; + sigma_recalctimings(sigma); + } + } + return; + + case 0x2D8: + sigma->sigmamode = val; + return; + case 0x2D9: + sigma->sigma_ctl = val; + return; + case 0x2DB: + sigma->lastport &= 0x7F; + return; + case 0x2DC: /* Reset NMI */ + nmi = 0; + sigma->lastport &= 0x7F; + return; + case 0x2DD: /* Page in RAM at 0xC1800 */ + if (sigma->rom_paged != 0) + mmu_invalidate(0xC0000); + sigma->rom_paged = 0x00; + return; + + case 0x2DE: + if (sigma->sigma_ctl & CTL_PALETTE) + sigma->palette[val >> 4] = (val & 0x0F) ^ 0x0F; + else + sigma->plane = val & 3; + return; + } +} + + +static 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 */ + 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: + if (sigma->sigmamode & MODE_ENABLE) { + result = sigma->sigmastat & 0x07; + if (sigma->sigmastat & STATUS_RETR_V) + result |= 0x08; + } else { + /* + * The card is not running yet, and someone + * (probably the system BIOS) is trying to + * read our status in CGA mode. + * + * One of the systems that do this, is the + * DTK XT (PIM-10TB-Z board) with ERSO 2.42 + * BIOS. If this test fails (i.e. it doesnt + * see valid HS and VS bits alternate) it + * will generate lots of annoying beeps.. + * + * So, the trick here is to just send it + * some alternating bits, making it think + * the CGA circuitry is operational. + */ + sigma->fake_stat ^= (0x08 | 0x01); + result = sigma->fake_stat; + } + break; + } + + return result; +} + + +static void +sigma_write(uint32_t addr, uint8_t val, void *p) +{ + sigma_t *sigma = (sigma_t *)p; + + sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)] = val; + egawrites++; + sub_cycles(4); +} + + +static uint8_t +sigma_read(uint32_t addr, void *p) +{ + sigma_t *sigma = (sigma_t *)p; + + sub_cycles(4); + egareads++; + return sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)]; +} + + +static 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)) + ; + else + sigma->bram[addr & 0x7FF] = val; +} + + +static uint8_t +sigma_bread(uint32_t addr, void *p) +{ + sigma_t *sigma = (sigma_t *)p; + uint8_t result; + + addr &= 0x3FFF; + if (addr >= 0x2000) + return 0xFF; + if (addr < 0x1800 || sigma->rom_paged) + result = sigma->bios_rom.rom[addr & 0x1FFF]; + else + result = sigma->bram[addr & 0x7FF]; + + return result; +} + + +static void +sigma_recalctimings(sigma_t *sigma) +{ + double disptime; + double _dispontime, _dispofftime; + + 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; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + sigma->dispontime = (uint64_t)(_dispontime); + sigma->dispofftime = (uint64_t)(_dispofftime); +} + + +/* Render a line in 80-column text mode */ +static 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 << 1) & 0x3FFF); + int drawcursor; + uint32_t cols[4]; + uint8_t *vram = sigma->vram + (ma & 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) | 16; + cols[0] = ((attr >> 4) & 7) | 16; + if ((sigma->cgablink & 8) && (attr & 0x80) && !sigma->drawcursor) + cols[1] = cols[0]; + } else { /* No blink */ + cols[1] = (attr & 15) | 16; + cols[0] = (attr >> 4) | 16; + } + + if (drawcursor) { + for (c = 0; c < 8; c++) { + if (sigma->sigmamode & MODE_FONT16) + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; + else + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdat[chr][sigma->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; + } + } else { + for (c = 0; c < 8; c++) { + if (sigma->sigmamode & MODE_FONT16) + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + else + 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]; +} + + +/* Render a line in 40-column text mode */ +static 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 << 1) & 0x3FFF); + int drawcursor; + uint32_t cols[4]; + uint8_t *vram = sigma->vram + (ma & 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) | 16; + cols[0] = ((attr >> 4) & 7) | 16; + if ((sigma->cgablink & 8) && (attr & 0x80) && !sigma->drawcursor) + cols[1] = cols[0]; + } else { /* No blink */ + cols[1] = (attr & 15) | 16; + cols[0] = (attr >> 4) | 16; + } + + if (drawcursor) { + for (c = 0; c < 8; c++) { + buffer32->line[sigma->displine][(x << 4) + 2*c + 8] = + buffer32->line[sigma->displine][(x << 4) + 2*c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; + } + } else { + for (c = 0; c < 8; c++) { + buffer32->line[sigma->displine][(x << 4) + 2*c + 8] = + 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]; +} + + +/* Draw a line in the 640x400 graphics mode */ +static 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); + col |= 16; + 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. */ +static 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); + col |= 16; + buffer32->line[sigma->displine][(x << 3) + c + 8] = col; + } + + if (x & 1) + ++sigma->ma; + } +} + + +/* Draw a line in the 320x200 graphics mode */ +static 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); + col |= 16; + mask = mask >> 1; + + buffer32->line[sigma->displine][(x << 3) + (c << 1) + 8] = + buffer32->line[sigma->displine][(x << 3) + (c << 1) + 9] = col; + } + + if (x & 1) + ++sigma->ma; + } +} + + +static 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(); + } + sigma->lastline = sigma->displine; + + cols[0] = 16; + /* Left overscan */ + for (c = 0; c < 8; c++) { + buffer32->line[sigma->displine][c] = cols[0]; + if (sigma->sigmamode & MODE_80COLS) + buffer32->line[sigma->displine][c + (sigma->crtc[1] << 4) + 8] = cols[0]; + else + 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] = 16; + 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++) + buffer32->line[sigma->displine][c] = sigma->palette[buffer32->line[sigma->displine][c] & 0xf] | 16; + + 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) || + video_force_resize_get()) { + xsize = x; + ysize = sigma->lastline - sigma->firstline; + if (xsize < 64) + xsize = 656; + if (ysize < 32) + ysize = 200; + if (ysize <= 250) + set_screen_size(xsize, (ysize << 1) + 16); + else + set_screen_size(xsize, ysize + 8); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + video_blit_memtoscreen_8(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; + } +} + + +static void +*sigma_init(const device_t *info) +{ + int bios_addr; + sigma_t *sigma = malloc(sizeof(sigma_t)); + memset(sigma, 0, sizeof(sigma_t)); + + bios_addr = device_get_config_hex20("bios_addr"); + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_sigma); + + sigma->enable_nmi = device_get_config_int("enable_nmi"); + + loadfont(ROM_SIGMA_FONT, 7); + rom_init(&sigma->bios_rom, ROM_SIGMA_BIOS, bios_addr, 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); + memcpy(sigma->bram, &sigma->bios_rom.rom[0x1800], 0x800); + + 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, bios_addr, 0x2000, + 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; + + cga_palette = device_get_config_int("rgb_type") << 1; + if (cga_palette > 6) + cga_palette = 0; + cgapal_rebuild(); + + if (sigma->enable_nmi) + sigma->sigmastat = STATUS_LPEN_T; + + return sigma; +} + + +static int +sigma_available(void) +{ + return((rom_present(ROM_SIGMA_FONT) && rom_present(ROM_SIGMA_BIOS))); +} + + +static 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[] = +{ + { + "rgb_type", "RGB type", CONFIG_SELECTION, "", 0, + { + { + "Color", 0 + }, + { + "Green Monochrome", 1 + }, + { + "Amber Monochrome", 2 + }, + { + "Gray Monochrome", 3 + }, + { + "Color (no brown)", 4 + }, + { + "" + } + } + }, + { + "enable_nmi", "Enable NMI for CGA emulation", CONFIG_BINARY, "", 1 + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xc0000, + { + { + "C000H", 0xc0000 + }, + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D000H", 0xd0000 + }, + { + "D400H", 0xd4000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "E000H", 0xe0000 + }, + { + "E400H", 0xe4000 + }, + { + "E800H", 0xe8000 + }, + { + "EC00H", 0xec000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +const device_t sigma_device = +{ + "Sigma Color 400", + DEVICE_ISA, 0, + sigma_init, + sigma_close, + NULL, + sigma_available, + sigma_speed_changed, + NULL, + sigma_config +}; diff --git a/src/video/vid_sigma.h b/src/video/vid_sigma.h new file mode 100644 index 000000000..e331ad753 --- /dev/null +++ b/src/video/vid_sigma.h @@ -0,0 +1,2 @@ +extern const device_t sigma_device; + diff --git a/src/video/vid_stg_ramdac.c b/src/video/vid_stg_ramdac.c index 37b1b5a2a..75722ef5a 100644 --- a/src/video/vid_stg_ramdac.c +++ b/src/video/vid_stg_ramdac.c @@ -8,7 +8,7 @@ * * STG1702 true colour RAMDAC emulation. * - * Version: @(#)vid_stg_ramdac.c 1.0.4 2018/01/25 + * Version: @(#)vid_stg_ramdac.c 1.0.5 2018/10/04 * * Authors: Sarah Walker, * Miran Grca, @@ -18,10 +18,13 @@ */ #include #include +#include #include #include #include "../86box.h" +#include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_stg_ramdac.h" @@ -31,151 +34,213 @@ static int stg_state_read[2][8] = {{1,2,3,4,0,0,0,0}, {1,2,3,4,5,6,7,7}}; static int stg_state_write[8] = {0,0,0,0,0,6,7,7}; -void stg_ramdac_set_bpp(svga_t *svga, stg_ramdac_t *ramdac) +void +stg_ramdac_set_bpp(svga_t *svga, stg_ramdac_t *ramdac) { - if (ramdac->command & 0x8) - { - switch (ramdac->regs[3]) - { - case 0: case 5: case 7: svga->bpp = 8; break; - case 1: case 2: case 8: svga->bpp = 15; break; - case 3: case 6: svga->bpp = 16; break; - case 4: case 9: svga->bpp = 24; break; - default: svga->bpp = 8; break; - } + if (ramdac->command & 0x8) { + switch (ramdac->regs[3]) { + case 0: + case 5: + case 7: + default: + svga->bpp = 8; + break; + case 1: + case 2: + case 8: + svga->bpp = 15; + break; + case 3: + case 6: + svga->bpp = 16; + break; + case 4: + case 9: + svga->bpp = 24; + break; } - else - { - switch (ramdac->command >> 5) - { - case 0: svga->bpp = 8; break; - case 5: svga->bpp = 15; break; - case 6: svga->bpp = 16; break; - case 7: svga->bpp = 24; break; - default: svga->bpp = 8; break; - } + } else { + switch (ramdac->command >> 5) { + case 0: + default: + svga->bpp = 8; + break; + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 16; + break; + case 7: + svga->bpp = 24; + break; } - svga_recalctimings(svga); + } + + svga_recalctimings(svga); } -void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga) + +void +stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga) { - int didwrite, old; - switch (addr) - { - case 0x3c6: - switch (ramdac->magic_count) - { + int didwrite, old; + + switch (addr) { + case 0x3c6: + switch (ramdac->magic_count) { /* 0 = PEL mask register */ - case 0: case 1: case 2: case 3: - break; - case 4: /* REG06 */ - old = ramdac->command; - ramdac->command = val; - if ((old ^ val) & 8) - { - stg_ramdac_set_bpp(svga, ramdac); - } - else - { - if ((old ^ val) & 0xE0) - { - stg_ramdac_set_bpp(svga, ramdac); - } - } - break; - case 5: - ramdac->index = (ramdac->index & 0xff00) | val; - break; - case 6: - ramdac->index = (ramdac->index & 0xff) | (val << 8); - break; - case 7: - if (ramdac->index < 0x100) - { - ramdac->regs[ramdac->index] = val; - } - if ((ramdac->index == 3) && (ramdac->command & 8)) stg_ramdac_set_bpp(svga, ramdac); - ramdac->index++; - break; - } - didwrite = (ramdac->magic_count >= 4); - ramdac->magic_count = stg_state_write[ramdac->magic_count & 7]; - if (didwrite) return; - break; - case 0x3c7: case 0x3c8: case 0x3c9: - ramdac->magic_count=0; - break; - } - svga_out(addr, val, svga); -} - -uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga) -{ - uint8_t temp = 0xff; - switch (addr) - { - case 0x3c6: - switch (ramdac->magic_count) - { - case 0: case 1: case 2: case 3: - temp = 0xff; - break; - case 4: - temp = ramdac->command; - break; - case 5: - temp = ramdac->index & 0xff; - break; - case 6: - temp = ramdac->index >> 8; - break; - case 7: - switch (ramdac->index) - { - case 0: - temp = 0x44; - break; - case 1: - temp = 0x03; - break; - case 7: - temp = 0x88; + case 0: + case 1: + case 2: + case 3: break; - default: - if (ramdac->index < 0x100) temp = ramdac->regs[ramdac->index]; - else temp = 0xff; - break; - } - ramdac->index++; - break; - } - ramdac->magic_count = stg_state_read[(ramdac->command & 0x10) ? 1 : 0][ramdac->magic_count & 7]; - return temp; - case 0x3c7: case 0x3c8: case 0x3c9: - ramdac->magic_count=0; - break; - } - return svga_in(addr, svga); + case 4: /* REG06 */ + old = ramdac->command; + ramdac->command = val; + if ((old ^ val) & 8) + stg_ramdac_set_bpp(svga, ramdac); + else { + if ((old ^ val) & 0xE0) + stg_ramdac_set_bpp(svga, ramdac); + } + break; + case 5: + ramdac->index = (ramdac->index & 0xff00) | val; + break; + case 6: + ramdac->index = (ramdac->index & 0xff) | (val << 8); + break; + case 7: + if (ramdac->index < 0x100) + ramdac->regs[ramdac->index] = val; + if ((ramdac->index == 3) && (ramdac->command & 8)) + stg_ramdac_set_bpp(svga, ramdac); + ramdac->index++; + break; + } + didwrite = (ramdac->magic_count >= 4); + ramdac->magic_count = stg_state_write[ramdac->magic_count & 7]; + if (didwrite) + return; + break; + case 0x3c7: + case 0x3c8: + case 0x3c9: + ramdac->magic_count=0; + break; + } + + svga_out(addr, val, svga); } -float stg_getclock(int clock, void *p) + +uint8_t +stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga) { - stg_ramdac_t *ramdac = (stg_ramdac_t *)p; - float t; - int m, n, n2; - float b, n1, d; - uint16_t *c; - if (clock == 0) return 25175000.0; - if (clock == 1) return 28322000.0; - clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ - c = (uint16_t *) &ramdac->regs[0x20 + (clock << 1)]; - m = (*c & 0xff) + 2; /* B+2 */ - n = ((*c >> 8) & 0x1f) + 2; /* N1+2 */ - n2 = ((*c >> 13) & 0x07); /* D */ - b = (float) m; - n1 = (float) n; - d = (double) (1 << n2); - t = (14318184.0 * (b / d)) / n1; - return t; + uint8_t temp = 0xff; + + switch (addr) { + case 0x3c6: + switch (ramdac->magic_count) { + case 0: + case 1: + case 2: + case 3: + temp = 0xff; + break; + case 4: + temp = ramdac->command; + break; + case 5: + temp = ramdac->index & 0xff; + break; + case 6: + temp = ramdac->index >> 8; + break; + case 7: + switch (ramdac->index) { + case 0: + temp = 0x44; + break; + case 1: + temp = 0x03; + break; + case 7: + temp = 0x88; + break; + default: + if (ramdac->index < 0x100) + temp = ramdac->regs[ramdac->index]; + else + temp = 0xff; + break; + } + ramdac->index++; + break; + } + ramdac->magic_count = stg_state_read[(ramdac->command & 0x10) ? 1 : 0][ramdac->magic_count & 7]; + return temp; + case 0x3c7: + case 0x3c8: + case 0x3c9: + ramdac->magic_count=0; + break; + } + + return svga_in(addr, svga); } + + +float +stg_getclock(int clock, void *p) +{ + stg_ramdac_t *ramdac = (stg_ramdac_t *)p; + float t; + int m, n, n2; + uint16_t *c; + + if (clock == 0) + return 25175000.0; + if (clock == 1) + return 28322000.0; + + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + c = (uint16_t *) &ramdac->regs[0x20 + (clock << 1)]; + m = (*c & 0xff) + 2; /* B+2 */ + n = ((*c >> 8) & 0x1f) + 2; /* N1+2 */ + n2 = ((*c >> 13) & 0x07); /* D */ + n2 = (1 << n2); + t = (14318184.0f * (float)m) / (float)(n * n2); + + return t; +} + + +static void * +stg_ramdac_init(const device_t *info) +{ + stg_ramdac_t *ramdac = (stg_ramdac_t *) malloc(sizeof(stg_ramdac_t)); + memset(ramdac, 0, sizeof(stg_ramdac_t)); + + return ramdac; +} + + +static void +stg_ramdac_close(void *priv) +{ + stg_ramdac_t *ramdac = (stg_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + + +const device_t stg_ramdac_device = +{ + "SGS-Thompson STG170x RAMDAC", + 0, 0, + stg_ramdac_init, stg_ramdac_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_stg_ramdac.h b/src/video/vid_stg_ramdac.h index 8e383ea17..76dbfcd3e 100644 --- a/src/video/vid_stg_ramdac.h +++ b/src/video/vid_stg_ramdac.h @@ -1,14 +1,30 @@ -/* Copyright holders: Sarah Walker, Tenshi - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * STG1702 true colour RAMDAC emulation header. + * + * Version: @(#)vid_stg_ramdac.h 1.0.0 2018/10/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ typedef struct stg_ramdac_t { - int magic_count; - uint8_t command; - int index; - uint8_t regs[256]; + int magic_count, index; + uint8_t regs[256]; + uint8_t command; } stg_ramdac_t; -void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga); -uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga); -float stg_getclock(int clock, void *p); +extern void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga); +extern uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga); +extern float stg_getclock(int clock, void *p); + +extern const device_t stg_ramdac_device; diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index cfb5e6d99..a07764f12 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,13 +11,13 @@ * This is intended to be used by another SVGA driver, * and not as a card in it's own right. * - * Version: @(#)vid_svga.c 1.0.31 2018/05/26 + * Version: @(#)vid_svga.c 1.0.40 2019/12/28 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -28,18 +28,16 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../machine/machine.h" +#include "../timer.h" #include "../io.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" -#define svga_output 0 - void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); extern int cyc_total; @@ -47,13 +45,6 @@ extern uint8_t edatlookup[4][4]; uint8_t svga_rotate[8][256]; -static const uint32_t mask16[16] = { - 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, - 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, - 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, - 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff -}; - /*Primary SVGA device. As multiple video cards are not yet supported this is the only SVGA device.*/ static svga_t *svga_pri; @@ -72,14 +63,23 @@ svga_set_override(svga_t *svga, int val) if (svga->override && !val) svga->fullchange = changeframecount; svga->override = val; -} + if (!val) { + /* Override turned off, restore overscan X and Y per the CRTC. */ + if (enable_overscan) { + overscan_y = (svga->rowcount + 1) << 1; -/* Used to add custom write modes, eg. by the CL-GD 54xx to add write modes 4 and 5. */ -void -svga_set_ven_write(svga_t *svga, void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr)) -{ - svga->ven_write = ven_write; + if (overscan_y < 16) + overscan_y = 16; + } + + overscan_x = (svga->seqregs[1] & 1) ? 16 : 18; + + if (svga->seqregs[1] & 8) + overscan_x <<= 1; + } else + overscan_x = overscan_y = 16; + /* Override turned off, fix overcan X and Y to 16. */ } @@ -88,7 +88,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; int c; - uint8_t o; + uint8_t o, index; switch (addr) { case 0x3c0: @@ -101,6 +101,8 @@ svga_out(uint16_t addr, uint8_t val, void *p) svga_recalctimings(svga); } } else { + if ((svga->attraddr == 0x13) && (svga->attrregs[0x13] != val)) + svga->fullchange = changeframecount; o = svga->attrregs[svga->attraddr & 31]; svga->attrregs[svga->attraddr & 31] = val; if (svga->attraddr < 16) @@ -159,7 +161,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) svga_recalctimings(svga); break; case 2: - svga->writemask = val & 0xf; + svga->writemask = val & 0xf; break; case 3: svga->charsetb = (((val >> 2) & 3) * 0x10000) + 2; @@ -173,24 +175,20 @@ svga_out(uint16_t addr, uint8_t val, void *p) 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->gdcreg[1]) && svga->chain4 && !(svga->adv_flags & FLAG_ADDR_BY8); break; } break; case 0x3c6: svga->dac_mask = val; break; - case 0x3C7: - svga->dac_read = val; - svga->dac_pos = 0; - break; - case 0x3c8: - svga->dac_write = val; - svga->dac_read = val - 1; - svga->dac_pos = 0; + case 0x3c7: + case 0x3c8: + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = (val + (addr & 0x01)) & 255; break; case 0x3c9: - svga->dac_status = 0; svga->fullchange = changeframecount; switch (svga->dac_pos) { case 0: @@ -202,15 +200,16 @@ 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].g = svga->dac_g; - svga->vgapal[svga->dac_write].b = val; + index = svga->dac_addr & 255; + svga->vgapal[index].r = svga->dac_r; + svga->vgapal[index].g = svga->dac_g; + svga->vgapal[index].b = val; if (svga->ramdac_type == RAMDAC_8BIT) - svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); + svga->pallook[index] = makecol32(svga->vgapal[index].r, svga->vgapal[index].g, svga->vgapal[index].b); else - svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f], video_6to8[svga->vgapal[index].g & 0x3f], video_6to8[svga->vgapal[index].b & 0x3f]); svga->dac_pos = 0; - svga->dac_write = (svga->dac_write + 1) & 255; + svga->dac_addr = (svga->dac_addr + 1) & 255; break; } break; @@ -221,7 +220,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) o = svga->gdcreg[svga->gdcaddr & 15]; switch (svga->gdcaddr & 15) { case 2: - svga->colourcompare=val; + svga->colourcompare = val; break; case 4: svga->readplane = val & 3; @@ -254,7 +253,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) } break; case 7: - svga->colournocare=val; + svga->colournocare = val; break; } svga->gdcreg[svga->gdcaddr & 15] = val; @@ -272,7 +271,7 @@ uint8_t svga_in(uint16_t addr, void *p) { svga_t *svga = (svga_t *)p; - uint8_t ret = 0xff; + uint8_t index, ret = 0xff; switch (addr) { case 0x3c0: @@ -300,32 +299,32 @@ svga_in(uint16_t addr, void *p) ret = svga->dac_status; break; case 0x3c8: - ret = svga->dac_write; + ret = svga->dac_addr; break; case 0x3c9: - svga->dac_status = 3; + index = (svga->dac_addr - 1) & 255; switch (svga->dac_pos) { case 0: svga->dac_pos++; if (svga->ramdac_type == RAMDAC_8BIT) - ret = svga->vgapal[svga->dac_read].r; + ret = svga->vgapal[index].r; else - ret = svga->vgapal[svga->dac_read].r & 0x3f; + ret = svga->vgapal[index].r & 0x3f; break; case 1: svga->dac_pos++; if (svga->ramdac_type == RAMDAC_8BIT) - ret = svga->vgapal[svga->dac_read].g; + ret = svga->vgapal[index].g; else - ret = svga->vgapal[svga->dac_read].g & 0x3f; + ret = svga->vgapal[index].g & 0x3f; break; case 2: svga->dac_pos=0; - svga->dac_read = (svga->dac_read + 1) & 255; + svga->dac_addr = (svga->dac_addr + 1) & 255; if (svga->ramdac_type == RAMDAC_8BIT) - ret = svga->vgapal[(svga->dac_read - 1) & 255].b; + ret = svga->vgapal[index].b; else - ret = svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + ret = svga->vgapal[index].b & 0x3f; break; } break; @@ -339,16 +338,16 @@ svga_in(uint16_t addr, void *p) /* The spec says GDC addresses 0xF8 to 0xFB return the latch. */ switch(svga->gdcaddr) { case 0xf8: - ret = (svga->latch & 0xFF); + ret = svga->latch.b[0]; break; case 0xf9: - ret = ((svga->latch & 0xFF00) >> 8); + ret = svga->latch.b[1]; break; case 0xfa: - ret = ((svga->latch & 0xFF0000) >> 16); + ret = svga->latch.b[2]; break; case 0xfb: - ret = ((svga->latch & 0xFF000000) >> 24); + ret = svga->latch.b[3]; break; default: ret = svga->gdcreg[svga->gdcaddr & 0xf]; @@ -357,7 +356,6 @@ svga_in(uint16_t addr, void *p) break; case 0x3da: svga->attrff = 0; - svga->attrff = 0; if (svga->cgastat & 0x01) svga->cgastat &= ~0x30; @@ -480,6 +478,7 @@ svga_recalctimings(svga_t *svga) case 0x40: case 0x60: /*256+ colours*/ switch (svga->bpp) { case 8: + svga->map8 = svga->pallook; if (svga->lowres) svga->render = svga_render_8bpp_lowres; else @@ -519,14 +518,25 @@ svga_recalctimings(svga_t *svga) svga->rowcount = svga->crtc[9] & 31; if (enable_overscan) { overscan_y = (svga->rowcount + 1) << 1; - if (svga->seqregs[1] & 8) /*Low res (320)*/ - overscan_y <<= 1; + if (overscan_y < 16) overscan_y = 16; } + + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { + overscan_x = (svga->seqregs[1] & 1) ? 16 : 18; + + if (svga->seqregs[1] & 8) + overscan_x <<= 1; + } else + overscan_x = 16; + if (svga->recalctimings_ex) svga->recalctimings_ex(svga); + svga->y_add = (overscan_y >> 1) - (svga->crtc[8] & 0x1f); + svga->x_add = (overscan_x >> 1); + if (svga->vblankstart < svga->dispend) svga->dispend = svga->vblankstart; @@ -539,12 +549,17 @@ svga_recalctimings(svga_t *svga) disptime *= 2; _dispontime *= 2; } + _dispofftime = disptime - _dispontime; _dispontime *= crtcconst; _dispofftime *= crtcconst; - svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + 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; } @@ -552,8 +567,9 @@ void svga_poll(void *p) { svga_t *svga = (svga_t *)p; - uint32_t x; + uint32_t x, blink_delay; int wx, wy; + int skip = (svga->crtc[8] >> 5) & 0x03; if (!svga->linepos) { if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { @@ -567,6 +583,17 @@ svga_poll(void *p) svga->hwcursor_oddeven = 1; } + if (svga->displine == svga->dac_hwcursor_latch.y && svga->dac_hwcursor_latch.ena) { + svga->dac_hwcursor_on = 64 - svga->dac_hwcursor_latch.yoff; + svga->dac_hwcursor_oddeven = 0; + } + + if (svga->displine == (svga->dac_hwcursor_latch.y + 1) && svga->dac_hwcursor_latch.ena && + svga->interlace) { + svga->dac_hwcursor_on = 64 - (svga->dac_hwcursor_latch.yoff + 1); + svga->dac_hwcursor_oddeven = 1; + } + if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 0; @@ -577,12 +604,12 @@ svga_poll(void *p) svga->overlay_oddeven = 1; } - svga->vidtime += svga->dispofftime; + timer_advance_u64(&svga->timer, svga->dispofftime); svga->cgastat |= 1; svga->linepos = 1; if (svga->dispon) { - svga->hdisp_on=1; + svga->hdisp_on = 1; svga->ma &= svga->vram_display_mask; if (svga->firstline == 2000) { @@ -590,25 +617,39 @@ svga_poll(void *p) video_wait_for_buffer(); } - if (svga->hwcursor_on || svga->overlay_on) { + if (svga->hwcursor_on || svga->dac_hwcursor_on || svga->overlay_on) { svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = svga->interlace ? 3 : 2; } - if (!svga->override) + if (!svga->override) { svga->render(svga); + svga->x_add = (overscan_x >> 1); + svga_render_overscan_left(svga); + svga_render_overscan_right(svga); + svga->x_add = (overscan_x >> 1) - svga->scrollcache; + } + if (svga->overlay_on) { - if (!svga->override) - svga->overlay_draw(svga, svga->displine); + if (!svga->override && svga->overlay_draw) + svga->overlay_draw(svga, svga->displine + svga->y_add); svga->overlay_on--; if (svga->overlay_on && svga->interlace) svga->overlay_on--; } + if (svga->dac_hwcursor_on) { + if (!svga->override && svga->dac_hwcursor_draw) + svga->dac_hwcursor_draw(svga, svga->displine + svga->y_add); + svga->dac_hwcursor_on--; + if (svga->dac_hwcursor_on && svga->interlace) + svga->dac_hwcursor_on--; + } + if (svga->hwcursor_on) { - if (!svga->override) - svga->hwcursor_draw(svga, svga->displine); + if (!svga->override && svga->hwcursor_draw) + svga->hwcursor_draw(svga, svga->displine + svga->y_add); svga->hwcursor_on--; if (svga->hwcursor_on && svga->interlace) svga->hwcursor_on--; @@ -627,14 +668,14 @@ svga_poll(void *p) if (svga->displine > 1500) svga->displine = 0; } else { - svga->vidtime += svga->dispontime; + timer_advance_u64(&svga->timer, svga->dispontime); if (svga->dispon) svga->cgastat &= ~1; svga->hdisp_on = 0; svga->linepos = 0; - if (svga->sc == (svga->crtc[11] & 31)) + if ((svga->sc == (svga->crtc[11] & 31)) || (svga->sc == svga->rowcount)) svga->con = 0; if (svga->dispon) { if (svga->linedbl && !svga->linecountff) { @@ -661,21 +702,27 @@ svga_poll(void *p) if (svga->vc == svga->split) { svga->ma = svga->maback = 0; - if (svga->attrregs[0x10] & 0x20) + svga->sc = 0; + if (svga->attrregs[0x10] & 0x20) { svga->scrollcache = 0; + svga->x_add = (overscan_x >> 1); + } } if (svga->vc == svga->dispend) { if (svga->vblank_start) svga->vblank_start(svga); - svga->dispon=0; + svga->dispon = 0; + blink_delay = (svga->crtc[11] & 0x60) >> 5; if (svga->crtc[10] & 0x20) svga->cursoron = 0; + else if (blink_delay == 2) + svga->cursoron = ((svga->blink % 96) >= 48); else - svga->cursoron = svga->blink & 16; + svga->cursoron = svga->blink & (16 + (16 * blink_delay)); if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) svga->fullchange = 2; - svga->blink++; + svga->blink = (svga->blink + 1) & 0x7f; for (x = 0; x < ((svga->vram_mask + 1) >> 12); x++) { if (svga->changedvram[x]) @@ -697,7 +744,7 @@ svga_poll(void *p) wx = x; wy = svga->lastline - svga->firstline; - if (!svga->override) + if (!svga->override/* && (wx > 0) && (wy > 0)*/) svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); svga->firstline = 2000; @@ -717,41 +764,44 @@ svga_poll(void *p) svga->ma = svga->maback = svga->ma_latch; svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf]; - svga->ma <<= 2; - svga->maback <<= 2; - svga->ca <<= 2; - - svga->video_res_x = wx; - svga->video_res_y = wy + 1; - if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; - svga->video_res_y /= (svga->crtc[9] & 31) + 1; - svga->video_bpp = 0; - } else { - if (svga->crtc[9] & 0x80) - svga->video_res_y /= 2; - if (!(svga->crtc[0x17] & 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->lowres) - svga->video_res_x /= 2; - - svga->video_bpp = svga->bpp; - } + svga->ma = (svga->ma << 2) + (skip << 2); + svga->maback = (svga->maback << 2) + (skip << 2); + svga->ca = (svga->ca << 2) + (skip << 2); } if (svga->vc == svga->vtotal) { svga->vc = 0; - svga->sc = svga->crtc[8] & 0x1f; + svga->sc = 0; svga->dispon = 1; svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; - svga->scrollcache = svga->attrregs[0x13] & 7; + + svga->scrollcache = (svga->attrregs[0x13] & 0x0f); + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 1) + svga->scrollcache &= 0x07; + else { + svga->scrollcache++; + if (svga->scrollcache > 8) + svga->scrollcache = 0; + } + } else if ((svga->render == svga_render_2bpp_lowres) || (svga->render == svga_render_2bpp_highres) || + (svga->render == svga_render_4bpp_lowres) || (svga->render == svga_render_4bpp_highres)) + svga->scrollcache &= 0x07; + else + svga->scrollcache = (svga->scrollcache & 0x06) >> 1; + + if ((svga->seqregs[1] & 8) || (svga->render == svga_render_8bpp_lowres)) + svga->scrollcache <<= 1; + + svga->x_add = (overscan_x >> 1) - svga->scrollcache; + svga->linecountff = 0; svga->hwcursor_on = 0; svga->hwcursor_latch = svga->hwcursor; + svga->dac_hwcursor_on = 0; + svga->dac_hwcursor_latch = svga->dac_hwcursor; + svga->overlay_on = 0; svga->overlay_latch = svga->overlay; } @@ -787,10 +837,13 @@ svga_init(svga_t *svga, void *p, int memsize, overscan_x = 16; overscan_y = 32; + svga->x_add = 8; + svga->y_add = 16; svga->crtc[0] = 63; svga->crtc[6] = 255; - svga->dispontime = svga->dispofftime = 1000 * (1 << TIMER_SHIFT); + svga->dispontime = 1000ull << 32; + svga->dispofftime = 1000ull << 32; svga->bpp = 8; svga->vram = malloc(memsize); svga->vram_max = memsize; @@ -803,17 +856,25 @@ svga_init(svga_t *svga, void *p, int memsize, svga->hwcursor_draw = hwcursor_draw; svga->overlay_draw = overlay_draw; + svga->hwcursor.xsize = svga->hwcursor.ysize = 32; + svga->hwcursor.yoff = 32; + + svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = 32; + svga->dac_hwcursor.yoff = 32; + 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; svga->ramdac_type = RAMDAC_6BIT; + svga->map8 = svga->pallook; + return 0; } @@ -828,27 +889,78 @@ svga_close(svga_t *svga) } +static uint32_t +svga_decode_addr(svga_t *svga, uint32_t addr, int write) +{ + int memory_map_mode = (svga->gdcreg[6] >> 2) & 3; + + addr &= 0x1ffff; + + switch (memory_map_mode) { + case 0: + break; + case 1: + if (addr >= 0x10000) + return 0xffffffff; + break; + case 2: + addr -= 0x10000; + if (addr >= 0x8000) + return 0xffffffff; + break; + default: + case 3: + addr -= 0x18000; + if (addr >= 0x8000) + return 0xffffffff; + break; + } + + if (memory_map_mode <= 1) { + if (svga->adv_flags & FLAG_EXTRA_BANKS) + addr = (addr & 0x17fff) + svga->extra_banks[(addr >> 15) & 1]; + else { + if (write) + addr += svga->write_bank; + else + addr += svga->read_bank; + } + } + + return addr; +} + + void svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) { svga_t *svga = (svga_t *)p; - int func_select, writemask2 = svga->writemask; - uint32_t write_mask, bit_mask, set_mask, val32 = (uint32_t) val; + int writemask2 = svga->writemask, reset_wm = 0; + latch_t vall; + uint8_t wm = svga->writemask; + uint8_t count, i; + + if (svga->adv_flags & FLAG_ADDR_BY8) + writemask2 = svga->seqregs[2]; egawrites++; - cycles -= video_timing_write_b; + sub_cycles(video_timing_write_b); if (!linear) { - addr &= svga->banked_mask; - addr += svga->write_bank; + addr = svga_decode_addr(svga, addr, 1); + + if (addr == 0xffffffff) + return; } if (!(svga->gdcreg[6] & 1)) svga->fullchange = 2; - if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) { + if ((svga->adv_flags & FLAG_ADDR_BY8) && (svga->writemode < 4)) + addr <<= 3; + else if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) { writemask2 = 1 << (addr & 3); addr &= ~3; } else if (svga->chain2_write) { @@ -859,6 +971,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) addr <<= 2; } else addr <<= 2; + addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -868,97 +981,93 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) svga->changedvram[addr >> 12] = changeframecount; - /* standard VGA latched access */ - func_select = (svga->gdcreg[3] >> 3) & 3; + count = 4; + if (svga->adv_flags & FLAG_LATCH8) + count = 8; switch (svga->writemode) { case 0: - /* rotate */ - if (svga->gdcreg[3] & 7) - val32 = svga_rotate[svga->gdcreg[3] & 7][val32]; - - /* apply set/reset mask */ - bit_mask = svga->gdcreg[8]; - - val32 |= (val32 << 8); - val32 |= (val32 << 16); - - if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && - (!svga->gdcreg[1] || svga->set_reset_disabled)) { - /* mask data according to sr[2] */ - write_mask = mask16[writemask2 & 0x0f]; - addr >>= 2; - ((uint32_t *)(svga->vram))[addr] &= ~write_mask; - ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + 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] || svga->set_reset_disabled)) { + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = val; + } return; + } else { + for (i = 0; i < count; i++) { + if (svga->gdcreg[1] & (1 << i)) + vall.b[i] = !!(svga->gdcreg[0] & (1 << i)) * 0xff; + else + vall.b[i] = val; + } } - - set_mask = mask16[svga->gdcreg[1] & 0x0f]; - val32 = (val32 & ~set_mask) | (mask16[svga->gdcreg[0] & 0x0f] & set_mask); break; case 1: - val32 = svga->latch; - - /* mask data according to sr[2] */ - write_mask = mask16[writemask2 & 0x0f]; - addr >>= 2; - ((uint32_t *)(svga->vram))[addr] &= ~write_mask; - ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = svga->latch.b[i]; + } return; case 2: - val32 = mask16[val32 & 0x0f]; - bit_mask = svga->gdcreg[8]; + for (i = 0; i < count; i++) + vall.b[i] = !!(val & (1 << i)) * 0xff; - if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) - func_select = 0; + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } + return; + } break; case 3: - /* rotate */ - if (svga->gdcreg[3] & 7) - val32 = svga_rotate[svga->gdcreg[3] & 7][val]; + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= val; - bit_mask = svga->gdcreg[8] & val32; - val32 = mask16[svga->gdcreg[0] & 0x0f]; - break; + for (i = 0; i < count; i++) + vall.b[i] = !!(svga->gdcreg[0] & (1 << i)) * 0xff; + + reset_wm = 1; + break; default: if (svga->ven_write) svga->ven_write(svga, val, addr); return; } - /* apply bit mask */ - bit_mask |= bit_mask << 8; - bit_mask |= bit_mask << 16; - - /* apply logical operation */ - switch(func_select) { - case 0: - default: - /* set */ - val32 &= bit_mask; - val32 |= (svga->latch & ~bit_mask); + switch (svga->gdcreg[3] & 0x18) { + case 0x00: /* Set */ + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } break; - case 1: - /* and */ - val32 |= ~bit_mask; - val32 &= svga->latch; + case 0x08: /* AND */ + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + } break; - case 2: - /* or */ - val32 &= bit_mask; - val32 |= svga->latch; + case 0x10: /* OR */ + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + } break; - case 3: - /* xor */ - val32 &= bit_mask; - val32 ^= svga->latch; + case 0x18: /* XOR */ + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + } break; } - /* mask data according to sr[2] */ - write_mask = mask16[writemask2 & 0x0f]; - addr >>= 2; - ((uint32_t *)(svga->vram))[addr] = (((uint32_t *)(svga->vram))[addr] & ~write_mask) | (val32 & write_mask); + if (reset_wm) + svga->gdcreg[8] = wm; } @@ -966,22 +1075,36 @@ uint8_t svga_read_common(uint32_t addr, uint8_t linear, void *p) { svga_t *svga = (svga_t *)p; - uint32_t latch_addr = 0, ret; + uint32_t latch_addr = 0; int readplane = svga->readplane; - uint8_t ret8; + uint8_t count, i; + uint8_t plane, pixel; + uint8_t temp, ret; - cycles -= video_timing_read_b; + if (svga->adv_flags & FLAG_ADDR_BY8) + readplane = svga->gdcreg[4] & 7; + + sub_cycles(video_timing_read_b); egareads++; if (!linear) { - addr &= svga->banked_mask; - addr += svga->read_bank; + addr = svga_decode_addr(svga, addr, 0); - latch_addr = (addr << 2) & svga->decode_mask; + if (addr == 0xffffffff) + return 0xff; } - if (svga->chain4 || svga->fb_only) { + count = 2; + if (svga->adv_flags & FLAG_LATCH8) + count = 3; + + latch_addr = (addr << count) & svga->decode_mask; + count = (1 << count); + + if (svga->adv_flags & FLAG_ADDR_BY8) + addr <<= 3; + else if (svga->chain4 || svga->fb_only) { addr &= svga->decode_mask; if (addr >= svga->vram_max) return 0xff; @@ -996,39 +1119,39 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) addr &= svga->decode_mask; /* standard VGA latched access */ - if (linear) { - if (addr >= svga->vram_max) - return 0xff; - - addr &= svga->vram_mask; - - svga->latch = ((uint32_t *)(svga->vram))[addr >> 2]; + if (latch_addr >= svga->vram_max) { + for (i = 0; i < count; i++) + svga->latch.b[i] = 0xff; } else { - if (latch_addr > svga->vram_max) - svga->latch = 0xffffffff; - else { - latch_addr &= svga->vram_mask; - svga->latch = ((uint32_t *)(svga->vram))[latch_addr >> 2]; + latch_addr &= svga->vram_mask; + + for (i = 0; i < count; i++) + svga->latch.b[i] = svga->vram[latch_addr | i]; + } + + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + + if (svga->readmode) { + temp = 0xff; + + for (pixel = 0; pixel < 8; pixel++) { + for (plane = 0; plane < count; plane++) { + if (svga->colournocare & (1 << plane)) { + /* If we care about a plane, and the pixel has a mismatch on it, clear its bit. */ + if (((svga->latch.b[plane] >> pixel) & 1) != ((svga->colourcompare >> plane) & 1)) + temp &= ~(1 << pixel); + } + } } - if (addr >= svga->vram_max) - return 0xff; + ret = temp; + } else + ret = svga->vram[addr | readplane]; - addr &= svga->vram_mask; - } - - if (!(svga->gdcreg[5] & 8)) { - /* read mode 0 */ - return svga->vram[addr | readplane]; - } else { - /* read mode 1 */ - ret = (svga->latch ^ mask16[svga->colourcompare & 0x0f]) & mask16[svga->colournocare & 0x0f]; - ret8 = (ret & 0xff); - ret8 |= ((ret >> 24) & 0xff); - ret8 |= ((ret >> 16) & 0xff); - ret8 |= ((ret >> 8) & 0xff); - return(~ret8); - } + return ret; } @@ -1063,70 +1186,72 @@ svga_read_linear(uint32_t addr, void *p) void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) { - int y_add = (enable_overscan) ? overscan_y : 0; - int x_add = (enable_overscan) ? 16 : 0; + int y_add, x_add, y_start, x_start, bottom; uint32_t *p; int i, j; + int xs_temp, ys_temp; - svga->frames++; + y_add = (enable_overscan) ? overscan_y : 0; + x_add = (enable_overscan) ? overscan_x : 0; + y_start = (enable_overscan) ? 0 : (overscan_y >> 1); + x_start = (enable_overscan) ? 0 : (overscan_x >> 1); + bottom = (overscan_y >> 1) + (svga->crtc[8] & 0x1f); - if ((xsize > 2032) || (ysize > 2032)) { - x_add = 0; - y_add = 0; - suppress_overscan = 1; - } else - suppress_overscan = 0; - - if (y1 > y2) { - video_blit_memtoscreen(32, 0, 0, 0, xsize + x_add, ysize + y_add); + if ((wx <= 0) || (wy <= 0)) { + video_blit_memtoscreen(x_start, y_start, 0, 0, 0, 0); return; } - if ((wx != xsize) || ((wy + 1) != ysize) || video_force_resize_get()) { - /* Screen res has changed.. fix up, and let them know. */ - xsize = wx; - ysize = wy + 1; - if (xsize < 64) - xsize = 640; - if (ysize < 32) - ysize = 200; + if (y1 > y2) { + video_blit_memtoscreen(x_start, y_start, 0, 0, xsize + x_add, ysize + y_add); + return; + } - set_screen_size(xsize+x_add,ysize+y_add); + xs_temp = wx; + ys_temp = wy + 1; + if (xs_temp < 64) + xs_temp = 640; + if (ys_temp < 32) + ys_temp = 200; + + if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { + /* Screen res has changed.. fix up, and let them know. */ + xsize = xs_temp; + ysize = ys_temp; + + if ((xsize > 1984) || (ysize > 2016)) { + /* 2048x2048 is the biggest safe render texture, to account for overscan, + we suppress overscan starting from x 1984 and y 2016. */ + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } else + suppress_overscan = 0; + + set_screen_size(xsize + x_add, ysize + y_add); if (video_force_resize_get()) video_force_resize_set(0); } - if (enable_overscan && !suppress_overscan) { - if ((wx >= 160) && ((wy + 1) >= 120)) { - /* Draw (overscan_size - scroll size) lines of overscan on top. */ - for (i = 0; i < (y_add >> 1); i++) { - p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + if ((wx >= 160) && ((wy + 1) >= 120)) { + /* Draw (overscan_size - scroll size) lines of overscan on top and bottom. */ + for (i = 0; i < svga->y_add; i++) { + p = &buffer32->line[i & 0x7ff][0]; - for (j = 0; j < (xsize + x_add); j++) - p[j] = svga->overscan_color; - } + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga->overscan_color; + } - /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ - for (i = 0; i < (y_add >> 1); i++) { - p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i) & 0x7ff])[32]; + for (i = 0; i < bottom; i++) { + p = &buffer32->line[(ysize + svga->y_add + i) & 0x7ff][0]; - for (j = 0; j < (xsize + x_add); j++) - p[j] = svga->overscan_color; - } - - for (i = (y_add >> 1); i < (ysize + (y_add >> 1)); i ++) { - p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; - - for (j = 0; j < 8; j++) { - p[j] = svga->pallook[svga->overscan_color]; - p[xsize + (x_add >> 1) + j] = svga->overscan_color; - } - } + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga->overscan_color; } } - video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); + video_blit_memtoscreen(x_start, y_start, y1, y2 + y_add, xsize + x_add, ysize + y_add); } @@ -1164,14 +1289,20 @@ svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p) egawrites += 2; - cycles -= video_timing_write_w; + sub_cycles(video_timing_write_w); + + if (!linear) { + addr = svga_decode_addr(svga, addr, 1); + + if (addr == 0xffffffff) + return; + } - if (!linear) - addr = (addr & svga->banked_mask) + svga->write_bank; 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; } @@ -1197,19 +1328,24 @@ svga_writel_common(uint32_t addr, uint32_t val, uint8_t linear, void *p) svga_t *svga = (svga_t *)p; if (!svga->fast) { - svga_write(addr, val, p); - svga_write(addr + 1, val >> 8, p); - svga_write(addr + 2, val >> 16, p); - svga_write(addr + 3, val >> 24, p); + svga_write_common(addr, val, linear, p); + svga_write_common(addr + 1, val >> 8, linear, p); + svga_write_common(addr + 2, val >> 16, linear, p); + svga_write_common(addr + 3, val >> 24, linear, p); return; } egawrites += 4; - cycles -= video_timing_write_l; + sub_cycles(video_timing_write_l); + + if (!linear) { + addr = svga_decode_addr(svga, addr, 1); + + if (addr == 0xffffffff) + return; + } - if (!linear) - addr = (addr & svga->banked_mask) + svga->write_bank; addr &= svga->decode_mask; if (addr >= svga->vram_max) return; @@ -1262,10 +1398,15 @@ svga_readw_common(uint32_t addr, uint8_t linear, void *p) egareads += 2; - cycles -= video_timing_read_w; + sub_cycles(video_timing_read_w); + + if (!linear) { + addr = svga_decode_addr(svga, addr, 0); + + if (addr == 0xffffffff) + return 0xffff; + } - if (!linear) - addr = (addr & svga->banked_mask) + svga->read_bank; addr &= svga->decode_mask; if (addr >= svga->vram_max) return 0xffff; @@ -1300,10 +1441,15 @@ svga_readl_common(uint32_t addr, uint8_t linear, void *p) egareads += 4; - cycles -= video_timing_read_l; + sub_cycles(video_timing_read_l); + + if (!linear) { + addr = svga_decode_addr(svga, addr, 0); + + if (addr == 0xffffffff) + return 0xffffffff; + } - if (!linear) - addr = (addr & svga->banked_mask) + svga->read_bank; addr &= svga->decode_mask; if (addr >= svga->vram_max) return 0xffffffff; @@ -1324,30 +1470,3 @@ svga_readl_linear(uint32_t addr, void *p) { return svga_readl_common(addr, 1, p); } - - -void -svga_add_status_info(char *s, int max_len, void *p) -{ - svga_t *svga = (svga_t *)p; - char temps[128]; - - if (svga->chain4) - strcpy(temps, "SVGA chained (possibly mode 13h)\n"); - else - strcpy(temps, "SVGA unchained (possibly mode-X)\n"); - strncat(s, temps, max_len); - - if (!svga->video_bpp) - strcpy(temps, "SVGA in text mode\n"); - else - sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); - strncat(s, temps, max_len); - - sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); - strncat(s, temps, max_len); - - sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames); - svga->frames = 0; - strncat(s, temps, max_len); -} diff --git a/src/video/vid_svga.h b/src/video/vid_svga.h index 214e62a13..589039d3d 100644 --- a/src/video/vid_svga.h +++ b/src/video/vid_svga.h @@ -8,7 +8,7 @@ * * Generic SVGA handling. * - * Version: @(#)vid_svga.h 1.0.12 2018/05/26 + * Version: @(#)vid_svga.h 1.0.15 2018/10/04 * * Authors: Sarah Walker, * Miran Grca, @@ -17,6 +17,12 @@ * Copyright 2016-2018 Miran Grca. */ + +#define FLAG_EXTRA_BANKS 1 +#define FLAG_ADDR_BY8 2 +#define FLAG_LATCH8 4 + + typedef struct { int ena, x, y, xoff, yoff, xsize, ysize, @@ -24,25 +30,34 @@ typedef struct { uint32_t addr, pitch; } hwcursor_t; +typedef union { + uint64_t q; + uint32_t d[2]; + uint16_t w[4]; + uint8_t b[8]; +} latch_t; + typedef struct svga_t { mem_mapping_t mapping; - int enabled; + uint8_t fast, chain4, chain2_write, chain2_read, + ext_overscan, bus_size, + lowres, interlace, linedbl, rowcount, + set_reset_disabled, bpp, ramdac_type, fb_only, + readmode, writemode, readplane, + hwcursor_oddeven, dac_hwcursor_oddeven, overlay_oddeven; - uint8_t crtcreg, crtc[128], - gdcaddr, gdcreg[64], - attrff, attr_palette_enable, - attraddr, attrregs[32], - seqaddr, seqregs[64], - miscout, cgastat, - plane_mask, writemask, - colourcompare, colournocare, - scrblank, egapal[16], - *vram, *changedvram; - - int vidclock, fb_only, - fast; + int dac_addr, dac_pos, dac_r, dac_g, + vtotal, dispend, vsyncstart, split, vblankstart, + hdisp, hdisp_old, htotal, hdisp_time, rowoffset, + dispon, hdisp_on, + vc, sc, linepos, vslines, linecountff, oddeven, + con, cursoron, blink, scrollcache, + firstline, lastline, firstline_draw, lastline_draw, + displine, fullchange, x_add, y_add, pan, + vram_display_mask, vidclock, + hwcursor_on, dac_hwcursor_on, overlay_on; /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : 0MB-1MB - VRAM @@ -53,50 +68,28 @@ typedef struct svga_t 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 dac_mask, dac_status; - int dac_read, dac_write, - dac_pos, ramdac_type, - dac_r, dac_g; - - int readmode, writemode, - readplane, extvram, - chain4, chain2_write, chain2_read, - oddeven_page, oddeven_chain, - set_reset_disabled; - - uint32_t charseta, charsetb, - latch, ma_latch, + uint32_t decode_mask, vram_max, + vram_mask, + charseta, charsetb, + adv_flags, ma_latch, ma, maback, write_bank, read_bank, + extra_banks[2], banked_mask, ca, overscan_color, - pallook[256]; + *map8, pallook[256]; PALETTE vgapal; - int vtotal, dispend, vsyncstart, split, vblankstart, - hdisp, hdisp_old, htotal, hdisp_time, rowoffset, - lowres, interlace, linedbl, rowcount, bpp, - dispon, hdisp_on, - vc, sc, linepos, vslines, linecountff, oddeven, - con, cursoron, blink, scrollcache, - firstline, lastline, firstline_draw, lastline_draw, - displine, fullchange, - video_res_x, video_res_y, video_bpp, frames, fps, - vram_display_mask, - hwcursor_on, overlay_on, - hwcursor_oddeven, overlay_oddeven; + uint64_t dispontime, dispofftime; + latch_t latch; + + pc_timer_t timer; double clock; - int64_t dispontime, dispofftime, - vidtime; - hwcursor_t hwcursor, hwcursor_latch, + dac_hwcursor, dac_hwcursor_latch, overlay, overlay_latch; void (*render)(struct svga_t *svga); @@ -107,16 +100,33 @@ typedef struct svga_t void (*hwcursor_draw)(struct svga_t *svga, int displine); + void (*dac_hwcursor_draw)(struct svga_t *svga, int displine); + void (*overlay_draw)(struct svga_t *svga, int displine); void (*vblank_start)(struct svga_t *svga); void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr); + float (*getclock)(int clock, void *p); /*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 crtc[128], gdcreg[64], attrregs[32], seqregs[64], + egapal[16], + *vram, *changedvram; + + uint8_t crtcreg, gdcaddr, + attrff, attr_palette_enable, attraddr, seqaddr, + miscout, cgastat, scrblank, + plane_mask, writemask, + colourcompare, colournocare, + dac_mask, dac_status, + ksc5601_sbyte_mask; + + void *ramdac, *clock_gen; } svga_t; @@ -154,9 +164,6 @@ uint8_t svga_in(uint16_t addr, void *p); svga_t *svga_get_pri(); void svga_set_override(svga_t *svga, int val); -void svga_set_ven_write(svga_t *svga, - void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr)); - void svga_set_ramdac_type(svga_t *svga, int type); void svga_close(svga_t *svga); diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 3e920bd1e..2448bd1fb 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -8,13 +8,13 @@ * * SVGA renderers. * - * Version: @(#)vid_svga_render.c 1.0.11 2018/05/26 + * Version: @(#)vid_svga_render.c 1.0.14 2019/11/19 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -22,839 +22,1045 @@ #include #include "../86box.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" -void svga_render_blank(svga_t *svga) +void +svga_render_blank(svga_t *svga) { - int x, xx; - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; + int x, xx; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x < svga->hdisp; x++) - { - switch (svga->seqregs[1] & 9) - { - case 0: - for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 9) + xx + 32 + x_add] = 0; - break; - case 1: - for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 8) + xx + 32 + x_add] = 0; - break; - case 8: - for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 18) + xx + 32 + x_add] = 0; - break; - case 9: - for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 16) + xx + 32 + x_add] = 0; - break; - } - } + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x < (svga->hdisp + svga->scrollcache); x++) { + switch (svga->seqregs[1] & 9) { + case 0: + for (xx = 0; xx < 9; xx++) + buffer32->line[svga->displine + svga->y_add][svga->x_add + (x * 9) + xx] = 0x00000000; + break; + case 1: + for (xx = 0; xx < 8; xx++) + buffer32->line[svga->displine + svga->y_add][svga->x_add + (x * 8) + xx] = 0x00000000; + break; + case 8: + for (xx = 0; xx < 18; xx++) + buffer32->line[svga->displine + svga->y_add][svga->x_add + (x * 18) + xx] = 0x00000000; + break; + case 9: + for (xx = 0; xx < 16; xx++) + buffer32->line[svga->displine + svga->y_add][svga->x_add + (x * 16) + xx] = 0x00000000; + break; + } + } } -void svga_render_text_40(svga_t *svga) + +void +svga_render_overscan_left(svga_t *svga) +{ + int i; + + if (svga->scrblank || (svga->hdisp == 0)) + return; + + for (i = 0; i < svga->x_add; i++) + buffer32->line[svga->displine + svga->y_add][i] = svga->overscan_color; +} + + +void +svga_render_overscan_right(svga_t *svga) +{ + int i, right; + + if (svga->scrblank || (svga->hdisp == 0)) + return; + + right = (overscan_x >> 1); + for (i = 0; i < right; i++) + buffer32->line[svga->displine + svga->y_add][svga->x_add + svga->hdisp + i] = svga->overscan_color; +} + + +void +svga_render_text_40(svga_t *svga) { - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; + uint32_t *p; + int x, xx; + int drawcursor, xinc; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + xinc = (svga->seqregs[1] & 1) ? 16 : 18; + + for (x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + if (drawcursor) { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; + } else { + fg = svga->pallook[svga->egapal[attr & 15]]; + bg = svga->pallook[svga->egapal[attr >> 4]]; + + if (attr & 0x80 && svga->attrregs[0x10] & 8) { + bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; + if (svga->blink & 16) + fg = bg; + } + } + + dat = svga->vram[charaddr + (svga->sc << 2)]; + if (svga->seqregs[1] & 1) { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + } else { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(svga->attrregs[0x10] & 4)) + p[16] = p[17] = bg; + else + p[16] = p[17] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + } + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_text_80(svga_t *svga) +{ + uint32_t *p; + int x, xx; + int drawcursor, xinc; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + xinc = (svga->seqregs[1] & 1) ? 8 : 9; + + for (x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + if (drawcursor) { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; + } else { + fg = svga->pallook[svga->egapal[attr & 15]]; + bg = svga->pallook[svga->egapal[attr >> 4]]; + if (attr & 0x80 && svga->attrregs[0x10] & 8) { + bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; + if (svga->blink & 16) + fg = bg; + } + } + + dat = svga->vram[charaddr + (svga->sc << 2)]; + if (svga->seqregs[1] & 1) { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + } else { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[8] = bg; + else + p[8] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + } + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_text_80_ksc5601(svga_t *svga) +{ + uint32_t *p; + int x, xx; + int drawcursor, xinc; + uint8_t chr, attr, dat, nextchr; + uint32_t charaddr; + int fg, bg; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + xinc = (svga->seqregs[1] & 1) ? 8 : 9; + + for (x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; + nextchr = svga->vram[((svga->ma + 4) << 1) & svga->vram_display_mask]; + 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 ((x + xinc) < svga->hdisp && (chr & (nextchr | svga->ksc5601_sbyte_mask) & 0x80)) { + if (((chr == 0xc9) || (chr == 0xfe)) && ((nextchr > 0xa0) && (nextchr < 0xff))) + dat = fontdatksc5601_user[((chr == 0xfe) ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc]; + else if (nextchr & 0x80) + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc]; + else + dat = 0xff; + } else { + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + 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 == 0xc9) || (chr == 0xfe)) && ((nextchr > 0xa0) && (nextchr < 0xff))) + dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc + 16]; + else if(nextchr & 0x80) + dat = fontdatksc5601[((chr & 0x7f) << 7) | (nextchr & 0x7F)].chr[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, x; + uint8_t dat[2]; + uint32_t addr, *p; + + if ((svga->displine + svga->y_add) < 0) + return; + + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { + addr = svga->ma; + + if (!(svga->crtc[0x17] & 0x40)) { + addr = (addr << 1) & svga->vram_mask; + addr &= ~7; + + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; + + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; + } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + + dat[0] = svga->vram[addr]; + dat[1] = svga->vram[addr | 0x1]; + if (svga->seqregs[1] & 4) + svga->ma += 2; + else + svga->ma += 4; + + svga->ma &= svga->vram_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]]; + p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; + + p += 16; + } + } +} + + +void +svga_render_2bpp_highres(svga_t *svga) +{ + int changed_offset, x; + uint8_t dat[2]; + uint32_t addr, *p; + + if ((svga->displine + svga->y_add) < 0) + return; + + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + addr = svga->ma; + + if (!(svga->crtc[0x17] & 0x40)) { + addr = (addr << 1) & svga->vram_mask; + addr &= ~7; + + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; + + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; + } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + + dat[0] = svga->vram[addr]; + dat[1] = svga->vram[addr | 0x1]; + if (svga->seqregs[1] & 4) + svga->ma += 2; + else + svga->ma += 4; + + svga->ma &= svga->vram_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; + } + } +} + + +void +svga_render_4bpp_lowres(svga_t *svga) +{ + int x, oddeven; + uint32_t addr, *p; + uint8_t edat[4]; + uint8_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { + addr = svga->ma; + oddeven = 0; + + if (!(svga->crtc[0x17] & 0x40)) { + addr = (addr << 1) & svga->vram_mask; + + if (svga->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + + addr &= ~7; + + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; + } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + + if (svga->seqregs[1] & 4) { + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->ma += 2; + } else { + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); + svga->ma += 4; + } + svga->ma &= svga->vram_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]]; + p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 16; + } + } +} + + +void +svga_render_4bpp_highres(svga_t *svga) +{ + int changed_offset, x; + int oddeven; + uint32_t addr, *p; + uint8_t edat[4]; + uint8_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + addr = svga->ma; + oddeven = 0; + + if (!(svga->crtc[0x17] & 0x40)) { + addr = (addr << 1) & svga->vram_mask; + + if (svga->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + + addr &= ~7; + + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; + } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + + if (svga->seqregs[1] & 4) { + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->ma += 2; + } else { + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); + svga->ma += 4; + } + svga->ma &= svga->vram_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]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 8; + } + } +} + + +void +svga_render_8bpp_lowres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + + p[0] = p[1] = svga->map8[dat & 0xff]; + p[2] = p[3] = svga->map8[(dat >> 8) & 0xff]; + p[4] = p[5] = svga->map8[(dat >> 16) & 0xff]; + p[6] = p[7] = svga->map8[(dat >> 24) & 0xff]; + + svga->ma += 4; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_8bpp_highres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp/* + svga->scrollcache*/); x += 8) { + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[0] = svga->map8[dat & 0xff]; + p[1] = svga->map8[(dat >> 8) & 0xff]; + p[2] = svga->map8[(dat >> 16) & 0xff]; + p[3] = svga->map8[(dat >> 24) & 0xff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + p[4] = svga->map8[dat & 0xff]; + p[5] = svga->map8[(dat >> 8) & 0xff]; + p[6] = svga->map8[(dat >> 16) & 0xff]; + p[7] = svga->map8[(dat >> 24) & 0xff]; + + svga->ma += 8; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_15bpp_lowres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + + p[(x << 1)] = p[(x << 1) + 1] = video_15to32[dat & 0xffff]; + + p[(x << 1) + 2] = p[(x << 1) + 3] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + + p[(x << 1) + 4] = p[(x << 1) + 5] = video_15to32[dat & 0xffff]; + + p[(x << 1) + 6] = p[(x << 1) + 7] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_15bpp_highres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + 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]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = video_15to32[dat & 0xffff]; + p[x + 3] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = video_15to32[dat & 0xffff]; + p[x + 5] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = video_15to32[dat & 0xffff]; + p[x + 7] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_15bpp_mix_lowres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[(x << 1)] = p[(x << 1) + 1] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + + dat >>= 16; + p[(x << 1) + 2] = p[(x << 1) + 3] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[(x << 1) + 4] = p[(x << 1) + 5] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + + dat >>= 16; + p[(x << 1) + 6] = p[(x << 1) + 7] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_15bpp_mix_highres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[x] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + dat >>= 16; + p[x + 1] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + dat >>= 16; + p[x + 3] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + dat >>= 16; + p[x + 5] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + dat >>= 16; + p[x + 7] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : video_15to32[dat & 0xffff]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_16bpp_lowres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[(x << 1)] = p[(x << 1) + 1] = video_16to32[dat & 0xffff]; + p[(x << 1) + 2] = p[(x << 1) + 3] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[(x << 1) + 4] = p[(x << 1) + 5] = video_16to32[dat & 0xffff]; + p[(x << 1) + 6] = p[(x << 1) + 7] = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_16bpp_highres(svga_t *svga) +{ + int x; + uint32_t *p; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + 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]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = video_16to32[dat & 0xffff]; + p[x + 3] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = video_16to32[dat & 0xffff]; + p[x + 5] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = video_16to32[dat & 0xffff]; + p[x + 7] = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_24bpp_lowres(svga_t *svga) +{ + int x; + uint32_t fg; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 3; + svga->ma &= svga->vram_display_mask; + buffer32->line[svga->displine + svga->y_add][(x << 1) + svga->x_add] = + buffer32->line[svga->displine + svga->y_add][(x << 1) + 1 + svga->x_add] = fg; + } + } +} + + +void +svga_render_24bpp_highres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[x] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); + p[x + 1] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); + p[x + 2] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); + p[x + 3] = dat & 0xffffff; + + svga->ma += 12; + } + svga->ma &= svga->vram_display_mask; + } +} + + +void +svga_render_32bpp_lowres(svga_t *svga) +{ + int x; + uint32_t fg; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + buffer32->line[svga->displine + svga->y_add][(x << 1) + svga->x_add] = + buffer32->line[svga->displine + svga->y_add][(x << 1) + 1 + svga->x_add] = fg; + } + } +} + + +void +svga_render_32bpp_highres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->fullchange) - { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; - int x, xx; - int drawcursor; - uint8_t chr, attr, dat; - uint32_t charaddr; - int fg, bg; - int xinc = (svga->seqregs[1] & 1) ? 16 : 18; - - for (x = 0; x < svga->hdisp; x += xinc) - { - drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); - chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; - attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; - if (attr & 8) charaddr = svga->charsetb + (chr * 128); - else charaddr = svga->charseta + (chr * 128); + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - if (drawcursor) - { - bg = svga->pallook[svga->egapal[attr & 15]]; - fg = svga->pallook[svga->egapal[attr >> 4]]; - } - else - { - fg = svga->pallook[svga->egapal[attr & 15]]; - bg = svga->pallook[svga->egapal[attr >> 4]]; - if (attr & 0x80 && svga->attrregs[0x10] & 8) - { - bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; - if (svga->blink & 16) - fg = bg; - } - } - - dat = svga->vram[charaddr + (svga->sc << 2)]; - if (svga->seqregs[1] & 1) - { - for (xx = 0; xx < 16; xx += 2) - p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; - } - else - { - for (xx = 0; xx < 16; xx += 2) - p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; - if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) - p[16] = p[17] = bg; - else - p[16] = p[17] = (dat & 1) ? fg : bg; - } - svga->ma += 4; - p += xinc; - } - svga->ma &= svga->vram_display_mask; - } + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = dat & 0xffffff; + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } } -void svga_render_text_80(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; +void +svga_render_ABGR8888_highres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->fullchange) - { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; - int x, xx; - int drawcursor; - uint8_t chr, attr, dat; - uint32_t charaddr; - int fg, bg; - int xinc = (svga->seqregs[1] & 1) ? 8 : 9; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x < svga->hdisp; x += xinc) - { - drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); - chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; - attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; - - - if (attr & 8) charaddr = svga->charsetb + (chr * 128); - else charaddr = svga->charseta + (chr * 128); - - if (drawcursor) - { - bg = svga->pallook[svga->egapal[attr & 15]]; - fg = svga->pallook[svga->egapal[attr >> 4]]; - } - else - { - fg = svga->pallook[svga->egapal[attr & 15]]; - bg = svga->pallook[svga->egapal[attr >> 4]]; - if (attr & 0x80 && svga->attrregs[0x10] & 8) - { - bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; - if (svga->blink & 16) - fg = bg; - } - } - - dat = svga->vram[charaddr + (svga->sc << 2)]; - if (svga->seqregs[1] & 1) - { - for (xx = 0; xx < 8; xx++) - p[xx] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = 0; xx < 8; xx++) - p[xx] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) - p[8] = bg; - else - p[8] = (dat & 1) ? fg : bg; - } - svga->ma += 4; - p += xinc; - } - svga->ma &= svga->vram_display_mask; - } + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } } -void svga_render_text_80_ksc5601(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; +void +svga_render_RGBA8888_highres(svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->fullchange) - { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; - int x, xx; - int drawcursor; - uint8_t chr, attr, dat, nextchr; - uint32_t charaddr; - int fg, bg; - int xinc = (svga->seqregs[1] & 1) ? 8 : 9; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x < svga->hdisp; x += xinc) - { - drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); - chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; - nextchr = svga->vram[((svga->ma + 4) << 1) & svga->vram_display_mask]; - 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(x + xinc < svga->hdisp && (chr & nextchr & 0x80)) - { - if((chr == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff)) - dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc]; - else - dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc]; - } - else - { - if (attr & 8) charaddr = svga->charsetb + (chr * 128); - else charaddr = svga->charseta + (chr * 128); - - 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 & 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 == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff)) - dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc + 16]; - else - dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc + 16]; - 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; - - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) - { - int x; - int offset = ((8 - svga->scrollcache) << 1) + 16; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 16) - { - uint8_t dat[2]; - - dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]; - dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1]; - svga->ma += 4; - 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]]; - p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; - - p += 16; - } - } -} - -void svga_render_2bpp_highres(svga_t *svga) -{ - int changed_offset; - - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) - { - int x; - int offset = (8 - svga->scrollcache) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 8) - { - uint8_t dat[2]; - - dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]; - dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1]; - svga->ma += 4; - 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; - } - } -} - -void svga_render_4bpp_lowres(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - int x; - int offset = ((8 - svga->scrollcache) << 1) + 16; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 16) - { - uint8_t edat[4]; - uint8_t dat; - - *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); - svga->ma += 4; - svga->ma &= svga->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]]; - p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - - p += 16; - } - } -} - -void svga_render_4bpp_highres(svga_t *svga) -{ - int changed_offset; - - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) - { - int x; - int offset = (8 - svga->scrollcache) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 8) - { - uint8_t edat[4]; - uint8_t dat; - - *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma | ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]); - svga->ma += 4; - 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]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - - p += 8; - } - } -} - -void svga_render_8bpp_lowres(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - int x; - int offset = (8 - (svga->scrollcache & 6)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 8) - { - uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->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) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - int x; - int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 8) - { - uint32_t dat; - dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); - p[0] = svga->pallook[dat & 0xff]; - p[1] = svga->pallook[(dat >> 8) & 0xff]; - p[2] = svga->pallook[(dat >> 16) & 0xff]; - p[3] = svga->pallook[(dat >> 24) & 0xff]; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); - p[4] = svga->pallook[dat & 0xff]; - p[5] = svga->pallook[(dat >> 8) & 0xff]; - p[6] = svga->pallook[(dat >> 16) & 0xff]; - p[7] = svga->pallook[(dat >> 24) & 0xff]; - - svga->ma += 8; - p += 8; - } - svga->ma &= svga->vram_display_mask; - } -} - -void svga_render_15bpp_lowres(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - int x; - int offset = (8 - (svga->scrollcache & 6)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 4) - { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; - - 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]; - } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; - } -} - -void svga_render_15bpp_highres(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - int x; - int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 8) - { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - p[x + 2] = video_15to32[dat & 0xffff]; - p[x + 3] = video_15to32[dat >> 16]; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); - p[x + 4] = video_15to32[dat & 0xffff]; - p[x + 5] = video_15to32[dat >> 16]; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); - p[x + 6] = video_15to32[dat & 0xffff]; - p[x + 7] = video_15to32[dat >> 16]; - } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; - } -} - -void svga_render_16bpp_lowres(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - int x; - int offset = (8 - (svga->scrollcache & 6)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 4) - { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; - - 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]; - } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; - } -} - -void svga_render_16bpp_highres(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - int x; - int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 8) - { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - p[x + 2] = video_16to32[dat & 0xffff]; - p[x + 3] = video_16to32[dat >> 16]; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); - p[x + 4] = video_16to32[dat & 0xffff]; - p[x + 5] = video_16to32[dat >> 16]; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); - p[x + 6] = video_16to32[dat & 0xffff]; - p[x + 7] = video_16to32[dat >> 16]; - } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; - } -} - -void svga_render_24bpp_lowres(svga_t *svga) -{ - int x, offset; - uint32_t fg; - - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - offset = (8 - (svga->scrollcache & 6)) + 24; - - for (x = 0; x <= svga->hdisp; x++) - { - fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); - svga->ma += 3; - svga->ma &= svga->vram_display_mask; - ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; - } - } -} - -void svga_render_24bpp_highres(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - int x; - int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x += 4) - { - uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); - p[x] = dat & 0xffffff; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); - p[x + 1] = dat & 0xffffff; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); - p[x + 2] = dat & 0xffffff; - - dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); - p[x + 3] = dat & 0xffffff; - - svga->ma += 12; - } - svga->ma &= svga->vram_display_mask; - } -} - -void svga_render_32bpp_lowres(svga_t *svga) -{ - int x, offset; - uint32_t fg; - - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) - { - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - offset = (8 - (svga->scrollcache & 6)) + 24; - - for (x = 0; x <= svga->hdisp; x++) - { - fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); - svga->ma += 4; - svga->ma &= svga->vram_display_mask; - ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; - } - } -} - -/*72% - 91%*/ -void svga_render_32bpp_highres(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) - { - int x; - int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x++) - { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); - p[x] = dat & 0xffffff; - } - svga->ma += 4; - svga->ma &= svga->vram_display_mask; - } -} - -void svga_render_ABGR8888_highres(svga_t *svga) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) - { - int x; - int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x++) - { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); - p[x] = ((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) -{ - int y_add = enable_overscan ? (overscan_y >> 1) : 0; - int x_add = enable_overscan ? 8 : 0; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) - { - int x; - int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= svga->hdisp; x++) - { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); - p[x] = dat >> 8; - } - svga->ma += 4; - svga->ma &= svga->vram_display_mask; - } + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = dat >> 8; + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } } diff --git a/src/video/vid_svga_render.h b/src/video/vid_svga_render.h index 4bbc43272..a99e25e16 100644 --- a/src/video/vid_svga_render.h +++ b/src/video/vid_svga_render.h @@ -28,6 +28,8 @@ extern int scrollcache; extern uint8_t edatlookup[4][4]; void svga_render_blank(svga_t *svga); +void svga_render_overscan_left(svga_t *svga); +void svga_render_overscan_right(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); @@ -38,8 +40,14 @@ void svga_render_4bpp_lowres(svga_t *svga); void svga_render_4bpp_highres(svga_t *svga); void svga_render_8bpp_lowres(svga_t *svga); void svga_render_8bpp_highres(svga_t *svga); +void svga_render_8bpp_gs_lowres(svga_t *svga); +void svga_render_8bpp_gs_highres(svga_t *svga); +void svga_render_8bpp_rgb_lowres(svga_t *svga); +void svga_render_8bpp_rgb_highres(svga_t *svga); void svga_render_15bpp_lowres(svga_t *svga); void svga_render_15bpp_highres(svga_t *svga); +void svga_render_15bpp_mix_lowres(svga_t *svga); +void svga_render_15bpp_mix_highres(svga_t *svga); void svga_render_16bpp_lowres(svga_t *svga); void svga_render_16bpp_highres(svga_t *svga); void svga_render_24bpp_lowres(svga_t *svga); diff --git a/src/video/vid_table.c b/src/video/vid_table.c index bee03c967..d86e61686 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -8,27 +8,26 @@ * * Define all known video cards. * - * Version: @(#)vid_table.c 1.0.30 2018/07/19 + * Version: @(#)vid_table.c 1.0.44 2019/10/01 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include #include -#include #include +#include #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../machine/machine.h" #include "../mem.h" -#include "../rom.h" #include "../device.h" -#include "../timer.h" #include "../plat.h" #include "video.h" #include "vid_svga.h" @@ -45,18 +44,17 @@ #include "vid_genius.h" #include "vid_hercules.h" #include "vid_herculesplus.h" +#include "vid_ht216.h" +#include "vid_im1024.h" #include "vid_incolor.h" #include "vid_colorplus.h" #include "vid_mda.h" -#ifdef DEV_BRANCH -# ifdef USE_RIVA -# include "vid_nvidia.h" -# endif -#endif #include "vid_oak_oti.h" #include "vid_paradise.h" +#include "vid_pgc.h" #include "vid_s3.h" #include "vid_s3_virge.h" +#include "vid_sigma.h" #include "vid_tgui9440.h" #include "vid_ti_cf62011.h" #include "vid_tvga.h" @@ -65,135 +63,136 @@ #include "vid_wy700.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 { const char *name; const char *internal_name; const device_t *device; - int legacy_id; - int flags; - video_timings_t timing; } VIDEO_CARD; +static video_timings_t timing_default = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + +static int was_reset = 0; + + static const VIDEO_CARD video_cards[] = { - { "None", "none", NULL, GFX_NONE }, - { "Internal", "internal", NULL, GFX_INTERNAL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_isa", &mach64gx_isa_device, GFX_MACH64GX_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - { "[ISA] ATI Korean VGA (ATI-28800-5)", "ati28800k", &ati28800k_device, GFX_ATIKOREANVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - { "[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device, GFX_VGA88, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device, GFX_VGACHARGER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - { "[ISA] ATI VGA Edge-16 (ATI-18800-5)", "ati18800", &ati18800_device, GFX_VGAEDGE16, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "None", "none", NULL }, + { "Internal", "internal", NULL }, + { "[ISA] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_isa", &mach64gx_isa_device }, + { "[ISA] ATI Korean VGA (ATI-28800-5)", "ati28800k", &ati28800k_device }, + { "[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device }, + { "[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device }, + { "[ISA] ATI VGA Edge-16 (ATI-18800-5)", "ati18800", &ati18800_device }, #if defined(DEV_BRANCH) && defined(USE_VGAWONDER) - { "[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device, GFX_VGAWONDER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device }, #endif #if defined(DEV_BRANCH) && defined(USE_XL24) - { "[ISA] ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device, GFX_VGAWONDERXL24, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + { "[ISA] ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device }, #endif - { "[ISA] CGA", "cga", &cga_device, GFX_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Chips & Technologies SuperEGA", "superega", &sega_device, GFX_SUPER_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device, GFX_CL_GD5428_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - { "[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device, GFX_CL_GD5429_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - { "[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device, GFX_CL_GD5434_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - { "[ISA] Compaq ATI VGA Wonder XL (ATI-28800-5)", "compaq_ati28800", &compaq_ati28800_device, GFX_VGAWONDERXL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - { "[ISA] Compaq CGA", "compaq_cga", &compaq_cga_device, GFX_COMPAQ_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Compaq CGA 2", "compaq_cga_2", &compaq_cga_2_device, GFX_COMPAQ_CGA_2, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Compaq EGA", "compaq_ega", &cpqega_device, GFX_COMPAQ_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] EGA", "ega", &ega_device, GFX_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Hercules", "hercules", &hercules_device, GFX_HERCULES, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Hercules Plus", "hercules_plus", &herculesplus_device, GFX_HERCULESPLUS, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Hercules InColor", "incolor", &incolor_device, GFX_INCOLOR, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] MDA", "mda", &mda_device, GFX_MDA, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] MDSI Genius", "genius", &genius_device, GFX_GENIUS, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] OAK OTI-037C", "oti037c", &oti037c_device, GFX_OTI037C, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, - { "[ISA] OAK OTI-067", "oti067", &oti067_device, GFX_OTI067, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, - { "[ISA] OAK OTI-077", "oti077", &oti077_device, GFX_OTI077, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, - { "[ISA] Paradise PVGA1A", "pvga1a", ¶dise_pvga1a_device, GFX_PVGA1A, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Paradise WD90C11-LR", "wd90c11", ¶dise_wd90c11_device, GFX_WD90C11, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device, GFX_WD90C30, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, - { "[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device, GFX_COLORPLUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] CGA", "cga", &cga_device }, + { "[ISA] Chips & Technologies SuperEGA", "superega", &sega_device }, +#if defined(DEV_BRANCH) && defined(USE_CL5422) + { "[ISA] Cirrus Logic CL-GD 5402", "cl_gd5402_isa", &gd5402_isa_device }, + { "[ISA] Cirrus Logic CL-GD 5420", "cl_gd5420_isa", &gd5420_isa_device }, + { "[ISA] Cirrus Logic CL-GD 5422", "cl_gd5422_isa", &gd5422_isa_device }, +#endif + { "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device }, + { "[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device }, + { "[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device }, + { "[ISA] Compaq ATI VGA Wonder XL (ATI-28800-5)", "compaq_ati28800", &compaq_ati28800_device }, + { "[ISA] Compaq CGA", "compaq_cga", &compaq_cga_device }, + { "[ISA] Compaq CGA 2", "compaq_cga_2", &compaq_cga_2_device }, + { "[ISA] Compaq EGA", "compaq_ega", &cpqega_device }, + { "[ISA] EGA", "ega", &ega_device }, + { "[ISA] G2 GC205", "g2_gc205", &g2_gc205_device }, + { "[ISA] Hercules", "hercules", &hercules_device }, + { "[ISA] Hercules Plus", "hercules_plus", &herculesplus_device }, + { "[ISA] Hercules InColor", "incolor", &incolor_device }, + { "[ISA] Image Manager 1024", "im1024", &im1024_device }, + { "[ISA] MDA", "mda", &mda_device }, + { "[ISA] MDSI Genius", "genius", &genius_device }, + { "[ISA] OAK OTI-037C", "oti037c", &oti037c_device }, + { "[ISA] OAK OTI-067", "oti067", &oti067_device }, + { "[ISA] OAK OTI-077", "oti077", &oti077_device }, + { "[ISA] Orchid Fahrenheit 1280 (S3 86c911)", "orchid_s3_911", &s3_orchid_86c911_isa_device }, + { "[ISA] Paradise PVGA1A", "pvga1a", ¶dise_pvga1a_device }, + { "[ISA] Paradise WD90C11-LR", "wd90c11", ¶dise_wd90c11_device }, + { "[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device }, + { "[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device }, + { "[ISA] Professional Graphics Controller", "pgc", &pgc_device }, + { "[ISA] Sigma Color 400", "sigma400", &sigma_device }, + { "[ISA] SPEA V7 Mirage (S3 86c801)", "px_s3_v7_801_isa", &s3_v7mirage_86c801_isa_device }, #if defined(DEV_BRANCH) && defined(USE_TI) - { "[ISA] TI CF62011 SVGA", "ti_cf62011", &ti_cf62011_device, GFX_TICF62011, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] TI CF62011 SVGA", "ti_cf62011", &ti_cf62011_device }, #endif - {"[ISA] Trident TVGA8900D", "tvga8900d", &tvga8900d_device, GFX_TVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - {"[ISA] Tseng ET4000AX", "et4000ax", &et4000_isa_device, GFX_ET4000_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - {"[ISA] VGA", "vga", &vga_device, GFX_VGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Wyse 700", "wy700", &wy700_device, GFX_WY700, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[MCA] Tseng ET4000AX", "et4000mca", &et4000_mca_device, GFX_ET4000_MCA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 3, 6, 5, 5, 10}}, - {"[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device, GFX_MACH64GX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, - {"[PCI] ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, - {"[PCI] Cardex Tseng ET4000/w32p", "et4000w32p_pci", &et4000w32p_cardex_pci_device, GFX_ET4000W32_CARDEX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, - {"[PCI] Cirrus Logic CL-GD 5430", "cl_gd5430_pci", &gd5430_pci_device, GFX_CL_GD5430_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[PCI] Cirrus Logic CL-GD 5434", "cl_gd5434_pci", &gd5434_pci_device, GFX_CL_GD5434_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[PCI] Cirrus Logic CL-GD 5436", "cl_gd5436_pci", &gd5436_pci_device, GFX_CL_GD5436_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[PCI] Cirrus Logic CL-GD 5440", "cl_gd5440_pci", &gd5440_pci_device, GFX_CL_GD5440_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[PCI] Cirrus Logic CL-GD 5446", "cl_gd5446_pci", &gd5446_pci_device, GFX_CL_GD5446_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[PCI] Cirrus Logic CL-GD 5480", "cl_gd5480_pci", &gd5480_pci_device, GFX_CL_GD5480_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) - {"[PCI] Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32_pci", &et4000w32p_pci_device, GFX_ET4000W32_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, + { "[ISA] Trident TVGA8900B", "tvga8900b", &tvga8900b_device }, + { "[ISA] Trident TVGA8900D", "tvga8900d", &tvga8900d_device }, + { "[ISA] Trigem Korean VGA (ET4000AX)", "tgkorvga", &et4000k_isa_device }, + { "[ISA] Tseng ET4000AX", "et4000ax", &et4000_isa_device }, + { "[ISA] VGA", "vga", &vga_device }, + { "[ISA] Video 7 VGA 1024i", "v7_vga_1024i", &v7_vga_1024i_device }, + { "[ISA] Wyse 700", "wy700", &wy700_device }, + { "[MCA] Tseng ET4000AX", "et4000mca", &et4000_mca_device }, + { "[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device }, + { "[PCI] ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device }, + { "[PCI] Cardex Tseng ET4000/w32p", "et4000w32p_pci", &et4000w32p_cardex_pci_device }, + { "[PCI] Cirrus Logic CL-GD 5430", "cl_gd5430_pci", &gd5430_pci_device, }, + { "[PCI] Cirrus Logic CL-GD 5434", "cl_gd5434_pci", &gd5434_pci_device }, + { "[PCI] Cirrus Logic CL-GD 5436", "cl_gd5436_pci", &gd5436_pci_device }, + { "[PCI] Cirrus Logic CL-GD 5440", "cl_gd5440_pci", &gd5440_pci_device }, + { "[PCI] Cirrus Logic CL-GD 5446", "cl_gd5446_pci", &gd5446_pci_device }, + { "[PCI] Cirrus Logic CL-GD 5480", "cl_gd5480_pci", &gd5480_pci_device }, + { "[PCI] Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32_pci", &et4000w32p_pci_device }, + { "[PCI] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_pci", &s3_virge_pci_device }, + { "[PCI] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_pci", &s3_virge_988_pci_device }, + { "[PCI] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_pci", &s3_diamond_stealth64_pci_device }, + { "[PCI] Diamond Stealth 64 VRAM (S3 Vision964)", "stealth64v_pci", &s3_diamond_stealth64_964_pci_device }, + { "[PCI] Number Nine 9FX (S3 Trio64)", "n9_9fx_pci", &s3_9fx_pci_device }, + { "[PCI] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_pci", &s3_bahamas64_pci_device }, + { "[PCI] Phoenix S3 Vision864", "px_vision864_pci", &s3_phoenix_vision864_pci_device }, + { "[PCI] Phoenix S3 Trio32", "px_trio32_pci", &s3_phoenix_trio32_pci_device }, + { "[PCI] Phoenix S3 Trio64", "px_trio64_pci", &s3_phoenix_trio64_pci_device }, + { "[PCI] S3 ViRGE/DX", "virge375_pci", &s3_virge_375_pci_device }, + { "[PCI] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_pci", &s3_virge_375_4_pci_device }, + { "[PCI] STB Nitro 64V (CL-GD 5446)", "cl_gd5446_stb_pci", &gd5446_stb_pci_device }, + { "[PCI] Trident TGUI9440", "tgui9440_pci", &tgui9440_pci_device }, + { "[VLB] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_vlb", &mach64gx_vlb_device }, + { "[VLB] Cardex Tseng ET4000/w32p", "et4000w32p_vlb", &et4000w32p_cardex_vlb_device }, +#if defined(DEV_BRANCH) && defined(USE_CL5422) + { "[VLB] Cirrus Logic CL-GD 5424", "cl_gd5424_vlb", &gd5424_vlb_device }, #endif - {"[PCI] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_pci", &s3_virge_pci_device, GFX_VIRGE_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[PCI] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_pci", &s3_virge_988_pci_device, GFX_VIRGEVX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, - {"[PCI] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_pci", &s3_diamond_stealth64_pci_device, GFX_STEALTH64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, -#if defined(DEV_BRANCH) && defined(USE_RIVA) - {"[PCI] nVidia RIVA 128", "riva128", &riva128_device, GFX_RIVA128, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}}, - /*{"[PCI] nVidia RIVA TNT", "rivatnt", &rivatnt_device, GFX_RIVATNT, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}}, - {"[PCI] nVidia RIVA TNT2", "rivatnt2", &rivatnt2_device, GFX_RIVATNT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}},*/ -#endif - {"[PCI] Number Nine 9FX (S3 Trio64)", "n9_9fx_pci", &s3_9fx_pci_device, GFX_N9_9FX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[PCI] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_pci", &s3_bahamas64_pci_device, GFX_BAHAMAS64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, - {"[PCI] Phoenix S3 Vision864", "px_vision864_pci", &s3_phoenix_vision864_pci_device, GFX_PHOENIX_VISION864_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, - {"[PCI] Phoenix S3 Trio32", "px_trio32_pci", &s3_phoenix_trio32_pci_device, GFX_PHOENIX_TRIO32_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[PCI] Phoenix S3 Trio64", "px_trio64_pci", &s3_phoenix_trio64_pci_device, GFX_PHOENIX_TRIO64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[PCI] S3 ViRGE/DX", "virge375_pci", &s3_virge_375_pci_device, GFX_VIRGEDX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[PCI] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_pci", &s3_virge_375_4_pci_device, GFX_VIRGEDX4_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[PCI] STB Nitro 64V (CL-GD 5446)", "cl_gd5446_stb_pci", &gd5446_stb_pci_device, GFX_CL_GD5446_STB_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[PCI] Trident TGUI9440", "tgui9440_pci", &tgui9440_pci_device, GFX_TGUI9440_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, - {"[VLB] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_vlb", &mach64gx_vlb_device, GFX_MACH64GX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, - {"[VLB] Cardex Tseng ET4000/w32p", "et4000w32p_vlb", &et4000w32p_cardex_vlb_device, GFX_ET4000W32_CARDEX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, - {"[VLB] Cirrus Logic CL-GD 5428", "cl_gd5428_vlb", &gd5428_vlb_device, GFX_CL_GD5428_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[VLB] Cirrus Logic CL-GD 5429", "cl_gd5429_vlb", &gd5429_vlb_device, GFX_CL_GD5429_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[VLB] Cirrus Logic CL-GD 5434", "cl_gd5434_vlb", &gd5434_vlb_device, GFX_CL_GD5434_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) - {"[VLB] Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32_vlb", &et4000w32p_vlb_device, GFX_ET4000W32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, -#endif - {"[VLB] Diamond SpeedStar PRO (CL-GD 5426)", "cl_gd5426_vlb", &gd5426_vlb_device, GFX_CL_GD5426_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[VLB] Diamond SpeedStar PRO SE (CL-GD 5430)", "cl_gd5430_vlb", &gd5430_vlb_device, GFX_CL_GD5430_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[VLB] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_vlb", &s3_virge_vlb_device, GFX_VIRGE_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[VLB] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_vlb", &s3_virge_988_vlb_device, GFX_VIRGEVX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, - {"[VLB] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_vlb", &s3_diamond_stealth64_vlb_device, GFX_STEALTH64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, - {"[VLB] Number Nine 9FX (S3 Trio64)", "n9_9fx_vlb", &s3_9fx_vlb_device, GFX_N9_9FX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[VLB] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_vlb", &s3_bahamas64_vlb_device, GFX_BAHAMAS64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, - {"[VLB] Phoenix S3 Vision864", "px_vision864_vlb", &s3_phoenix_vision864_vlb_device, GFX_PHOENIX_VISION864_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, - {"[VLB] Phoenix S3 Trio32", "px_trio32_vlb", &s3_phoenix_trio32_vlb_device, GFX_PHOENIX_TRIO32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[VLB] Phoenix S3 Trio64", "px_trio64_vlb", &s3_phoenix_trio64_vlb_device, GFX_PHOENIX_TRIO64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[VLB] S3 ViRGE/DX", "virge375_vlb", &s3_virge_375_vlb_device, GFX_VIRGEDX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[VLB] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_vlb", &s3_virge_375_4_vlb_device, GFX_VIRGEDX4_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[VLB] Trident TGUI9400CXi", "tgui9400cxi_vlb", &tgui9400cxi_device, GFX_TGUI9400CXI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, - {"[VLB] Trident TGUI9440", "tgui9440_vlb", &tgui9440_vlb_device, GFX_TGUI9440_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, - {"", "", NULL, -1 } + { "[VLB] Cirrus Logic CL-GD 5428", "cl_gd5428_vlb", &gd5428_vlb_device }, + { "[VLB] Cirrus Logic CL-GD 5429", "cl_gd5429_vlb", &gd5429_vlb_device }, + { "[VLB] Cirrus Logic CL-GD 5434", "cl_gd5434_vlb", &gd5434_vlb_device }, + { "[VLB] Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32_vlb", &et4000w32p_vlb_device }, + { "[VLB] Diamond SpeedStar PRO (CL-GD 5426)", "cl_gd5426_vlb", &gd5426_vlb_device }, + { "[VLB] Diamond SpeedStar PRO SE (CL-GD 5430)", "cl_gd5430_vlb", &gd5430_vlb_device }, + { "[VLB] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_vlb", &s3_virge_vlb_device }, + { "[VLB] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_vlb", &s3_virge_988_vlb_device }, + { "[VLB] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_vlb", &s3_diamond_stealth64_vlb_device }, + { "[VLB] Diamond Stealth 64 VRAM (S3 Vision964)", "stealth64v_vlb", &s3_diamond_stealth64_964_vlb_device }, + { "[VLB] Number Nine 9FX (S3 Trio64)", "n9_9fx_vlb", &s3_9fx_vlb_device }, + { "[VLB] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_vlb", &s3_bahamas64_vlb_device }, + { "[VLB] Phoenix S3 86c805", "px_86c805_vlb", &s3_phoenix_86c805_vlb_device }, + { "[VLB] Phoenix S3 Vision864", "px_vision864_vlb", &s3_phoenix_vision864_vlb_device }, + { "[VLB] Phoenix S3 Trio32", "px_trio32_vlb", &s3_phoenix_trio32_vlb_device }, + { "[VLB] Phoenix S3 Trio64", "px_trio64_vlb", &s3_phoenix_trio64_vlb_device }, + { "[VLB] S3 ViRGE/DX", "virge375_vlb", &s3_virge_375_vlb_device }, + { "[VLB] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_vlb", &s3_virge_375_4_vlb_device }, + { "[VLB] Trident TGUI9400CXi", "tgui9400cxi_vlb", &tgui9400cxi_device }, + { "[VLB] Trident TGUI9440", "tgui9440_vlb", &tgui9440_vlb_device }, + { "", "", NULL } }; #ifdef ENABLE_VID_TABLE_LOG int vid_table_do_log = ENABLE_VID_TABLE_LOG; -#endif static void vid_table_log(const char *fmt, ...) { -#ifdef ENABLE_VID_TABLE_LOG va_list ap; if (vid_table_do_log) { @@ -201,37 +200,63 @@ vid_table_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } +} +#else +#define vid_table_log(fmt, ...) #endif + + +void +video_reset_close(void) +{ + video_inform(VIDEO_FLAG_TYPE_NONE, &timing_default); + was_reset = 0; } void video_reset(int card) { - vid_table_log("VIDEO: reset (romset=%d, gfxcard=%d, internal=%d)\n", - romset, card, (machines[machine].flags & MACHINE_VIDEO)?1:0); + /* This is needed to avoid duplicate resets. */ + if ((video_get_type() != VIDEO_FLAG_TYPE_NONE) && was_reset) + return; - /* Reset the CGA palette. */ - cga_palette = 0; - cgapal_rebuild(); + vid_table_log("VIDEO: reset (gfxcard=%d, internal=%d)\n", + card, (machines[machine].flags & MACHINE_VIDEO)?1:0); + loadfont(L"roms/video/mda/mda.rom", 0); + + /* Reset (deallocate) the video font arrays. */ if (fontdatksc5601) { free(fontdatksc5601); fontdatksc5601 = NULL; } + /* Reset the CGA palette. */ + cga_palette = 0; + cgapal_rebuild(); + + /* Reset the blend. */ + herc_blend = 0; + /* Do not initialize internal cards here. */ - if (!(card == GFX_NONE) && \ - !(card == GFX_INTERNAL) && !machines[machine].fixed_gfxcard) { - vid_table_log("VIDEO: initializing '%s'\n", video_cards[video_old_to_new(card)].name); + if (!(card == VID_NONE) && \ + !(card == VID_INTERNAL) && !(machines[machine].flags & MACHINE_VIDEO_FIXED)) { + vid_table_log("VIDEO: initializing '%s'\n", video_cards[card].name); + + /* Do an inform on the default values, so that that there's some sane values initialized + even if the device init function does not do an inform of its own. */ + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_default); /* Initialize the video card. */ - device_add(video_cards[video_old_to_new(card)].device); + device_add(video_cards[card].device); } /* Enable the Voodoo if configured. */ if (voodoo_enabled) device_add(&voodoo_device); + + was_reset = 1; } @@ -268,19 +293,12 @@ video_card_has_config(int card) } -video_timings_t * -video_card_gettiming(int card) -{ - return((void *) &video_cards[card].timing); -} - - int video_card_getid(char *s) { int c = 0; - while (video_cards[c].legacy_id != -1) { + while (video_cards[c].name != NULL) { if (!strcmp((char *) video_cards[c].name, s)) return(c); c++; @@ -290,28 +308,6 @@ video_card_getid(char *s) } -int -video_old_to_new(int card) -{ - int c = 0; - - while (video_cards[c].legacy_id != -1) { - if (video_cards[c].legacy_id == card) - return(c); - c++; - } - - return(0); -} - - -int -video_new_to_old(int card) -{ - return(video_cards[card].legacy_id); -} - - char * video_get_internal_name(int card) { @@ -324,105 +320,32 @@ video_get_video_from_internal_name(char *s) { int c = 0; - while (video_cards[c].legacy_id != -1) { + while (video_cards[c].name != NULL) { if (!strcmp((char *) video_cards[c].internal_name, s)) - return(video_cards[c].legacy_id); + return(c); c++; } return(0); } -int video_is_mda(void) + +int +video_is_mda(void) { - switch (romset) - { - case ROM_IBMPCJR: - case ROM_TANDY: - case ROM_TANDY1000HX: - case ROM_TANDY1000SL2: - case ROM_PC1512: - case ROM_PC1640: - case ROM_PC200: - case ROM_OLIM24: - case ROM_PC2086: - case ROM_PC3086: - case ROM_MEGAPC: - case ROM_MEGAPCDX: - 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_T3100E: - return 0; - } - return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_MDA; + return (video_get_type() == VIDEO_FLAG_TYPE_MDA); } -int video_is_cga(void) + +int +video_is_cga(void) { - switch (romset) - { - case ROM_IBMPCJR: - case ROM_TANDY: - case ROM_TANDY1000HX: - case ROM_TANDY1000SL2: - case ROM_PC1512: - case ROM_PC200: - case ROM_OLIM24: - case ROM_T3100E: - return 1; - - case ROM_PC1640: - case ROM_PC2086: - case ROM_PC3086: - case ROM_MEGAPC: - case ROM_MEGAPCDX: - 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: - return 0; - } - return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_CGA; + return (video_get_type() == VIDEO_FLAG_TYPE_CGA); } -int video_is_ega_vga(void) + +int +video_is_ega_vga(void) { - switch (romset) - { - case ROM_IBMPCJR: - case ROM_TANDY: - case ROM_TANDY1000HX: - case ROM_TANDY1000SL2: - case ROM_PC1512: - case ROM_PC200: - case ROM_OLIM24: - case ROM_T3100E: - return 0; - - case ROM_PC1640: - case ROM_PC2086: - case ROM_PC3086: - case ROM_MEGAPC: - case ROM_MEGAPCDX: - 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: - return 1; - } - return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_SPECIAL; + return (video_get_type() == VIDEO_FLAG_TYPE_SPECIAL); } diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 9b01d5661..c366fae12 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -47,13 +47,13 @@ * access size or host data has any affect, but the Windows 3.1 * driver always reads bytes and write words of 0xffff. * - * Version: @(#)vid_tgui9440.c 1.0.7 2018/07/16 + * Version: @(#)vid_tgui9440.c 1.0.10 2019/09/28 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -62,6 +62,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../pci.h" #include "../rom.h" @@ -105,6 +106,9 @@ 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 ROM_TGUI_9400CXI L"roms/video/tgui9440/9400CXI.vbi" +#define ROM_TGUI_9440 L"roms/video/tgui9440/9440.vbi" + #define EXT_CTRL_16BIT 0x01 #define EXT_CTRL_MONO_EXPANSION 0x02 #define EXT_CTRL_MONO_TRANSPARENT 0x04 @@ -152,8 +156,6 @@ typedef struct tgui_t svga_t svga; int pci; - tkd8001_ramdac_t ramdac; /*TGUI9400CXi*/ - int type; struct @@ -210,6 +212,8 @@ typedef struct tgui_t volatile int write_blitter; } tgui_t; +video_timings_t timing_tgui = {VIDEO_BUS, 4, 8, 16, 4, 8, 16}; + void tgui_recalcmapping(tgui_t *tgui); static void fifo_thread(void *param); @@ -255,7 +259,7 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) break; case 0xC: if (svga->seqregs[0xe] & 0x80) - svga->seqregs[0xc] = val; + svga->seqregs[0xc] = val; break; case 0xd: if (tgui->oldmode) @@ -280,7 +284,7 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) case 0x3C6: if (tgui->type == TGUI_9400CXI) { - tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga); + tkd8001_ramdac_out(addr, val, svga->ramdac, svga); return; } if (tgui->ramdac_state == 4) @@ -307,7 +311,7 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) case 0x3C7: case 0x3C8: case 0x3C9: if (tgui->type == TGUI_9400CXI) { - tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga); + tkd8001_ramdac_out(addr, val, svga->ramdac, svga); return; } tgui->ramdac_state = 0; @@ -461,14 +465,14 @@ uint8_t tgui_in(uint16_t addr, void *p) break; case 0x3C6: if (tgui->type == TGUI_9400CXI) - return tkd8001_ramdac_in(addr, &tgui->ramdac, svga); + return tkd8001_ramdac_in(addr, svga->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); + return tkd8001_ramdac_in(addr, svga->ramdac, svga); tgui->ramdac_state = 0; break; case 0x3CF: @@ -514,20 +518,11 @@ void tgui_recalctimings(svga_t *svga) svga->interlace = svga->crtc[0x1e] & 4; if (svga->interlace && tgui->type < TGUI_9440) svga->rowoffset >>= 1; - - if (svga->crtc[0x17] & 4) - { - svga->vtotal *= 2; - svga->dispend *= 2; - svga->vsyncstart *= 2; - svga->split *= 2; - svga->vblankstart *= 2; - } if (tgui->type >= TGUI_9440) { if (svga->miscout & 8) - svga->clock = cpuclock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + 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; @@ -538,20 +533,20 @@ void tgui_recalctimings(svga_t *svga) { switch (((svga->miscout >> 2) & 3) | ((tgui->newctrl2 << 2) & 4) | ((tgui->newctrl2 >> 3) & 8)) { - case 0x02: svga->clock = cpuclock/ 44900000.0; break; - case 0x03: svga->clock = cpuclock/ 36000000.0; break; - case 0x04: svga->clock = cpuclock/ 57272000.0; break; - case 0x05: svga->clock = cpuclock/ 65000000.0; break; - case 0x06: svga->clock = cpuclock/ 50350000.0; break; - case 0x07: svga->clock = cpuclock/ 40000000.0; break; - case 0x08: svga->clock = cpuclock/ 88000000.0; break; - case 0x09: svga->clock = cpuclock/ 98000000.0; break; - case 0x0a: svga->clock = cpuclock/118800000.0; break; - case 0x0b: svga->clock = cpuclock/108000000.0; break; - case 0x0c: svga->clock = cpuclock/ 72000000.0; break; - case 0x0d: svga->clock = cpuclock/ 77000000.0; break; - case 0x0e: svga->clock = cpuclock/ 80000000.0; break; - case 0x0f: svga->clock = cpuclock/ 75000000.0; break; + 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) { @@ -686,10 +681,6 @@ void tgui_hwcursor_draw(svga_t *svga, int displine) uint32_t dat[2]; int xx; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int y_add, x_add; - - y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; - x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 8; @@ -701,9 +692,9 @@ void tgui_hwcursor_draw(svga_t *svga, int displine) if (offset >= svga->hwcursor_latch.x) { if (!(dat[0] & 0x80000000)) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x80000000) ? 0xffffff : 0; + buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x80000000) ? 0xffffff : 0; else if (dat[1] & 0x80000000) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; } offset++; @@ -775,99 +766,13 @@ void tgui_pci_write(int func, int addr, uint8_t val, void *p) } } -static void *tgui_init(const device_t *info, wchar_t *bios_fn, int type) -{ - tgui_t *tgui = malloc(sizeof(tgui_t)); - memset(tgui, 0, sizeof(tgui_t)); - - tgui->vram_size = device_get_config_int("memory") << 20; - tgui->vram_mask = tgui->vram_size - 1; - - tgui->type = type; - - tgui->pci = !!(info->flags & DEVICE_PCI); - - rom_init(&tgui->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - - svga_init(&tgui->svga, tgui, tgui->vram_size, - tgui_recalctimings, - tgui_in, tgui_out, - tgui_hwcursor_draw, - NULL); - - mem_mapping_add(&tgui->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, 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); - if (tgui->type >= TGUI_9440) - io_sethandler(0x43c8, 0x0002, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); - - if ((info->flags & DEVICE_PCI) && (tgui->type >= TGUI_9440)) - pci_add_card(PCI_ADD_VIDEO, tgui_pci_read, tgui_pci_write, tgui); - - tgui->wake_fifo_thread = thread_create_event(); - tgui->fifo_not_full_event = thread_create_event(); - tgui->fifo_thread = thread_create(fifo_thread, tgui); - - return tgui; -} - -static void *tgui9400cxi_init(const device_t *info) -{ - return tgui_init(info, L"roms/video/tgui9440/9400CXI.vbi", TGUI_9400CXI); -} - -static void *tgui9440_init(const device_t *info) -{ - return tgui_init(info, L"roms/video/tgui9440/9440.vbi", TGUI_9440); -} - -static int tgui9400cxi_available() -{ - return rom_present(L"roms/video/tgui9440/9400CXI.vbi"); -} - -static int tgui9440_available() -{ - return rom_present(L"roms/video/tgui9440/9440.vbi"); -} - -void tgui_close(void *p) -{ - tgui_t *tgui = (tgui_t *)p; - - svga_close(&tgui->svga); - - thread_kill(tgui->fifo_thread); - thread_destroy_event(tgui->wake_fifo_thread); - thread_destroy_event(tgui->fifo_not_full_event); - - free(tgui); -} - -void tgui_speed_changed(void *p) -{ - tgui_t *tgui = (tgui_t *)p; - - svga_recalctimings(&tgui->svga); -} - -void tgui_force_redraw(void *p) -{ - tgui_t *tgui = (tgui_t *)p; - - tgui->svga.fullchange = changeframecount; -} - - 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; + + sub_cycles(video_timing_read_b); addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -898,7 +803,7 @@ static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) 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; + sub_cycles(video_timing_write_b); addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -967,7 +872,7 @@ static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) 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; + sub_cycles(video_timing_write_w); addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -1730,6 +1635,102 @@ void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *p) svga_writel_linear(addr, val, svga); } +static void *tgui_init(const device_t *info) +{ + const wchar_t *bios_fn; + int type = info->local; + + tgui_t *tgui = malloc(sizeof(tgui_t)); + memset(tgui, 0, sizeof(tgui_t)); + + tgui->vram_size = device_get_config_int("memory") << 20; + tgui->vram_mask = tgui->vram_size - 1; + + tgui->type = type; + + tgui->pci = !!(info->flags & DEVICE_PCI); + + switch(info->local) { + case TGUI_9400CXI: + bios_fn = ROM_TGUI_9400CXI; + break; + case TGUI_9440: + bios_fn = ROM_TGUI_9440; + break; + default: + free(tgui); + return NULL; + } + + rom_init(&tgui->bios_rom, (wchar_t *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_tgui); + + svga_init(&tgui->svga, tgui, tgui->vram_size, + tgui_recalctimings, + tgui_in, tgui_out, + tgui_hwcursor_draw, + NULL); + + if (tgui->type == TGUI_9400CXI) + tgui->svga.ramdac = device_add(&tkd8001_ramdac_device); + + 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, MEM_MAPPING_EXTERNAL, &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, MEM_MAPPING_EXTERNAL, tgui); + mem_mapping_disable(&tgui->accel_mapping); + + io_sethandler(0x03c0, 0x0020, 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); + + if ((info->flags & DEVICE_PCI) && (tgui->type >= TGUI_9440)) + pci_add_card(PCI_ADD_VIDEO, tgui_pci_read, tgui_pci_write, tgui); + + tgui->wake_fifo_thread = thread_create_event(); + tgui->fifo_not_full_event = thread_create_event(); + tgui->fifo_thread = thread_create(fifo_thread, tgui); + + return tgui; +} + +static int tgui9400cxi_available() +{ + return rom_present(L"roms/video/tgui9440/9400CXI.vbi"); +} + +static int tgui9440_available() +{ + return rom_present(L"roms/video/tgui9440/9440.vbi"); +} + +void tgui_close(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_close(&tgui->svga); + + thread_kill(tgui->fifo_thread); + thread_destroy_event(tgui->wake_fifo_thread); + thread_destroy_event(tgui->fifo_not_full_event); + + free(tgui); +} + +void tgui_speed_changed(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_recalctimings(&tgui->svga); +} + +void tgui_force_redraw(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + tgui->svga.fullchange = changeframecount; +} + + static const device_config_t tgui9440_config[] = { { @@ -1761,8 +1762,8 @@ const device_t tgui9400cxi_device = { "Trident TGUI 9400CXi", DEVICE_VLB, - 0, - tgui9400cxi_init, + TGUI_9400CXI, + tgui_init, tgui_close, NULL, tgui9400cxi_available, @@ -1775,8 +1776,8 @@ const device_t tgui9440_vlb_device = { "Trident TGUI 9440 VLB", DEVICE_VLB, - 0, - tgui9440_init, + TGUI_9440, + tgui_init, tgui_close, NULL, tgui9440_available, @@ -1789,12 +1790,12 @@ const device_t tgui9440_pci_device = { "Trident TGUI 9440 PCI", DEVICE_PCI, - 0, - tgui9440_init, + TGUI_9440, + tgui_init, tgui_close, NULL, tgui9440_available, tgui_speed_changed, tgui_force_redraw, tgui9440_config -}; \ No newline at end of file +}; diff --git a/src/video/vid_ti_cf62011.c b/src/video/vid_ti_cf62011.c index d3ec979f1..e77ce27c9 100644 --- a/src/video/vid_ti_cf62011.c +++ b/src/video/vid_ti_cf62011.c @@ -42,7 +42,7 @@ * which are the same as the XGA. It supports up to 1MB of VRAM, * but we lock it down to 512K. The PS/1 2122 had 256K. * - * Version: @(#)vid_ti_cf62011.c 1.0.7 2018/04/29 + * Version: @(#)vid_ti_cf62011.c 1.0.9 2018/10/02 * * Authors: Sarah Walker, * Miran Grca, @@ -58,8 +58,8 @@ #include #include #include "../86box.h" -#include "../config.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -83,6 +83,8 @@ typedef struct { uint8_t reg_210a; } tivga_t; +static video_timings_t timing_ti_cf62011 = {VIDEO_ISA, 6, 8,16, 6, 8,16}; + static void vid_out(uint16_t addr, uint8_t val, void *priv) @@ -243,9 +245,11 @@ vid_init(const device_t *info) /* Set amount of VRAM in KB. */ if (info->local == 0) ti->vram_size = device_get_config_int("vram_size"); - else + else ti->vram_size = info->local; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ti_cf62011); + svga_init(&ti->svga, ti, ti->vram_size<<10, NULL, vid_in, vid_out, NULL, NULL); @@ -289,7 +293,7 @@ static const device_config_t vid_config[] = const device_t ti_cf62011_device = { "TI CF62011 SVGA", - 0, + DEVICE_ISA, 0, vid_init, vid_close, NULL, NULL, @@ -302,7 +306,7 @@ const device_t ti_cf62011_device = { const device_t ibm_ps1_2121_device = { "IBM PS/1 Model 2121 SVGA", - 0, + DEVICE_ISA, 512, vid_init, vid_close, NULL, NULL, diff --git a/src/video/vid_tkd8001_ramdac.c b/src/video/vid_tkd8001_ramdac.c index e2d266cac..e7c381a79 100644 --- a/src/video/vid_tkd8001_ramdac.c +++ b/src/video/vid_tkd8001_ramdac.c @@ -8,73 +8,110 @@ * * Trident TKD8001 RAMDAC emulation. * - * Version: @(#)vid_tkd8001_ramdac.c 1.0.2 2017/11/04 + * Version: @(#)vid_tkd8001_ramdac.c 1.0.3 2018/10/04 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "../86box.h" +#include "../device.h" +#include "../timer.h" #include "../mem.h" #include "video.h" #include "vid_svga.h" #include "vid_tkd8001_ramdac.h" -void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga) +void +tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga) { - switch (addr) - { - case 0x3C6: - if (ramdac->state == 4) - { - ramdac->state = 0; - ramdac->ctrl = val; - switch (val >> 5) - { - case 0: case 1: case 2: case 3: - svga->bpp = 8; - break; - case 5: - svga->bpp = 15; - break; - case 6: - svga->bpp = 24; - break; - case 7: - svga->bpp = 16; - break; - } - return; - } - break; - case 0x3C7: case 0x3C8: case 0x3C9: - ramdac->state = 0; - break; - } - svga_out(addr, val, svga); + switch (addr) { + case 0x3C6: + if (ramdac->state == 4) { + ramdac->state = 0; + ramdac->ctrl = val; + switch (val >> 5) { + case 0: + case 1: + case 2: + case 3: + svga->bpp = 8; + break; + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 24; + break; + case 7: + svga->bpp = 16; + break; + } + return; + } + break; + case 0x3C7: + case 0x3C8: + case 0x3C9: + ramdac->state = 0; + break; + } + + svga_out(addr, val, svga); } -uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga) + +uint8_t +tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga) { - switch (addr) - { - case 0x3C6: - if (ramdac->state == 4) - { - return ramdac->ctrl; - } - ramdac->state++; - break; - case 0x3C7: case 0x3C8: case 0x3C9: - ramdac->state = 0; - break; - } - return svga_in(addr, svga); + switch (addr) { + case 0x3C6: + if (ramdac->state == 4) + return ramdac->ctrl; + ramdac->state++; + break; + case 0x3C7: + case 0x3C8: + case 0x3C9: + ramdac->state = 0; + break; + } + return svga_in(addr, svga); } + + +static void * +tkd8001_ramdac_init(const device_t *info) +{ + tkd8001_ramdac_t *ramdac = (tkd8001_ramdac_t *) malloc(sizeof(tkd8001_ramdac_t)); + memset(ramdac, 0, sizeof(tkd8001_ramdac_t)); + + return ramdac; +} + + +static void +tkd8001_ramdac_close(void *priv) +{ + tkd8001_ramdac_t *ramdac = (tkd8001_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + + +const device_t tkd8001_ramdac_device = +{ + "Trident TKD8001 RAMDAC", + 0, 0, + tkd8001_ramdac_init, tkd8001_ramdac_close, + NULL, NULL, NULL, NULL +}; diff --git a/src/video/vid_tkd8001_ramdac.h b/src/video/vid_tkd8001_ramdac.h index f83ba978d..3cfa166b0 100644 --- a/src/video/vid_tkd8001_ramdac.h +++ b/src/video/vid_tkd8001_ramdac.h @@ -1,11 +1,28 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Trident TKD8001 RAMDAC emulation header. + * + * Version: @(#)vid_tkd8001_ramdac.h 1.0.0 2018/10/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ typedef struct tkd8001_ramdac_t { - int state; - uint8_t ctrl; + int state; + uint8_t ctrl; } tkd8001_ramdac_t; -void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga); -uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga); +extern void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga); +extern uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga); + +extern const device_t tkd8001_ramdac_device; diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index 84bc2421e..8e2fd3bc3 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -8,7 +8,7 @@ * * Trident TVGA (8900D) emulation. * - * Version: @(#)vid_tvga.c 1.0.6 2018/04/26 + * Version: @(#)vid_tvga.c 1.0.9 2018/12/28 * * Authors: Sarah Walker, * Miran Grca, @@ -23,6 +23,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -32,6 +33,11 @@ #include "vid_tkd8001_ramdac.h" #include "vid_tvga.h" +#define TVGA8900B_ID 0x03 +#define TVGA8900CLD_ID 0x33 + +#define ROM_TVGA_8900B L"roms/video/tvga/tvga8900B.VBI" +#define ROM_TVGA_8900CLD L"roms/video/tvga/trident.bin" typedef struct tvga_t { @@ -39,9 +45,9 @@ typedef struct tvga_t mem_mapping_t accel_mapping; svga_t svga; - tkd8001_ramdac_t ramdac; - + rom_t bios_rom; + uint8_t card_id; uint8_t tvga_3d8, tvga_3d9; int oldmode; @@ -52,6 +58,8 @@ typedef struct tvga_t uint32_t vram_mask; } tvga_t; +video_timings_t timing_tvga = {VIDEO_ISA, 3, 3, 6, 8, 8, 12}; + static uint8_t crtc_mask[0x40] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -109,7 +117,7 @@ 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); + tkd8001_ramdac_out(addr, val, svga->ramdac, svga); return; case 0x3CF: @@ -183,7 +191,7 @@ uint8_t tvga_in(uint16_t addr, void *p) if ((svga->seqaddr & 0xf) == 0xb) { tvga->oldmode = 0; - return 0x33; /*TVGA8900D*/ + return tvga->card_id; /*Must be at least a TVGA8900*/ } if ((svga->seqaddr & 0xf) == 0xd) { @@ -197,7 +205,7 @@ 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); + return tkd8001_ramdac_in(addr, svga->ramdac, svga); case 0x3D4: return svga->crtcreg; case 0x3D5: @@ -236,15 +244,16 @@ void tvga_recalctimings(svga_t *svga) if (svga->bpp == 24) svga->hdisp = (svga->crtc[1] + 1) * 8; - if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; - if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; - if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; - + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; + if (tvga->oldctrl2 & 0x10) { svga->rowoffset <<= 1; svga->ma_latch <<= 1; } + if (svga->gdcreg[0xf] & 0x08) { svga->htotal *= 2; @@ -252,19 +261,19 @@ void tvga_recalctimings(svga_t *svga) svga->hdisp_time *= 2; } - svga->interlace = (svga->crtc[0x1e] & 4); + svga->interlace = (svga->crtc[0x1e] & 4); if (svga->interlace) svga->rowoffset >>= 1; switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4)) { - case 2: svga->clock = cpuclock/44900000.0; break; - case 3: svga->clock = cpuclock/36000000.0; break; - case 4: svga->clock = cpuclock/57272000.0; break; - case 5: svga->clock = cpuclock/65000000.0; break; - case 6: svga->clock = cpuclock/50350000.0; break; - case 7: svga->clock = cpuclock/40000000.0; break; + case 2: svga->clock = (cpuclock * (double)(1ull << 32))/44900000.0; break; + case 3: svga->clock = (cpuclock * (double)(1ull << 32))/36000000.0; break; + case 4: svga->clock = (cpuclock * (double)(1ull << 32))/57272000.0; break; + case 5: svga->clock = (cpuclock * (double)(1ull << 32))/65000000.0; break; + case 6: svga->clock = (cpuclock * (double)(1ull << 32))/50350000.0; break; + case 7: svga->clock = (cpuclock * (double)(1ull << 32))/40000000.0; break; } if (tvga->oldctrl2 & 0x10) @@ -272,7 +281,7 @@ void tvga_recalctimings(svga_t *svga) switch (svga->bpp) { case 8: - svga->render = svga_render_8bpp_highres; + svga->render = svga_render_8bpp_highres; break; case 15: svga->render = svga_render_15bpp_highres; @@ -292,30 +301,55 @@ void tvga_recalctimings(svga_t *svga) } -static void *tvga8900d_init(const device_t *info) +static void *tvga_init(const device_t *info) { + const wchar_t *bios_fn; tvga_t *tvga = malloc(sizeof(tvga_t)); memset(tvga, 0, sizeof(tvga_t)); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_tvga); tvga->vram_size = device_get_config_int("memory") << 10; tvga->vram_mask = tvga->vram_size - 1; - - rom_init(&tvga->bios_rom, L"roms/video/tvga/trident.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + tvga->card_id = info->local; + + switch (info->local) + { + case TVGA8900B_ID: + bios_fn = ROM_TVGA_8900B; + break; + case TVGA8900CLD_ID: + bios_fn = ROM_TVGA_8900CLD; + break; + default: + free(tvga); + return NULL; + } + + rom_init(&tvga->bios_rom, (wchar_t *) bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&tvga->svga, tvga, tvga->vram_size, tvga_recalctimings, tvga_in, tvga_out, NULL, NULL); + + tvga->svga.ramdac = device_add(&tkd8001_ramdac_device); io_sethandler(0x03c0, 0x0020, tvga_in, NULL, NULL, tvga_out, NULL, NULL, tvga); return tvga; } +static int tvga8900b_available(void) +{ + return rom_present(ROM_TVGA_8900B); +} + static int tvga8900d_available(void) { - return rom_present(L"roms/video/tvga/trident.bin"); + return rom_present(ROM_TVGA_8900CLD); } void tvga_close(void *p) @@ -366,12 +400,26 @@ static const device_config_t tvga_config[] = } }; +const device_t tvga8900b_device = +{ + "Trident TVGA 8900B", + DEVICE_ISA, + TVGA8900B_ID, + tvga_init, + tvga_close, + NULL, + tvga8900b_available, + tvga_speed_changed, + tvga_force_redraw, + tvga_config +}; + const device_t tvga8900d_device = { "Trident TVGA 8900D", DEVICE_ISA, - 0, - tvga8900d_init, + TVGA8900CLD_ID, + tvga_init, tvga_close, NULL, tvga8900d_available, diff --git a/src/video/vid_tvga.h b/src/video/vid_tvga.h index 43e1b778b..6a4f0105a 100644 --- a/src/video/vid_tvga.h +++ b/src/video/vid_tvga.h @@ -1,4 +1,5 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ +extern const device_t tvga8900b_device; extern const device_t tvga8900d_device; diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 5ea76dc83..b01e9fa53 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -8,7 +8,7 @@ * * IBM VGA emulation. * - * Version: @(#)vid_vga.c 1.0.5 2018/04/26 + * Version: @(#)vid_vga.c 1.0.6 2018/09/19 * * Authors: Sarah Walker, * Miran Grca, @@ -26,6 +26,7 @@ #include "../mem.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_vga.h" @@ -38,6 +39,10 @@ typedef struct vga_t rom_t bios_rom; } vga_t; +static video_timings_t timing_vga = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; +static video_timings_t timing_ps1_svga_isa = {VIDEO_ISA, 6, 8, 16, 6, 8, 16}; +static video_timings_t timing_ps1_svga_mca = {VIDEO_MCA, 6, 8, 16, 6, 8, 16}; + void vga_out(uint16_t addr, uint8_t val, void *p) { vga_t *vga = (vga_t *)p; @@ -109,6 +114,8 @@ static void *vga_init(const device_t *info) rom_init(&vga->bios_rom, L"roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_vga); + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ NULL, vga_in, vga_out, @@ -124,39 +131,17 @@ static void *vga_init(const device_t *info) } -#ifdef DEV_BRANCH -static void *trigem_unk_init(const device_t *info) -{ - vga_t *vga = malloc(sizeof(vga_t)); - memset(vga, 0, sizeof(vga_t)); - - rom_init(&vga->bios_rom, L"roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); - - svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ - NULL, - vga_in, vga_out, - NULL, - NULL); - - io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); - - io_sethandler(0x22ca, 0x0002, svga_in, NULL, NULL, vga_out, NULL, NULL, vga); - io_sethandler(0x22ce, 0x0002, svga_in, NULL, NULL, vga_out, NULL, NULL, vga); - io_sethandler(0x32ca, 0x0002, svga_in, NULL, NULL, vga_out, NULL, NULL, vga); - - vga->svga.bpp = 8; - vga->svga.miscout = 1; - - return vga; -} -#endif - /*PS/1 uses a standard VGA controller, but with no option ROM*/ void *ps1vga_init(const device_t *info) { vga_t *vga = malloc(sizeof(vga_t)); memset(vga, 0, sizeof(vga_t)); + if (info->flags & DEVICE_MCA) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ps1_svga_mca); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ps1_svga_isa); + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ NULL, vga_in, vga_out, @@ -212,25 +197,25 @@ const device_t vga_device = vga_force_redraw, NULL }; -#ifdef DEV_BRANCH -const device_t trigem_unk_device = -{ - "VGA", - DEVICE_ISA, - 0, - trigem_unk_init, - vga_close, - NULL, - vga_available, - vga_speed_changed, - vga_force_redraw, - NULL -}; -#endif + const device_t ps1vga_device = { "PS/1 VGA", - 0, + DEVICE_ISA, + 0, + ps1vga_init, + vga_close, + NULL, + vga_available, + vga_speed_changed, + vga_force_redraw, + NULL +}; + +const device_t ps1vga_mca_device = +{ + "PS/1 VGA", + DEVICE_MCA, 0, ps1vga_init, vga_close, diff --git a/src/video/vid_vga.h b/src/video/vid_vga.h index 44fa836fb..533fdbb9a 100644 --- a/src/video/vid_vga.h +++ b/src/video/vid_vga.h @@ -2,7 +2,5 @@ see COPYING for more details */ extern const device_t vga_device; -#ifdef DEV_BRANCH -extern const device_t trigem_unk_device; -#endif extern const device_t ps1vga_device; +extern const device_t ps1vga_mca_device; diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index 1bbdcc64a..2685aa2ac 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -8,7 +8,7 @@ * * Emulation of the 3DFX Voodoo Graphics controller. * - * Version: @(#)vid_voodoo.c 1.0.14 2018/04/26 + * Version: @(#)vid_voodoo.c 1.0.15 2018/10/18 * * Authors: Sarah Walker, * leilei @@ -215,6 +215,15 @@ typedef struct texture_t 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 voodoo_t { mem_mapping_t mapping; @@ -227,7 +236,7 @@ typedef struct voodoo_t uint16_t dac_pll_regs[16]; float pixel_clock; - int line_time; + uint64_t line_time; voodoo_params_t params; @@ -261,7 +270,7 @@ typedef struct voodoo_t int swap_count; int disp_buffer, draw_buffer; - int64_t timer_count; + pc_timer_t timer; int line; svga_t *svga; @@ -331,14 +340,7 @@ typedef struct voodoo_t 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]; + vert_t verts[4]; int vertex_num; int num_verticies; @@ -386,7 +388,7 @@ typedef struct voodoo_t int dst_stride; } blt; - rgbp_t clutData[33]; + rgbp_t clutData[64]; int clutData_dirty; rgbp_t clutData256[256]; uint32_t video_16to32[0x10000]; @@ -397,9 +399,9 @@ typedef struct voodoo_t int fb_write_buffer, fb_draw_buffer; int buffer_cutoff; - int64_t read_time, write_time, burst_time; + int read_time, write_time, burst_time; - int64_t wake_timer; + pc_timer_t wake_timer; uint8_t thefilter[256][256]; // pixel filter, feeding from one or two uint8_t thefilterg[256][256]; // for green @@ -1044,13 +1046,11 @@ enum #ifdef ENABLE_VOODOO_LOG int voodoo_do_log = ENABLE_VOODOO_LOG; -#endif static void voodoo_log(const char *fmt, ...) { -#ifdef ENABLE_VOODOO_LOG va_list ap; if (voodoo_do_log) { @@ -1058,8 +1058,10 @@ voodoo_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define voodoo_log(fmt, ...) +#endif static void voodoo_threshold_check(voodoo_t *voodoo); @@ -2656,9 +2658,9 @@ static inline void voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t state->tex_a[0] ^= 0xff; } -#if ((defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32) && !(defined __amd64__) && (defined USE_DYNAREC)) +#if ((defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86) && !(defined __amd64__ || defined _M_X64) && (defined USE_DYNAREC)) #include "vid_voodoo_codegen_x86.h" -#elif ((defined __amd64__) && (defined USE_DYNAREC)) +#elif ((defined __amd64__ || defined _M_X64) && (defined USE_DYNAREC)) #include "vid_voodoo_codegen_x86-64.h" #else #define NO_CODEGEN @@ -2802,7 +2804,10 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood { int x, x2; int real_y = (state->y << 4) + 8; - int start_x, start_x2; + int start_x; +#ifdef ENABLE_VOODOO_LOG + int start_x2; +#endif int dx; uint16_t *fb_mem, *aux_mem; @@ -2849,7 +2854,9 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood else x -= (1 << 16); dx = ((x + 0x7000) >> 16) - (((state->vertexAx << 12) + 0x7000) >> 16); +#ifdef ENABLE_VOODOO_LOG start_x2 = x + 0x7000; +#endif x = (x + 0x7000) >> 16; x2 = (x2 + 0x7000) >> 16; @@ -3742,9 +3749,15 @@ static void triangle_setup(voodoo_t *voodoo) int va = 0, vb = 1, vc = 2; int reverse_cull = 0; - if (voodoo->verts[0].sVy < voodoo->verts[1].sVy) + 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 (voodoo->verts[1].sVy < voodoo->verts[2].sVy) + if (verts[1].sVy < verts[2].sVy) { /* V1>V0, V2>V1, V2>V1>V0*/ va = 0; /*OK*/ @@ -3754,7 +3767,7 @@ static void triangle_setup(voodoo_t *voodoo) else { /* V1>V0, V1>V2*/ - if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) + if (verts[0].sVy < verts[2].sVy) { /* V1>V0, V1>V2, V2>V0, V1>V2>V0*/ va = 0; @@ -3773,10 +3786,10 @@ static void triangle_setup(voodoo_t *voodoo) } else { - if (voodoo->verts[1].sVy < voodoo->verts[2].sVy) + if (verts[1].sVy < verts[2].sVy) { /* V0>V1, V2>V1*/ - if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) + if (verts[0].sVy < verts[2].sVy) { /* V0>V1, V2>V1, V2>V0, V2>V0>V1*/ va = 1; @@ -3802,10 +3815,10 @@ static void triangle_setup(voodoo_t *voodoo) } } - 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; + 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; @@ -3840,66 +3853,66 @@ static void triangle_setup(voodoo_t *voodoo) 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); + 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) 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); + 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)(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); + 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)(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); + 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)(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.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)(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[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)(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[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; @@ -3909,18 +3922,18 @@ static void triangle_setup(voodoo_t *voodoo) } 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); + 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)(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.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); @@ -4336,7 +4349,7 @@ static void wait_for_swap_complete(voodoo_t *voodoo) { thread_wait_event(voodoo->wake_fifo_thread, -1); thread_reset_event(voodoo->wake_fifo_thread); - if ((voodoo->swap_pending && voodoo->flush) || FIFO_ENTRIES >= 65536) + 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, 1024); @@ -5898,15 +5911,13 @@ static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) #define WAKE_DELAY (TIMER_USEC * 100) static inline void wake_fifo_thread(voodoo_t *voodoo) { - if (!voodoo->wake_timer) + 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_process(); - voodoo->wake_timer = WAKE_DELAY; - timer_update_outstanding(); + timer_set_delay_u64(&voodoo->wake_timer, WAKE_DELAY); } } @@ -5918,8 +5929,6 @@ static inline void wake_fifo_thread_now(voodoo_t *voodoo) 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*/ } @@ -5954,7 +5963,7 @@ static uint16_t voodoo_readw(uint32_t addr, void *p) addr &= 0xffffff; - cycles -= voodoo->read_time; + sub_cycles(voodoo->read_time); if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ { @@ -6011,7 +6020,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) voodoo->rd_count++; addr &= 0xffffff; - cycles -= voodoo->read_time; + sub_cycles(voodoo->read_time); if (addr & 0x800000) /*Texture*/ { @@ -6164,14 +6173,23 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) 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; - break; + { + 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 & ~0x1ff; @@ -6216,9 +6234,9 @@ static void voodoo_writew(uint32_t addr, uint16_t val, void *p) addr &= 0xffffff; if (addr == voodoo->last_write_addr+4) - cycles -= voodoo->burst_time; + sub_cycles(voodoo->burst_time); else - cycles -= voodoo->write_time; + sub_cycles(voodoo->write_time); voodoo->last_write_addr = addr; if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ @@ -6246,7 +6264,7 @@ static void voodoo_pixelclock_update(voodoo_t *voodoo) voodoo->pixel_clock = t; clock_const = cpuclock / t; - voodoo->line_time = (int)((double)line_length * clock_const * (double)(1 << TIMER_SHIFT)); + voodoo->line_time = (uint64_t)((double)line_length * clock_const * (double)(1ULL << 32)); } static void voodoo_writel(uint32_t addr, uint32_t val, void *p) @@ -6258,9 +6276,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) addr &= 0xffffff; if (addr == voodoo->last_write_addr+4) - cycles -= voodoo->burst_time; + sub_cycles(voodoo->burst_time); else - cycles -= voodoo->write_time; + sub_cycles(voodoo->write_time); voodoo->last_write_addr = addr; if (addr & 0x800000) /*Texture*/ @@ -7334,8 +7352,6 @@ static void voodoo_filterline_v2(voodoo_t *voodoo, uint8_t *fil, int column, uin void voodoo_callback(void *p) { voodoo_t *voodoo = (voodoo_t *)p; - int y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; - int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) { @@ -7365,12 +7381,12 @@ void voodoo_callback(void *p) if (draw_voodoo->dirty_line[draw_line]) { - uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line + y_add])[32 + x_add]; + uint32_t *p = &buffer32->line[voodoo->line + 8][8]; 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; @@ -7378,7 +7394,11 @@ void voodoo_callback(void *p) } if (voodoo->line > voodoo->dirty_line_high) voodoo->dirty_line_high = voodoo->line; - + + /* Draw left overscan. */ + for (x = 0; x < 8; x++) + buffer32->line[voodoo->line + 8][x] = 0x00000000; + if (voodoo->scrfilter && voodoo->scrfilterEnabled) { uint8_t fil[(voodoo->h_disp) * 3]; /* interleaved 24-bit RGB */ @@ -7400,6 +7420,10 @@ void voodoo_callback(void *p) p[x] = draw_voodoo->video_16to32[src[x]]; } } + + /* Draw right overscan. */ + for (x = 0; x < 8; x++) + buffer32->line[voodoo->line + 8][voodoo->h_disp + x + 8] = 0x00000000; } } } @@ -7480,9 +7504,9 @@ skip_draw: voodoo->v_retrace = 0; } if (voodoo->line_time) - voodoo->timer_count += voodoo->line_time; + timer_advance_u64(&voodoo->timer, voodoo->line_time); else - voodoo->timer_count += TIMER_USEC * 32; + timer_advance_u64(&voodoo->timer, TIMER_USEC * 32); } static void voodoo_speed_changed(void *p) @@ -7563,7 +7587,7 @@ void *voodoo_card_init() } } - 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; @@ -7580,7 +7604,7 @@ void *voodoo_card_init() 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); + timer_add(&voodoo->wake_timer, voodoo_wake_timer, (void *)voodoo, 0); for (c = 0; c < 0x100; c++) { diff --git a/src/video/vid_wy700.c b/src/video/vid_wy700.c index 814da2cca..b490dc4a6 100644 --- a/src/video/vid_wy700.c +++ b/src/video/vid_wy700.c @@ -8,7 +8,7 @@ * * Wyse-700 emulation. * - * Version: @(#)vid_wy700.c 1.0.9 2018/05/20 + * Version: @(#)vid_wy700.c 1.0.10 2018/09/19 * * Authors: Sarah Walker, * Miran Grca, @@ -23,9 +23,9 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_wy700.h" @@ -212,13 +212,13 @@ typedef struct wy700_t int enabled; /* Display enabled, 0 or 1 */ int detach; /* Detach cursor, 0 or 1 */ - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int linepos, displine; int vc; int dispon, blink; - int64_t vsynctime; + int vsynctime; uint8_t *vram; } wy700_t; @@ -233,6 +233,8 @@ void wy700_write(uint32_t addr, uint8_t val, void *p); uint8_t wy700_read(uint32_t addr, void *p); void wy700_checkchanges(wy700_t *wy700); +static video_timings_t timing_wy700 = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + void wy700_out(uint16_t addr, uint8_t val, void *p) { @@ -512,8 +514,8 @@ void wy700_recalctimings(wy700_t *wy700) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - wy700->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - wy700->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + wy700->dispontime = (uint64_t)(_dispontime); + wy700->dispofftime = (uint64_t)(_dispofftime); } @@ -576,7 +578,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] = + buffer32->line[wy700->displine][(x * cw) + c] = mdacols[attr][blink][1]; } else /* Draw 16 pixels of character */ @@ -593,16 +595,16 @@ void wy700_textline(wy700_t *wy700) 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; + buffer32->line[wy700->displine][(x * cw) + 2*c] = col; + buffer32->line[wy700->displine][(x * cw) + 2*c + 1] = col; } - else buffer->line[wy700->displine][(x * cw) + c] = col; + else 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]; + buffer32->line[wy700->displine][(x * cw) + c] ^= (mda ? mdacols : cgacols)[attr][0][1]; } ++ma; } @@ -640,8 +642,8 @@ void wy700_cgaline(wy700_t *wy700) ink = (dat & 0x80000000) ? 16 + 15: 16 + 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] = + buffer32->line[wy700->displine][x*64 + 2*c] = + buffer32->line[wy700->displine][x*64 + 2*c+1] = ink; dat = dat << 1; } @@ -659,10 +661,10 @@ void wy700_cgaline(wy700_t *wy700) } 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] = + buffer32->line[wy700->displine][x*64 + 4*c] = + buffer32->line[wy700->displine][x*64 + 4*c+1] = + buffer32->line[wy700->displine][x*64 + 4*c+2] = + buffer32->line[wy700->displine][x*64 + 4*c+3] = ink; dat = dat << 2; } @@ -701,10 +703,10 @@ void wy700_medresline(wy700_t *wy700) } /* 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] = + buffer32->line[wy700->displine][x*64 + 4*c] = + buffer32->line[wy700->displine][x*64 + 4*c+1] = + buffer32->line[wy700->displine][x*64 + 4*c+2] = + buffer32->line[wy700->displine][x*64 + 4*c+3] = ink; dat = dat << 2; } @@ -716,8 +718,8 @@ void wy700_medresline(wy700_t *wy700) ink = (dat & 0x80000000) ? 16 + 15: 16 + 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] = + buffer32->line[wy700->displine][x*64 + 2*c] = + buffer32->line[wy700->displine][x*64 + 2*c+1] = ink; dat = dat << 1; } @@ -763,8 +765,8 @@ void wy700_hiresline(wy700_t *wy700) } /* 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] = + buffer32->line[wy700->displine][x*32 + 2*c] = + buffer32->line[wy700->displine][x*32 + 2*c+1] = ink; dat = dat << 2; } @@ -776,7 +778,7 @@ void wy700_hiresline(wy700_t *wy700) ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; /* Display disabled? */ if (!(wy700->wy700_mode & 8)) ink = 16; - buffer->line[wy700->displine][x*32 + c] = ink; + buffer32->line[wy700->displine][x*32 + c] = ink; dat = dat << 1; } } @@ -793,7 +795,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; @@ -854,7 +856,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) @@ -902,13 +904,14 @@ void *wy700_init(const device_t *info) int c; wy700_t *wy700 = malloc(sizeof(wy700_t)); memset(wy700, 0, sizeof(wy700_t)); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_wy700); /* 128k video RAM */ wy700->vram = malloc(0x20000); loadfont(L"roms/video/wyse700/wy700.rom", 3); - 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) */ diff --git a/src/video/video.c b/src/video/video.c index ae7085e96..7d87c5382 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -40,23 +40,26 @@ * W = 3 bus clocks * L = 4 bus clocks * - * Version: @(#)video.c 1.0.23 2018/05/25 + * Version: @(#)video.c 1.0.35 2019/12/06 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ +#define PNG_DEBUG 0 +#include +#include #include #include #include #include #include #include +#define HAVE_STDARG_H #include "../86box.h" #include "../cpu/cpu.h" -#include "../machine/machine.h" #include "../io.h" #include "../mem.h" #include "../rom.h" @@ -67,31 +70,29 @@ #include "vid_svga.h" -enum { - VIDEO_ISA = 0, - VIDEO_BUS -}; - -bitmap_t *screen = NULL, - *buffer = NULL, - *buffer32 = NULL; +volatile int screenshots = 0; +bitmap_t *buffer32 = NULL; +bitmap_t *render_buffer = NULL; uint8_t fontdat[2048][8]; /* IBM CGA font */ uint8_t fontdatm[2048][16]; /* IBM MDA font */ uint8_t fontdatw[512][32]; /* Wyse700 font */ uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ -dbcs_font_t *fontdatksc5601; /* Korean KSC-5601 font */ -dbcs_font_t *fontdatksc5601_user; /* Korean KSC-5601 user defined font */ +uint8_t fontdat12x18[256][36]; /* IM1024 font */ +dbcs_font_t *fontdatksc5601 = NULL; /* Korean KSC-5601 font */ +dbcs_font_t *fontdatksc5601_user = NULL; /* Korean KSC-5601 user defined font */ uint32_t pal_lookup[256]; int xsize = 1, ysize = 1; -int cga_palette = 0; +int cga_palette = 0, + herc_blend = 0; uint32_t *video_6to8 = NULL, + *video_8togs = NULL, + *video_8to32 = NULL, *video_15to32 = NULL, *video_16to32 = NULL; int egareads = 0, egawrites = 0, changeframecount = 2; -uint8_t rotatevga[8][256]; int frames = 0; int fullchange = 0; uint8_t edatlookup[4][4]; @@ -110,6 +111,9 @@ static int video_force_resize; int invert_display = 0; int video_grayscale = 0; int video_graytype = 0; +static int vid_type; +static const video_timings_t *vid_timings; +static uint32_t cga_2_table[16]; PALETTE cgapal = { @@ -255,6 +259,26 @@ static struct { static void (*blit_func)(int x, int y, int y1, int y2, int w, int h); +#ifdef ENABLE_VIDEO_LOG +int sdl_do_log = ENABLE_VIDEO_LOG; + + +static void +video_log(const char *fmt, ...) +{ + va_list ap; + + if (video_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define video_log(fmt, ...) +#endif + + static void blit_thread(void *param) { @@ -307,10 +331,144 @@ video_wait_for_buffer(void) } +static png_structp png_ptr; +static png_infop info_ptr; + + +static void +video_take_screenshot(const wchar_t *fn, int startx, int starty, int w, int h) +{ + int i, x, y; + png_bytep *b_rgb = NULL; + FILE *fp = NULL; + uint32_t temp = 0x00000000; + + /* create file */ + fp = plat_fopen((wchar_t *) fn, (wchar_t *) L"wb"); + if (!fp) { + video_log("[video_take_screenshot] File %ls could not be opened for writing", fn); + return; + } + + /* initialize stuff */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!png_ptr) { + video_log("[video_take_screenshot] png_create_write_struct failed"); + fclose(fp); + return; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + video_log("[video_take_screenshot] png_create_info_struct failed"); + fclose(fp); + return; + } + + png_init_io(png_ptr, fp); + + png_set_IHDR(png_ptr, info_ptr, w, h, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * h); + if (b_rgb == NULL) { + video_log("[video_take_screenshot] Unable to Allocate RGB Bitmap Memory"); + fclose(fp); + return; + } + + for (y = 0; y < h; ++y) { + b_rgb[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); + for (x = 0; x < w; ++x) { + temp = render_buffer->line[y + starty][x + startx]; + + b_rgb[y][(x) * 3 + 0] = (temp >> 16) & 0xff; + b_rgb[y][(x) * 3 + 1] = (temp >> 8) & 0xff; + b_rgb[y][(x) * 3 + 2] = temp & 0xff; + } + } + + png_write_info(png_ptr, info_ptr); + + png_write_image(png_ptr, b_rgb); + + png_write_end(png_ptr, NULL); + + /* cleanup heap allocation */ + for (i = 0; i < h; i++) + if (b_rgb[i]) free(b_rgb[i]); + + if (b_rgb) free(b_rgb); + + if (fp) fclose(fp); +} + + +static void +video_screenshot(int x, int y, int w, int h) +{ + wchar_t path[1024], fn[128]; + + memset(fn, 0, sizeof(fn)); + memset(path, 0, sizeof(path)); + + plat_append_filename(path, usr_path, SCREENSHOT_PATH); + + if (! plat_dir_check(path)) + plat_dir_create(path); + + wcscat(path, L"\\"); + + plat_tempfile(fn, NULL, L".png"); + wcscat(path, fn); + + video_log("taking screenshot to: %S\n", path); + + video_take_screenshot((const wchar_t *) path, x, y, w, h); + png_destroy_write_struct(&png_ptr, &info_ptr); +} + + +static void +video_transform_copy(uint32_t *dst, uint32_t *src, int len) +{ + int i; + + for (i = 0; i < len; i++) { + *dst = video_color_transform(*src); + dst++; + src++; + } +} + + void video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) { - if (h <= 0) return; + int yy; + + if ((w > 0) && (h > 0)) { + for (yy = 0; yy < h; yy++) { + if (((y + yy) >= 0) && ((y + yy) < buffer32->h)) { + if (video_grayscale || invert_display) + video_transform_copy(&(render_buffer->line[y + yy][x]), &(buffer32->line[y + yy][x]), w); + else + memcpy(&(render_buffer->line[y + yy][x]), &(buffer32->line[y + yy][x]), w << 2); + } + } + } + + if (screenshots) { + if (render_buffer != NULL) + video_screenshot(x, y, w, h); + screenshots--; + video_log("screenshot taken, %i left\n", screenshots); + } + + if ((w <= 0) || (h <= 0)) + return; video_wait_for_blit(); @@ -327,19 +485,75 @@ video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) } +uint8_t pixels8(uint32_t *pixels) +{ + int i; + uint8_t temp = 0; + + for (i = 0; i < 8; i++) + temp |= (!!*(pixels + i) << (i ^ 7)); + + return temp; +} + + +uint32_t pixel_to_color(uint8_t *pixels32, uint8_t pos) +{ + uint32_t temp; + temp = *(pixels32 + pos) & 0x03; + switch (temp) { + case 0: + default: + return 0x00; + case 1: + return 0x07; + case 2: + return 0x0f; + } +} + + +void +video_blend(int x, int y) +{ + int xx; + uint32_t pixels32_1, pixels32_2; + unsigned int val1, val2; + static unsigned int carry = 0; + + if (!herc_blend) + return; + + if (!x) + carry = 0; + + val1 = pixels8(&(buffer32->line[y][x])); + val2 = (val1 >> 1) + carry; + carry = (val1 & 1) << 7; + pixels32_1 = cga_2_table[val1 >> 4] + cga_2_table[val2 >> 4]; + pixels32_2 = cga_2_table[val1 & 0xf] + cga_2_table[val2 & 0xf]; + for (xx = 0; xx < 4; xx++) { + buffer32->line[y][x + xx] = pixel_to_color((uint8_t *) &pixels32_1, xx); + buffer32->line[y][x + (xx | 4)] = pixel_to_color((uint8_t *) &pixels32_2, xx); + } +} + + void video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h) { int yy, xx; - if (h <= 0) return; - - for (yy = 0; yy < h; yy++) - { - if ((y + yy) >= 0 && (y + yy) < buffer->h) - { - for (xx = 0; xx < w; xx++) - *(uint32_t *) &(buffer32->line[y + yy][(x + xx) << 2]) = pal_lookup[buffer->line[y + yy][x + xx]]; + if ((w > 0) && (h > 0)) { + for (yy = 0; yy < h; yy++) { + if ((y + yy) >= 0 && (y + yy) < buffer32->h) { + for (xx = 0; xx < w; xx++) { + if (buffer32->line[y + yy][x + xx] <= 0xff) + buffer32->line[y + yy][x + xx] = pal_lookup[buffer32->line[y + yy][x + xx]]; + else + buffer32->line[y + yy][x + xx] = 0x00000000; + } + } } } @@ -363,7 +577,7 @@ cgapal_rebuild(void) if ((cga_palette > 1) && (cga_palette < 8)) { if (vid_cga_contrast != 0) { - for (c=0; c<16; c++) { + for (c = 0; c < 16; c++) { pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], video_6to8[cgapal_mono[cga_palette - 2][c].g], video_6to8[cgapal_mono[cga_palette - 2][c].b]); @@ -378,7 +592,7 @@ cgapal_rebuild(void) video_6to8[cgapal_mono[cga_palette - 2][c].b]); } } else { - for (c=0; c<16; c++) { + for (c = 0; c < 16; c++) { pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], video_6to8[cgapal_mono[cga_palette - 1][c].g], video_6to8[cgapal_mono[cga_palette - 1][c].b]); @@ -400,95 +614,41 @@ cgapal_rebuild(void) } -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_t1000 = {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_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_endeavor = {VIDEO_BUS, 3, 2, 4,25,25,40}; +void +video_inform(int type, const video_timings_t *ptr) +{ + vid_type = type; + vid_timings = ptr; +} + + +int +video_get_type(void) +{ + return vid_type; +} + void video_update_timing(void) { - video_timings_t *timing; - int new_gfxcard; + if (!vid_timings) + return; - new_gfxcard = 0; - - 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: - timing = &timing_pc1640; - break; - case ROM_PC200: - timing = &timing_pc200; - break; - case ROM_OLIM24: - timing = &timing_m24; - break; - case ROM_PC2086: - case ROM_PC3086: - timing = &timing_pvga1a; - break; - case ROM_T1000: - case ROM_T1200: - timing = &timing_t1000; - break; - case ROM_MEGAPC: - case ROM_MEGAPCDX: - timing = &timing_wd90c11; - break; - case ROM_IBMPS1_2011: - case ROM_IBMPS2_M30_286: - case ROM_IBMPS2_M50: - case ROM_IBMPS2_M55SX: - case ROM_IBMPS2_M80: - timing = &timing_vga; - break; - case ROM_IBMPS1_2121: - case ROM_IBMPS1_2133: - timing = &timing_ps1_svga; - break; - case ROM_T3100E: - timing = &timing_t3100e; - break; - case ROM_ENDEAVOR: - timing = &timing_endeavor; - break; - default: - new_gfxcard = video_old_to_new(gfxcard); - timing = video_card_gettiming(new_gfxcard); - 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); + if (vid_timings->type == VIDEO_ISA) { + video_timing_read_b = ISA_CYCLES(vid_timings->read_b); + video_timing_read_w = ISA_CYCLES(vid_timings->read_w); + video_timing_read_l = ISA_CYCLES(vid_timings->read_l); + video_timing_write_b = ISA_CYCLES(vid_timings->write_b); + video_timing_write_w = ISA_CYCLES(vid_timings->write_w); + video_timing_write_l = ISA_CYCLES(vid_timings->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); + video_timing_read_b = (int)(bus_timing * vid_timings->read_b); + video_timing_read_w = (int)(bus_timing * vid_timings->read_w); + video_timing_read_l = (int)(bus_timing * vid_timings->read_l); + video_timing_write_b = (int)(bus_timing * vid_timings->write_b); + video_timing_write_w = (int)(bus_timing * vid_timings->write_w); + video_timing_write_l = (int)(bus_timing * vid_timings->write_l); } if (cpu_16bitbus) { @@ -516,6 +676,26 @@ calc_6to8(int c) } +int +calc_8to32(int c) +{ + int b, g, r; + double db, dg, dr; + + b = (c & 3); + g = ((c >> 2) & 7); + r = ((c >> 5) & 7); + db = (((double) b) / 3.0) * 255.0; + dg = (((double) g) / 7.0) * 255.0; + dr = (((double) r) / 7.0) * 255.0; + b = (int) db; + g = ((int) dg) << 8; + r = ((int) dr) << 16; + + return(b | g | r); +} + + int calc_15to32(int c) { @@ -559,13 +739,13 @@ calc_16to32(int c) void hline(bitmap_t *b, int x1, int y, int x2, uint32_t col) { - if (y < 0 || y >= buffer->h) + int x; + + if (y < 0 || y >= buffer32->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); + for (x = x1; x < x2; x++) + b->line[y][x] = col; } @@ -605,12 +785,12 @@ destroy_bitmap(bitmap_t *b) bitmap_t * create_bitmap(int x, int y) { - bitmap_t *b = malloc(sizeof(bitmap_t) + (y * sizeof(uint8_t *))); + bitmap_t *b = malloc(sizeof(bitmap_t) + (y * sizeof(uint32_t *))); int c; b->dat = malloc(x * y * 4); for (c = 0; c < y; c++) - b->line[c] = b->dat + (c * x * 4); + b->line[c] = &(b->dat[c * x]); b->w = x; b->h = y; @@ -621,12 +801,18 @@ create_bitmap(int x, int y) void video_init(void) { - int c, d, e; + int c, d; + uint8_t total[2] = { 0, 1 }; + + for (c = 0; c < 16; c++) { + cga_2_table[c] = (total[(c >> 3) & 1] << 0 ) | (total[(c >> 2) & 1] << 8 ) | + (total[(c >> 1) & 1] << 16) | (total[(c >> 0) & 1] << 24); + } /* Account for overscan. */ - buffer32 = create_bitmap(2048, 2048); + buffer32 = create_bitmap(2048 + 64, 2048 + 64); + render_buffer = create_bitmap(2048 + 64, 2048 + 64); - 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; @@ -640,13 +826,6 @@ video_init(void) cgapal[c + 128].b = (((c & 1) ? 2 : 0) | ((c & 0x08) ? 1 : 0)) * 21; } - for (c = 0; c < 256; c++) { - e = c; - for (d = 0; d < 8; d++) { - rotatevga[d][c] = e; - e = (e >> 1) | ((e & 1) ? 0x80 : 0); - } - } for (c = 0; c < 4; c++) { for (d = 0; d < 4; d++) { edatlookup[c][d] = 0; @@ -660,19 +839,20 @@ video_init(void) video_6to8 = malloc(4 * 256); for (c = 0; c < 256; c++) video_6to8[c] = calc_6to8(c); + + video_8togs = malloc(4 * 256); + for (c = 0; c < 256; c++) + video_8togs[c] = c | (c << 16) | (c << 24); + + video_8to32 = malloc(4 * 256); + for (c = 0; c < 256; c++) + video_8to32[c] = calc_8to32(c); + video_15to32 = malloc(4 * 65536); -#if 0 for (c = 0; c < 65536; c++) - video_15to32[c] = ((c & 31) << 3) | (((c >> 5) & 31) << 11) | (((c >> 10) & 31) << 19); -#endif - for (c = 0; c < 65536; c++) - video_15to32[c] = calc_15to32(c); + video_15to32[c] = calc_15to32(c & 0x7fff); video_16to32 = malloc(4 * 65536); -#if 0 - for (c = 0; c < 65536; c++) - video_16to32[c] = ((c & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 11) & 31) << 19); -#endif for (c = 0; c < 65536; c++) video_16to32[c] = calc_16to32(c); @@ -691,11 +871,13 @@ video_close(void) thread_destroy_event(blit_data.blit_complete); thread_destroy_event(blit_data.wake_blit_thread); - free(video_6to8); - free(video_15to32); free(video_16to32); + free(video_15to32); + free(video_8to32); + free(video_8togs); + free(video_6to8); - destroy_bitmap(buffer); + destroy_bitmap(render_buffer); destroy_bitmap(buffer32); if (fontdatksc5601) { @@ -749,17 +931,14 @@ loadfont(wchar_t *s, int format) break; case 1: /* PC200 */ - for (c=0; c<256; c++) - for (d=0; d<8; d++) - fontdatm[c][d] = fgetc(f); - for (c=0; c<256; c++) - for (d=0; d<8; d++) - fontdatm[c][d+8] = fgetc(f); - (void)fseek(f, 4096, SEEK_SET); - for (c=0; c<256; c++) { - for (d=0; d<8; d++) - fontdat[c][d] = fgetc(f); - for (d=0; d<8; d++) (void)fgetc(f); + 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][0], 1, 16, f); + for (c = 0; c < 256; c++) { /* 8x8 CGA in 8x16 cell */ + fread(&fontdat[256*d + c][0], 1, 8, f); + fseek(f, 8, SEEK_CUR); + } } break; @@ -826,6 +1005,28 @@ loadfont(wchar_t *s, int format) fontdatksc5601[c].chr[d]=getc(f); } break; + + case 7: /* 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 8: /* Amstrad PC1512, Toshiba T1000/T1200 */ + for (c = 0; c < 2048; c++) /* Allow up to 2048 chars */ + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + break; + + case 9: /* Image Manager 1024 native font */ + for (c = 0; c < 256; c++) + fread(&fontdat12x18[c][0], 1, 36, f); + break; } (void)fclose(f); @@ -861,15 +1062,3 @@ video_color_transform(uint32_t color) color ^= 0x00ffffff; return color; } - -void -video_transform_copy(uint32_t *dst, uint32_t *src, int len) -{ - int i; - - for (i = 0; i < len; i++) { - *dst = video_color_transform(*src); - dst++; - src++; - } -} diff --git a/src/video/video.h b/src/video/video.h index 265efc95f..427b0e5c9 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -8,15 +8,15 @@ * * Definitions for the video controller module. * - * Version: @(#)video.h 1.0.30 2018/07/19 + * Version: @(#)video.h 1.0.37 2019/12/06 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_VIDEO_H # define EMU_VIDEO_H @@ -27,110 +27,15 @@ enum { - GFX_NONE = 0, - GFX_INTERNAL, - GFX_CGA, - GFX_COMPAQ_CGA, /* Compaq CGA */ - GFX_COMPAQ_CGA_2, /* Compaq CGA 2 */ - GFX_COLORPLUS, /* Plantronics ColorPlus */ - GFX_WY700, /* Wyse 700 */ - GFX_MDA, - GFX_GENIUS, /* MDSI Genius */ - GFX_HERCULES, - GFX_HERCULESPLUS, - GFX_INCOLOR, /* Hercules InColor */ - GFX_EGA, /* Using IBM EGA BIOS */ - GFX_COMPAQ_EGA, /* Compaq EGA */ - GFX_SUPER_EGA, /* Using Chips & Technologies SuperEGA BIOS */ - GFX_VGA, /* IBM VGA */ - GFX_TVGA, /* Using Trident TVGA8900D BIOS */ - GFX_ET4000_ISA, /* Tseng ET4000 */ - GFX_ET4000_MCA, /* Tseng ET4000 */ - GFX_ET4000W32_CARDEX_VLB, /* Tseng ET4000/W32p (Cardex) VLB */ - GFX_ET4000W32_CARDEX_PCI, /* Tseng ET4000/W32p (Cardex) PCI */ -#if defined(DEV_BRANCH) && defined(USE_STEALTH32) - GFX_ET4000W32_VLB, /* Tseng ET4000/W32p (Diamond Stealth 32) VLB */ - GFX_ET4000W32_PCI, /* Tseng ET4000/W32p (Diamond Stealth 32) PCI */ -#endif - GFX_BAHAMAS64_VLB, /* S3 Vision864 (Paradise Bahamas 64) VLB */ - GFX_BAHAMAS64_PCI, /* S3 Vision864 (Paradise Bahamas 64) PCI */ - GFX_N9_9FX_VLB, /* S3 764/Trio64 (Number Nine 9FX) VLB */ - GFX_N9_9FX_PCI, /* S3 764/Trio64 (Number Nine 9FX) PCI */ - GFX_TGUI9400CXI, /* Trident TGUI9400CXi VLB */ - GFX_TGUI9440_VLB, /* Trident TGUI9440AGi VLB */ - GFX_TGUI9440_PCI, /* Trident TGUI9440AGi PCI */ - GFX_ATIKOREANVGA, /*ATI Korean VGA (28800-5)*/ - GFX_VGA88, /* ATI VGA-88 (18800-1) */ - GFX_VGAEDGE16, /* ATI VGA Edge-16 (18800-1) */ - GFX_VGACHARGER, /* ATI VGA Charger (28800-5) */ -#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) - GFX_VGAWONDER, /* Compaq ATI VGA Wonder (18800) */ -#endif - GFX_VGAWONDERXL, /* Compaq ATI VGA Wonder XL (28800-5) */ -#if defined(DEV_BRANCH) && defined(USE_XL24) - GFX_VGAWONDERXL24, /* Compaq ATI VGA Wonder XL24 (28800-6) */ -#endif - GFX_MACH64GX_ISA, /* ATI Graphics Pro Turbo (Mach64) ISA */ - GFX_MACH64GX_VLB, /* ATI Graphics Pro Turbo (Mach64) VLB */ - GFX_MACH64GX_PCI, /* ATI Graphics Pro Turbo (Mach64) PCI */ - GFX_MACH64VT2, /* ATI Mach64 VT2 */ - GFX_CL_GD5424_ISA, /* Cirrus Logic CL-GD 5424 ISA */ - GFX_CL_GD5424_VLB, /* Cirrus Logic CL-GD 5424 VLB */ - GFX_CL_GD5426_VLB, /* Diamond SpeedStar PRO (Cirrus Logic CL-GD 5426) VLB */ - GFX_CL_GD5428_ISA, /* Cirrus Logic CL-GD 5428 ISA */ - GFX_CL_GD5428_VLB, /* Cirrus Logic CL-GD 5428 VLB */ - GFX_CL_GD5429_ISA, /* Cirrus Logic CL-GD 5429 ISA */ - GFX_CL_GD5429_VLB, /* Cirrus Logic CL-GD 5429 VLB */ - GFX_CL_GD5430_VLB, /* Diamond SpeedStar PRO SE (Cirrus Logic CL-GD 5430) VLB */ - GFX_CL_GD5430_PCI, /* Cirrus Logic CL-GD 5430 PCI */ - GFX_CL_GD5434_ISA, /* Cirrus Logic CL-GD 5434 ISA */ - GFX_CL_GD5434_VLB, /* Cirrus Logic CL-GD 5434 VLB */ - GFX_CL_GD5434_PCI, /* Cirrus Logic CL-GD 5434 PCI */ - GFX_CL_GD5436_PCI, /* Cirrus Logic CL-GD 5436 PCI */ - GFX_CL_GD5440_PCI, /* Cirrus Logic CL-GD 5440 PCI */ - GFX_CL_GD5446_PCI, /* Cirrus Logic CL-GD 5446 PCI */ - GFX_CL_GD5446_STB_PCI, /* STB Nitro 64V (Cirrus Logic CL-GD 5446) PCI */ - GFX_CL_GD5480_PCI, /* Cirrus Logic CL-GD 5480 PCI */ -#if defined(DEV_BRANCH) && defined(USE_RIVA) - GFX_RIVATNT, /* nVidia Riva TNT */ - GFX_RIVATNT2, /* nVidia Riva TNT2 */ - GFX_RIVA128, /* nVidia Riva 128 */ -#endif - GFX_OTI037C, /* Oak OTI-037C */ - GFX_OTI067, /* Oak OTI-067 */ - GFX_OTI077, /* Oak OTI-077 */ - GFX_PVGA1A, /* Paradise PVGA1A Standalone */ - GFX_WD90C11, /* Paradise WD90C11-LR Standalone */ - GFX_WD90C30, /* Paradise WD90C30-LR Standalone */ - GFX_PHOENIX_TRIO32_VLB, /* S3 732/Trio32 (Phoenix) VLB */ - GFX_PHOENIX_TRIO32_PCI, /* S3 732/Trio32 (Phoenix) PCI */ - GFX_PHOENIX_TRIO64_VLB, /* S3 764/Trio64 (Phoenix) VLB */ - GFX_PHOENIX_TRIO64_PCI, /* S3 764/Trio64 (Phoenix) PCI */ - GFX_VIRGE_VLB, /* S3 Virge VLB */ - GFX_VIRGE_PCI, /* S3 Virge PCI */ - GFX_VIRGEDX_VLB, /* S3 Virge/DX VLB */ - GFX_VIRGEDX_PCI, /* S3 Virge/DX PCI */ - GFX_VIRGEDX4_VLB, /* S3 Virge/DX (VBE 2.0) VLB */ - GFX_VIRGEDX4_PCI, /* S3 Virge/DX (VBE 2.0) PCI */ - GFX_VIRGEVX_VLB, /* S3 Virge/VX VLB */ - GFX_VIRGEVX_PCI, /* S3 Virge/VX PCI */ - GFX_STEALTH64_VLB, /* S3 Vision864 (Diamond Stealth 64) VLB */ - GFX_STEALTH64_PCI, /* S3 Vision864 (Diamond Stealth 64) PCI */ - GFX_PHOENIX_VISION864_VLB, /* S3 Vision864 (Phoenix) VLB */ - GFX_PHOENIX_VISION864_PCI, /* S3 Vision864 (Phoenix) PCI */ -#if defined(DEV_BRANCH) && defined(USE_TI) - GFX_TICF62011, /* TI CF62011 */ -#endif - - GFX_MAX + VID_NONE = 0, + VID_INTERNAL }; enum { FULLSCR_SCALE_FULL = 0, FULLSCR_SCALE_43, - FULLSCR_SCALE_SQ, - FULLSCR_SCALE_INT, - FULLSCR_SCALE_KEEPRATIO + FULLSCR_SCALE_KEEPRATIO, + FULLSCR_SCALE_INT }; @@ -139,6 +44,18 @@ extern "C" { #endif +enum { + VIDEO_ISA = 0, + VIDEO_MCA, + VIDEO_BUS +}; + +#define VIDEO_FLAG_TYPE_CGA 0 +#define VIDEO_FLAG_TYPE_MDA 1 +#define VIDEO_FLAG_TYPE_SPECIAL 2 +#define VIDEO_FLAG_TYPE_NONE 3 +#define VIDEO_FLAG_TYPE_MASK 3 + typedef struct { int type; int write_b, write_w, write_l; @@ -147,8 +64,8 @@ typedef struct { typedef struct { int w, h; - uint8_t *dat; - uint8_t *line[2048]; + uint32_t *dat; + uint32_t *line[2048]; } bitmap_t; typedef struct { @@ -162,14 +79,12 @@ typedef struct { typedef rgb_t PALETTE[256]; -extern int gfx_present[GFX_MAX]; extern int egareads, egawrites; extern int changeframecount; -extern bitmap_t *screen, - *buffer, - *buffer32; +extern volatile int screenshots; +extern bitmap_t *buffer32, *render_buffer; extern PALETTE cgapal, cgapal_mono[6]; extern uint32_t pal_lookup[256]; @@ -179,9 +94,14 @@ extern int video_fullscreen, extern int fullchange; extern uint8_t fontdat[2048][8]; extern uint8_t fontdatm[2048][16]; +extern uint8_t fontdatw[512][32]; +extern uint8_t fontdat8x12[256][16]; +extern uint8_t fontdat12x18[256][36]; extern dbcs_font_t *fontdatksc5601; extern dbcs_font_t *fontdatksc5601_user; extern uint32_t *video_6to8, + *video_8togs, + *video_8to32, *video_15to32, *video_16to32; extern int xsize,ysize; @@ -199,12 +119,13 @@ extern int video_res_x, video_res_y, video_bpp; extern int vid_resize; -extern int cga_palette; +extern int cga_palette, + herc_blend; extern int vid_cga_contrast; extern int video_grayscale; extern int video_graytype; -extern float cpuclock; +extern double cpuclock; extern int emu_fps, frames; extern int readflash; @@ -221,20 +142,20 @@ extern char *video_card_getname(int card); extern const device_t *video_card_getdevice(int card); #endif extern int video_card_has_config(int card); -extern video_timings_t *video_card_gettiming(int card); extern int video_card_getid(char *s); -extern int video_old_to_new(int card); -extern int video_new_to_old(int card); extern char *video_get_internal_name(int card); extern int video_get_video_from_internal_name(char *s); extern int video_is_mda(void); extern int video_is_cga(void); extern int video_is_ega_vga(void); +extern void video_inform(int type, const video_timings_t *ptr); +extern int video_get_type(void); extern void video_setblit(void(*blit)(int,int,int,int,int,int)); -extern void video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +extern void video_blend(int x, int y); extern void video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h); +extern void video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); extern void video_blit_complete(void); extern void video_wait_for_blit(void); extern void video_wait_for_buffer(void); @@ -247,6 +168,7 @@ extern void updatewindowsize(int x, int y); extern void video_init(void); extern void video_close(void); +extern void video_reset_close(void); extern void video_reset(int card); extern uint8_t video_force_resize_get(void); extern void video_force_resize_set(uint8_t res); @@ -262,7 +184,6 @@ extern void svga_dump_vram(void); #endif extern uint32_t video_color_transform(uint32_t color); -extern void video_transform_copy(uint32_t *dst, uint32_t *src, int len); #ifdef __cplusplus } diff --git a/src/vnc.c b/src/vnc.c index 8ee76bea6..7b6040c4b 100644 --- a/src/vnc.c +++ b/src/vnc.c @@ -8,12 +8,12 @@ * * Implement the VNC remote renderer with LibVNCServer. * - * Version: @(#)vnc.c 1.0.12 2018/05/26 + * Version: @(#)vnc.c 1.0.15 2019/12/06 * * Authors: Fred N. van Kempen, * Based on raw code by RichardG, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -49,22 +49,22 @@ static int ptr_x, ptr_y, ptr_but; #ifdef ENABLE_VNC_LOG int vnc_do_log = ENABLE_VNC_LOG; -#endif static void -vnc_log(const char *format, ...) +vnc_log(const char *fmt, ...) { -#ifdef ENABLE_VNC_LOG va_list ap; if (vnc_do_log) { - va_start(ap, format); - pclog_ex(format, ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define vnc_log(fmt, ...) +#endif static void @@ -169,18 +169,14 @@ vnc_display(rfbClientPtr cl) static void vnc_blit(int x, int y, int y1, int y2, int w, int h) { - uint32_t *p, *q; + uint32_t *p; int yy; for (yy=y1; yyframeBuffer)[yy*VNC_MAX_X]); - if ((y+yy) >= 0 && (y+yy) < VNC_MAX_Y) { - if (video_grayscale || invert_display) - video_transform_copy(p, &(((uint32_t *)buffer32->line[y+yy])[x]), w); - else - memcpy(p, &(((uint32_t *)buffer32->line[y+yy])[x]), w*4); - } + if ((y+yy) >= 0 && (y+yy) < VNC_MAX_Y) + memcpy(p, &(render_buffer->line[y+yy][x]), w*4); } video_blit_complete(); diff --git a/src/vnc_keymap.c b/src/vnc_keymap.c index 20a9126aa..d8b453066 100644 --- a/src/vnc_keymap.c +++ b/src/vnc_keymap.c @@ -22,12 +22,12 @@ * NOTE: The values are as defined in the Microsoft document named * "Keyboard Scan Code Specification", version 1.3a of 2000/03/16. * - * Version: @(#)vnc_keymap.c 1.0.3 2018/04/29 + * Version: @(#)vnc_keymap.c 1.0.4 2019/03/24 * * Authors: Fred N. van Kempen, * Based on raw code by RichardG, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -668,5 +668,30 @@ vnc_kbinput(int down, int k) } /* Send this scancode sequence to the PC keyboard. */ - keyboard_input(down, scan); + switch (scan >> 8) { + case 0x00: + default: + if (scan & 0xff) + keyboard_input(down, scan & 0xff); + break; + case 0x2a: + if (scan & 0xff) { + if (down) { + keyboard_input(down, 0x2a); + keyboard_input(down, scan & 0xff); + } else { + keyboard_input(down, scan & 0xff); + keyboard_input(down, 0x2a); + } + } + break; + case 0xe0: + if (scan & 0xff) + keyboard_input(down, (scan & 0xff) | 0x100); + break; + case 0xe1: + if (scan == 0x1d) + keyboard_input(down, 0x100); + break; + } } diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 119257941..851b7d287 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -8,12 +8,14 @@ * * Application resource script for Windows. * - * Version: @(#)86Box.rc 1.0.38 2018/07/19 + * Version: @(#)86Box.rc 1.0.56 2019/12/21 * * Authors: Miran Grca, * Fred N. van Kempen, + * David HrdliÄka, * - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 David HrdliÄka. */ #include #define IN_RESOURCE_H @@ -64,15 +66,17 @@ BEGIN MENUITEM SEPARATOR POPUP "Re&nderer" BEGIN - MENUITEM "&DirectDraw", IDM_VID_DDRAW + MENUITEM "&SDL (Software)", IDM_VID_SDL_SW + MENUITEM "&SDL (Hardware)", IDM_VID_SDL_HW +#ifdef USE_D2D MENUITEM "Direct&2D 1.0", IDM_VID_D2D - MENUITEM "Direct&3D 9", IDM_VID_D3D - MENUITEM "&SDL", IDM_VID_SDL +#endif #ifdef USE_VNC MENUITEM "&VNC", IDM_VID_VNC #endif END MENUITEM SEPARATOR + MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 POPUP "&Window scale factor" BEGIN MENUITEM "&0.5x", IDM_VID_SCALE_1X @@ -84,16 +88,14 @@ BEGIN MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN POPUP "Fullscreen &stretch mode" BEGIN - MENUITEM "&Full screen stretch", IDM_VID_FS_FULL - MENUITEM "&4:3", IDM_VID_FS_43 - MENUITEM "&Square pixels", IDM_VID_FS_SQ - MENUITEM "&Integer scale", IDM_VID_FS_INT - MENUITEM "&Keep size", IDM_VID_FS_KEEPRATIO + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels (Keep ratio)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Integer scale", IDM_VID_FS_INT END POPUP "E&GA/(S)VGA settings" BEGIN MENUITEM "&Inverted VGA monitor", IDM_VID_INVERT - MENUITEM "E&GA/(S)VGA overscan", IDM_VID_OVERSCAN POPUP "VGA screen &type" BEGIN MENUITEM "RGB &Color", IDM_VID_GRAY_RGB @@ -110,13 +112,17 @@ BEGIN END END MENUITEM SEPARATOR - MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 + MENUITEM "CGA/PCjr/Tandy/E&GA/(S)VGA overscan", IDM_VID_OVERSCAN MENUITEM "Change contrast for &monochrome display", IDM_VID_CGACON END POPUP "&Tools" BEGIN MENUITEM "&Settings...", IDM_CONFIG MENUITEM "&Update status bar icons", IDM_UPDATE_ICONS +# ifdef USE_DISCORD + MENUITEM SEPARATOR + MENUITEM "Enable &Discord integration", IDM_DISCORD +# endif MENUITEM SEPARATOR MENUITEM "Take s&creenshot\tCtrl+F11", IDM_ACTION_SCREENSHOT END @@ -206,7 +212,7 @@ BEGIN VK_PRIOR,IDM_VID_FULLSCREEN, VIRTKEY, CONTROL , ALT VK_F11, IDM_ACTION_SCREENSHOT, VIRTKEY, CONTROL VK_F12, IDM_ACTION_RESET_CAD, VIRTKEY, CONTROL - VK_PAUSE,IDM_ACTION_PAUSE + VK_PAUSE,IDM_ACTION_PAUSE, VIRTKEY END @@ -221,8 +227,13 @@ FONT 9, "Segoe UI" BEGIN DEFPUSHBUTTON "OK",IDOK,129,94,71,12 ICON 100,IDC_ABOUT_ICON,7,7,20,20 - LTEXT "86Box v2.00 - A fork of PCem\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information.", +#ifdef RELEASE_BUILD + LTEXT "86Box v2.07 - An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information.", IDC_ABOUT_ICON,54,7,146,73 +#else + LTEXT "86Box v2.10 - An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information.", + IDC_ABOUT_ICON,54,7,146,73 +#endif CONTROL "",IDC_ABOUT_ICON,"Static",SS_BLACKFRAME | SS_SUNKEN,0, 86,208,1 END @@ -287,11 +298,7 @@ BEGIN #endif END -#ifdef USE_DYNAREC -DLG_CFG_MACHINE DIALOG DISCARDABLE 97, 0, 267, 114 -#else -DLG_CFG_MACHINE DIALOG DISCARDABLE 97, 0, 267, 99 -#endif +DLG_CFG_MACHINE DIALOG DISCARDABLE 97, 0, 267, 199 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -314,13 +321,18 @@ BEGIN 12,12 LTEXT "MB",IDT_1705,123,64,10,10 LTEXT "Memory:",IDT_1706,7,64,30,10 - CONTROL "Enable time sync",IDC_CHECK_SYNC,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,81,102,10 CONTROL "Enable FPU",IDC_CHECK_FPU,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,147,81,113,10 + WS_TABSTOP,7,81,113,10 + GROUPBOX "Time synchronization",IDC_TIME_SYNC,7,96,100,56 + CONTROL "Disabled",IDC_RADIO_TS_DISABLED,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,108,84,10 + CONTROL "Enabled (local time)", IDC_RADIO_TS_LOCAL,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,14,122,84,10 + CONTROL "Enabled (UTC)", IDC_RADIO_TS_UTC,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,14,136,84,10 #ifdef USE_DYNAREC CONTROL "Dynamic Recompiler",IDC_CHECK_DYNAREC,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,96,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,147,81,94,10 #endif END @@ -328,13 +340,13 @@ DLG_CFG_VIDEO DIALOG DISCARDABLE 97, 0, 267, 45 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "Video:",IDT_1707,7,8,55,10 - COMBOBOX IDC_COMBO_VIDEO,71,7,140,120,CBS_DROPDOWNLIST | + LTEXT "Video:",IDT_1707,7,8,48,10 + COMBOBOX IDC_COMBO_VIDEO,64,7,155,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_VID,214,7,46,12 + PUSHBUTTON "Configure",IDC_CONFIGURE_VID,222,7,38,12 CONTROL "Voodoo Graphics",IDC_CHECK_VOODOO,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,27,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_VOODOO,214,26,46,12 + PUSHBUTTON "Configure",IDC_BUTTON_VOODOO,222,26,38,12 END DLG_CFG_INPUT DIALOG DISCARDABLE 97, 0, 267, 65 @@ -354,7 +366,7 @@ BEGIN PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 END -DLG_CFG_SOUND DIALOG DISCARDABLE 97, 0, 267, 116 +DLG_CFG_SOUND DIALOG DISCARDABLE 97, 0, 267, 199 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -368,55 +380,59 @@ BEGIN LTEXT "MIDI Out Device:",IDT_1712,7,26,59,10 PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI,214,25,46,12 + COMBOBOX IDC_COMBO_MIDI_IN,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "MIDI In Device:",IDT_1713,7,44,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI_IN,214,43,46,12 + CONTROL "Standalone MPU-401",IDC_CHECK_MPU401,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,45,199,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,44,46,12 + BS_AUTOCHECKBOX | WS_TABSTOP,7,65,199,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,64,46,12 CONTROL "Innovation SSI-2001",IDC_CHECK_SSI,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,63,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,83,94,10 CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,63,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,147,83,94,10 CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,81,94,10 - CONTROL "Use Nuked OPL",IDC_CHECK_NUKEDOPL,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,81,94,10 - - CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_GUS,214,99,46,12 + + CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,115,94,10 END DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "Network type:",IDT_1713,7,8,59,10 + LTEXT "Network type:",IDT_1714,7,8,59,10 COMBOBOX IDC_COMBO_NET_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "PCap device:",IDT_1714,7,26,59,10 + LTEXT "PCap device:",IDT_1715,7,26,59,10 COMBOBOX IDC_COMBO_PCAP,71,25,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Network adapter:",IDT_1715,7,44,59,10 + LTEXT "Network adapter:",IDT_1716,7,44,59,10 COMBOBOX IDC_COMBO_NET,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,43,46,12 END -DLG_CFG_PORTS DIALOG DISCARDABLE 97, 0, 267, 99 +DLG_CFG_PORTS DIALOG DISCARDABLE 97, 0, 267, 117 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "LPT1 Device:",IDT_1716,7,8,61,10 + LTEXT "LPT1 Device:",IDT_1717,7,8,61,10 COMBOBOX IDC_COMBO_LPT1,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LPT2 Device:",IDT_1717,7,27,61,10 + LTEXT "LPT2 Device:",IDT_1718,7,27,61,10 COMBOBOX IDC_COMBO_LPT2,71,26,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LPT3 Device:",IDT_1718,7,46,61,10 + LTEXT "LPT3 Device:",IDT_1719,7,46,61,10 COMBOBOX IDC_COMBO_LPT3,71,45,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP @@ -425,34 +441,61 @@ BEGIN CONTROL "Serial port 2",IDC_CHECK_SERIAL2,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,147,64,94,10 - CONTROL "Parallel port",IDC_CHECK_PARALLEL,"Button", + CONTROL "Parallel port 1",IDC_CHECK_PARALLEL1,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,82,94,10 + CONTROL "Parallel port 2",IDC_CHECK_PARALLEL2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,82,94,10 + CONTROL "Parallel port 3",IDC_CHECK_PARALLEL3,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,100,94,10 END -DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 97, 0, 267, 97 +DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 97, 0, 267, 200 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "SCSI Controller:",IDT_1716,7,8,59,10 - COMBOBOX IDC_COMBO_SCSI,71,7,140,120,CBS_DROPDOWNLIST | + LTEXT "SCSI Controller:",IDT_1717,7,8,48,10 + COMBOBOX IDC_COMBO_SCSI,64,7,155,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI,214,7,46,12 + PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI,222,7,38,12 - LTEXT "HD Controller:",IDT_1717,7,26,61,10 - COMBOBOX IDC_COMBO_HDC,71,25,140,120,CBS_DROPDOWNLIST | + LTEXT "HD Controller:",IDT_1718,7,26,48,10 + COMBOBOX IDC_COMBO_HDC,64,25,155,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,214,25,46,12 + PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,222,25,38,12 CONTROL "Tertiary IDE Controller",IDC_CHECK_IDE_TER,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,44,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_IDE_TER,214,43,46,12 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_TER,222,43,38,12 CONTROL "Quaternary IDE Controller",IDC_CHECK_IDE_QUA,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,62,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_IDE_QUA,214,61,46,12 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_QUA,222,61,38,12 CONTROL "ISABugger device",IDC_CHECK_BUGGER,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,80,94,10 + + LTEXT "ISA RTC",IDT_1767,7,99,48,10 + COMBOBOX IDC_COMBO_ISARTC,64,98,155,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISARTC,222,98,38,12 + + GROUPBOX "ISA Memory Expansion",IDC_GROUP_ISAMEM,7,118,255,70 + LTEXT "#1:",IDT_1763,12,130,21,10 + COMBOBOX IDC_COMBO_ISAMEM_1,25,129,190,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_1,217,129,38,12 + LTEXT "#2:",IDT_1764,12,144,21,10 + COMBOBOX IDC_COMBO_ISAMEM_2,25,143,190,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_2,217,143,38,12 + LTEXT "#3:",IDT_1765,12,158,21,10 + COMBOBOX IDC_COMBO_ISAMEM_3,25,157,190,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_3,217,157,38,12 + LTEXT "#4:",IDT_1766,12,172,21,10 + COMBOBOX IDC_COMBO_ISAMEM_4,25,171,190,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_4,217,171,38,12 END DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 97, 0, 267, 154 @@ -784,7 +827,7 @@ BEGIN 2048 "86Box" IDS_2049 "86Box Error" IDS_2050 "86Box Fatal Error" - IDS_2051 "This will reset 86Box.\nAre you sure you want to save the settings?" + IDS_2051 "This will hard reset the emulated machine.\nAre you sure you want to save the settings?" IDS_2052 "Use CTRL+ALT+PAGE DOWN to return to windowed mode" IDS_2053 "Speed" IDS_2054 "ZIP %03i %i (%s): %ls" @@ -822,7 +865,7 @@ END STRINGTABLE DISCARDABLE BEGIN IDS_2080 "E&xport to 86F..." - IDS_2081 "Unable to initialize FluidSynth, make sure you have the following libraries\nin your 86Box folder:\n\nlibfluidsynth.dll\nlibglib-2.0-0.dll\nlibiconv-2.dll\nlibintl-8.dll\nlibpcre-1.dll" + IDS_2081 "Unable to initialize FluidSynth, libfluidsynth.dll is required" IDS_2082 "Bus" IDS_2083 "File" IDS_2084 "C" @@ -859,7 +902,11 @@ BEGIN IDS_2115 "%u" IDS_2116 "%u MB (CHS: %i, %i, %i)" IDS_2117 "Floppy %i (%s): %ls" - IDS_2118 "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.DDI;*.DSK;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.DDI;*.DSK;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.DDI;*.DSK;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.DDI;*.DSK;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F)\0*.86F\0All files (*.*)\0*.*\0" + IDS_2118 "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.MFM;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.D??;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F;*.MFM)\0*.86F;*.MFM\0All files (*.*)\0*.*\0" + IDS_2119 "Unable to initialize FreeType, freetype.dll is required" + IDS_2120 "Unable to initialize SDL, SDL2.dll is required" + IDS_2121 "Are you sure you want to hard reset the emulated machine?" + IDS_2122 "Are you sure you want to quit 86Box?" END STRINGTABLE DISCARDABLE @@ -900,10 +947,12 @@ BEGIN IDS_5376 "Disabled" IDS_5380 "ATAPI" IDS_5381 "SCSI" + IDS_5382 "SCSI (Chinon)" IDS_5632 "Disabled" IDS_5636 "ATAPI (%01i:%01i)" IDS_5637 "SCSI (ID %02i)" + IDS_5638 "SCSI (ID %02i)" IDS_5888 "160 kB" IDS_5889 "180 kB" @@ -937,8 +986,13 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,0 - PRODUCTVERSION 2,0,0,0 +#ifdef RELEASE_BUILD + FILEVERSION 2,7,0,0 + PRODUCTVERSION 2,7,0,0 +#else + FILEVERSION 2,10,0,0 + PRODUCTVERSION 2,10,0,0 +#endif FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -951,19 +1005,27 @@ VS_VERSION_INFO VERSIONINFO BEGIN BLOCK "StringFileInfo" BEGIN - BLOCK "0409fde9" + BLOCK "040904b0" BEGIN VALUE "Comments", "\0" VALUE "CompanyName", "IRC #SoftHistory\0" VALUE "FileDescription", "86Box - an emulator for X86-based systems\0" - VALUE "FileVersion", "2.00\0" +#ifdef RELEASE_BUILD + VALUE "FileVersion", "2.07\0" +#else + VALUE "FileVersion", "2.10\0" +#endif VALUE "InternalName", "86Box\0" VALUE "LegalCopyright", "Copyright (C)SoftHistory, Sarah Walker, 2007-2017, Released under the GNU GPL v2\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "86Box.exe\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "86Box Emulator\0" - VALUE "ProductVersion", "2.00\0" +#ifdef RELEASE_BUILD + VALUE "ProductVersion", "2.07\0" +#else + VALUE "ProductVersion", "2.10\0" +#endif VALUE "SpecialBuild", "\0" END END diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 405349dc5..901ac9215 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -8,7 +8,7 @@ # # Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.120 2018/07/19 +# Version: @(#)Makefile.mingw 1.0.140 2019/12/21 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -27,6 +27,9 @@ endif ifndef DEV_BUILD DEV_BUILD := n endif +ifndef FLTO +FLTO := full +endif ifeq ($(DEV_BUILD), y) ifndef DEBUG @@ -38,29 +41,53 @@ ifeq ($(DEV_BUILD), y) ifndef AMD_K AMD_K := y endif + ifndef CL5422 + CL5422 := y + endif ifndef CRASHDUMP CRASHDUMP := y endif + ifndef D2D + D2D := y + endif ifndef I686 I686 := y endif ifndef LASERXT LASERXT := y endif + ifndef MR495 + MR495 := y + endif ifndef MRTHOR MRTHOR := y endif - ifndef NV_RIVA - NV_RIVA := y - endif ifndef PAS16 - PAS16 := y + PAS16 := n endif ifndef PORTABLE3 PORTABLE3 := y endif - ifndef STEALTH32 - STEALTH32 := y + ifndef PS1M2133 + PS1M2133 := y + endif + ifndef PS2M70T4 + PS2M70T4 := y + endif + ifndef TI + TI := y + endif + ifndef TC430HX + TC430HX := y + endif + ifndef VECTRA54 + VECTRA54 := y + endif + ifndef MICRONICS386 + MICRONICS386 := y + endif + ifndef VGAWONDER + VGAWONDER := y endif ifndef VNC VNC := y @@ -78,29 +105,50 @@ else ifndef AMD_K AMD_K := n endif + ifndef CL5422 + CL5422 := n + endif ifndef CRASHDUMP CRASHDUMP := n endif + ifndef D2D + D2D := n + endif ifndef I686 I686 := n endif ifndef LASERXT LASERXT := n endif + ifndef MR495 + MR495 := n + endif ifndef MRTHOR MRTHOR := n endif - ifndef NV_RIVA - NV_RIVA := n - endif ifndef PAS16 PAS16 := n endif ifndef PORTABLE3 PORTABLE3 := n endif - ifndef STEALTH32 - STEALTH32 := n + ifndef PS1M2133 + PS1M2133 := n + endif + ifndef PS2M70T4 + PS2M70T4 := n + endif + ifndef TI + TI := n + endif + ifndef TC430HX + TC430HX := n + endif + ifndef VECTRA54 + VECTRA54 := n + endif + ifndef MICRONICS386 + MICRONICS386 := n endif ifndef VGAWONDER VGAWONDER := n @@ -126,6 +174,12 @@ endif ifndef X64 X64 := n endif +ifndef ARM +ARM := n +endif +ifndef ARM64 +ARM64 := n +endif ifndef WX WX := n endif @@ -135,6 +189,9 @@ endif ifndef RDP RDP := n endif +ifndef DINPUT + DINPUT := n +endif ifndef OPENAL OPENAL := y endif @@ -145,7 +202,16 @@ ifndef MUNT MUNT := y endif ifndef DYNAREC -DYNAREC := y + DYNAREC := y + ifeq ($(ARM), y) + DYNAREC := n + endif + ifeq ($(ARM64), y) + DYNAREC := n + endif +endif +ifndef DISCORD + DISCORD := y endif @@ -195,20 +261,34 @@ endif # Nothing should need changing from here on.. # ######################################################################### VPATH := $(EXPATH) . cpu \ - cdrom disk floppy game machine \ + cdrom chipset disk floppy game machine \ + printer \ sound \ sound/munt sound/munt/c_interface sound/munt/sha1 \ sound/munt/srchelper \ sound/resid-fp \ scsi video network network/slirp win ifeq ($(X64), y) -CPP := g++ -m64 -CC := gcc -m64 +TOOL_PREFIX := x86_64-w64-mingw32- else -CPP := g++ -m32 -CC := gcc -m32 +TOOL_PREFIX := i686-w64-mingw32- endif +CPP := ${TOOL_PREFIX}g++ +CC := gcc WINDRES := windres +STRIP := strip +ifeq ($(ARM64), y) +CPP := aarch64-w64-mingw32-g++ +CC := aarch64-w64-mingw32-gcc +WINDRES := aarch64-w64-mingw32-windres +STRIP := aarch64-w64-mingw32-strip +endif +ifeq ($(ARM), y) +CPP := armv7-w64-mingw32-g++ +CC := armv7-w64-mingw32-gcc +WINDRES := armv7-w64-mingw32-windres +STRIP := armv7-w64-mingw32-strip +endif DEPS = -MMD -MF $*.d -c $< DEPFILE := win/.depends @@ -244,7 +324,7 @@ else ifeq ($(OPTIM), y) AOPTIM := -mtune=native ifndef COPTIM - COPTIM := -O3 -flto + COPTIM := -O3 -flto=$(FLTO) endif else ifndef COPTIM @@ -253,6 +333,16 @@ else endif endif AFLAGS := -msse2 -mfpmath=sse +ifeq ($(ARM), y) + DFLAGS := -march=armv7-a + AOPTIM := + AFLAGS := -mfloat-abi=hard +endif +ifeq ($(ARM64), y) + DFLAGS := -march=armv8-a + AOPTIM := + AFLAGS := -mfloat-abi=hard +endif RFLAGS := --input-format=rc -O coff ifeq ($(RELEASE), y) OPTS += -DRELEASE_BUILD @@ -262,19 +352,16 @@ ifeq ($(VRAMDUMP), y) OPTS += -DENABLE_VRAM_DUMP RFLAGS += -DENABLE_VRAM_DUMP endif -ifeq ($(X64), y) -PLATCG := codegen_x86-64.o -CGOPS := codegen_ops_x86-64.h -VCG := vid_voodoo_codegen_x86-64.h -else -PLATCG := codegen_x86.o -CGOPS := codegen_ops_x86.h -VCG := vid_voodoo_codegen_x86.h -endif # Optional modules. ifeq ($(DYNAREC), y) +ifeq ($(X64), y) +PLATCG := codegen_x86-64.o +else +PLATCG := codegen_x86.o +endif + OPTS += -DUSE_DYNAREC RFLAGS += -DUSE_DYNAREC DYNARECOBJ := 386_dynarec_ops.o \ @@ -291,7 +378,7 @@ ifneq ($(WX), n) UIOBJ := wx_main.o wx_ui.o wx_stbar.o wx_render.o else UIOBJ := win_ui.o win_stbar.o \ - win_ddraw.o win_d2d.o win_d3d.o win_sdl.o \ + win_sdl.o \ win_dialog.o win_about.o \ win_settings.o win_devconf.o win_snd_gain.o \ win_new_floppy.o win_jsconf.o @@ -315,6 +402,13 @@ MUNTOBJ := midi_mt32.o \ Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o endif +ifeq ($(D2D), y) +OPTS += -DUSE_D2D +RFLAGS += -DUSE_D2D +D2DLIB := -ld2d1 +D2DOBJ := win_d2d.o +endif + ifeq ($(VNC), y) OPTS += -DUSE_VNC RFLAGS += -DUSE_VNC @@ -337,6 +431,16 @@ RDPLIB += -lrdp RDPOBJ := rdp.o endif +ifeq ($(DINPUT), y) +OPTS += -DUSE_DINPUT +endif + +ifeq ($(DISCORD), y) +OPTS += -DUSE_DISCORD +RFLAGS += -DUSE_DISCORD +DISCORDOBJ := win_discord.o +endif + # Options for the DEV branch. ifeq ($(DEV_BRANCH), y) OPTS += -DDEV_BRANCH @@ -346,6 +450,10 @@ ifeq ($(AMD_K), y) OPTS += -DUSE_AMD_K endif +ifeq ($(CL5422), y) +OPTS += -DUSE_CL5422 +endif + ifeq ($(CRASHDUMPOBJ), y) OPTS += -DUSE_CRASHDUMP DEVBROBJ += win_crashdump.o @@ -353,6 +461,7 @@ endif ifeq ($(I686), y) OPTS += -DUSE_I686 +DEVBROBJ += m_at_socket8.o endif ifeq ($(LASERXT), y) @@ -360,13 +469,12 @@ OPTS += -DUSE_LASERXT DEVBROBJ += m_xt_laserxt.o endif -ifeq ($(MRTHOR), y) -OPTS += -DUSE_MRTHOR +ifeq ($(MR495), y) +OPTS += -DUSE_MR495 endif -ifeq ($(NV_RIVA), y) -OPTS += -DUSE_RIVA -DEVBROBJ += vid_nvidia.o +ifeq ($(MRTHOR), y) +OPTS += -DUSE_MRTHOR endif ifeq ($(PAS16), y) @@ -378,9 +486,28 @@ ifeq ($(PORTABLE3), y) OPTS += -DUSE_PORTABLE3 endif -ifeq ($(STEALTH32), y) -OPTS += -DUSE_STEALTH32 -DEVBROBJ += vid_icd2061.o +ifeq ($(PS1M2133), y) +OPTS += -DUSE_PS1M2133 +endif + +ifeq ($(PS2M70T4), y) +OPTS += -DUSE_PS2M70T4 +endif + +ifeq ($(TI), y) +OPTS += -DUSE_TI +endif + +ifeq ($(TC430HX), y) +OPTS += -DUSE_TC430HX +endif + +ifeq ($(VECTRA54), y) +OPTS += -DUSE_VECTRA54 +endif + +ifeq ($(MICRONICS386), y) +OPTS += -DUSE_MICRONICS386 endif ifeq ($(VGAWONDER), y) @@ -403,48 +530,56 @@ endif # Final versions of the toolchain flags. CFLAGS := $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ $(AFLAGS) -fomit-frame-pointer -mstackrealign -Wall \ - -fno-strict-aliasing + -fno-strict-aliasing -funroll-loops + +# Add freetyp2 references through pkgconfig +CFLAGS := $(CFLAGS) `pkg-config.exe --cflags freetype2` + CXXFLAGS := $(CFLAGS) ######################################################################### # Create the (final) list of objects to build. # ######################################################################### -MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \ - pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \ - device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) +MAINOBJ := pc.o config.o random.o timer.o io.o apm_new.o dma.o nmi.o \ + pic.o pit.o port_92.o ppi.o pci.o mca.o mcr.o mem.o \ + rom.o device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) -INTELOBJ := intel.o \ - intel_flash.o \ +INTELOBJ := intel_flash.o \ intel_sio.o intel_piix.o CPUOBJ := cpu.o cpu_table.o \ - 808x.o 386.o 386_dynarec.o \ + 808x.o 386.o \ + 386_dynarec.o \ x86seg.o x87.o \ $(DYNARECOBJ) +CHIPSETOBJ := acc2168.o acer_m3a.o ali1429.o headland.o \ + intel_4x0.o neat.o opti495.o scat.o \ + sis_85c471.o sis_85c496.o \ + wd76c10.o + MCHOBJ := machine.o machine_table.o \ m_xt.o m_xt_compaq.o \ m_xt_t1000.o m_xt_t1000_vid.o \ - m_xt_xi8088.o \ + m_xt_xi8088.o m_xt_zenith.o \ m_pcjr.o \ - m_amstrad.o \ - m_europc.o \ + m_amstrad.o m_europc.o \ m_olivetti_m24.o m_tandy.o \ - m_at.o \ - m_at_ali1429.o m_at_commodore.o \ - m_at_neat.o m_at_headland.o \ + m_at.o m_at_commodore.o \ m_at_t3100e.o m_at_t3100e_vid.o \ m_ps1.o m_ps1_hdc.o \ m_ps2_isa.o m_ps2_mca.o \ - m_at_opti495.o m_at_scat.o \ - m_at_compaq.o m_at_wd76c10.o \ - m_at_sis_85c471.o m_at_sis_85c496.o \ - m_at_4x0.o + m_at_compaq.o \ + m_at_286_386sx.o m_at_386dx_486.o \ + m_at_socket4_5.o m_at_socket7_s7.o -DEVOBJ := bugger.o lpt.o $(SERIAL) \ - sio_fdc37c66x.o sio_fdc37c669.o sio_fdc37c93x.o \ - sio_pc87306.o sio_w83877f.o sio_um8669f.o \ +DEVOBJ := bugger.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \ + sio_acc3221.o \ + sio_fdc37c66x.o sio_fdc37c669.o \ + sio_fdc37c93x.o \ + sio_pc87306.o sio_w83877f.o \ + sio_um8669f.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ gameport.o \ @@ -457,18 +592,19 @@ DEVOBJ := bugger.o lpt.o $(SERIAL) \ FDDOBJ := fdd.o fdc.o fdi2raw.o \ fdd_common.o fdd_86f.o \ fdd_fdi.o fdd_imd.o fdd_img.o fdd_json.o \ - fdd_td0.o + fdd_mfm.o fdd_td0.o HDDOBJ := hdd.o \ hdd_image.o hdd_table.o \ hdc.o \ - hdc_mfm_xt.o hdc_mfm_at.o \ + hdc_st506_xt.o hdc_st506_at.o \ hdc_xta.o \ hdc_esdi_at.o hdc_esdi_mca.o \ - hdc_xtide.o hdc_ide.o + hdc_xtide.o hdc_ide.o \ + hdc_ide_sff8038i.o CDROMOBJ := cdrom.o \ - cdrom_dosbox.o cdrom_image.o cdrom_null.o + cdrom_image_backend.o cdrom_image.o ZIPOBJ := zip.o @@ -476,12 +612,11 @@ ifeq ($(USB), y) USBOBJ := usb.o endif -SCSIOBJ := scsi.o \ - scsi_bus.o scsi_device.o \ - scsi_disk.o \ +SCSIOBJ := scsi.o scsi_device.o \ + scsi_cdrom.o scsi_disk.o \ scsi_x54x.o \ scsi_aha154x.o scsi_buslogic.o \ - scsi_ncr5380.o scsi_ncr53c810.o + scsi_ncr5380.o scsi_ncr53c8xx.o NETOBJ := network.o \ net_pcap.o \ @@ -491,12 +626,15 @@ NETOBJ := network.o \ sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ net_dp8390.o \ net_3c503.o net_ne2000.o \ - net_wd8003.o + net_pcnet.o net_wd8003.o +PRINTOBJ := png.o prt_cpmap.o \ + prt_escp.o prt_text.o prt_ps.o + SNDOBJ := sound.o \ openal.o \ - snd_opl.o snd_dbopl.o \ - dbopl.o nukedopl.o \ + snd_opl.o snd_opl_backend.o \ + nukedopl.o \ snd_resid.o \ convolve.o convolve-sse.o envelope.o extfilt.o \ filter.o pot.o sid.o voice.o wave6581__ST.o \ @@ -524,6 +662,8 @@ VIDOBJ := video.o \ vid_hercules.o vid_herculesplus.o vid_incolor.o \ vid_colorplus.o \ vid_genius.o \ + vid_pgc.o vid_im1024.o \ + vid_sigma.o \ vid_wy700.o \ vid_ega.o vid_ega_render.o \ vid_svga.o vid_svga_render.o \ @@ -531,15 +671,19 @@ VIDOBJ := video.o \ vid_ati_eeprom.o \ vid_ati18800.o vid_ati28800.o \ vid_ati_mach64.o vid_ati68860_ramdac.o \ - vid_ics2595.o \ + vid_bt48x_ramdac.o \ + vid_av9194.o \ + vid_icd2061.o vid_ics2595.o \ vid_cl54xx.o \ vid_et4000.o vid_sc1502x_ramdac.o \ vid_et4000w32.o vid_stg_ramdac.o \ + vid_ht216.o \ vid_oak_oti.o \ vid_paradise.o \ vid_ti_cf62011.o \ vid_tvga.o \ vid_tgui9440.o vid_tkd8001_ramdac.o \ + vid_att20c49x_ramdac.o \ vid_s3.o vid_s3_virge.o \ vid_sdac_ramdac.o \ vid_voodoo.o @@ -547,21 +691,24 @@ VIDOBJ := video.o \ PLATOBJ := win.o \ win_dynld.o win_thread.o \ win_cdrom.o win_keyboard.o \ - win_mouse.o win_joystick.o win_midi.o + win_midi.o \ + win_mouse.o win_joystick.o -OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(MCHOBJ) $(DEVOBJ) \ - $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ - $(USBOBJ) $(NETOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ - $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ - $(DEVBROBJ) +OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) \ + $(DEVOBJ) $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ + $(USBOBJ) $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ + $(PLATOBJ) $(UIOBJ) $(D2DOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ + $(DEVBROBJ) $(DISCORDOBJ) ifdef EXOBJ OBJ += $(EXOBJ) endif -LIBS := -mwindows \ - -lopenal.dll \ - -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 -ld2d1\ - -lcomctl32 -lwinmm +LIBS := -mwindows -lcomctl32 \ + -lopenal -lole32 + +ifeq ($(D2D), y) +LIBS += $(D2DLIB) +endif ifeq ($(VNC), y) LIBS += $(VNCLIB) -lws2_32 endif @@ -571,12 +718,15 @@ endif ifneq ($(WX), n) LIBS += $(WX_LIBS) -lm endif -LIBS += -lpng -lz -lwsock32 -liphlpapi -LIBS += -static -lstdc++ -lgcc +LIBS += -lpng -lz -lwsock32 -liphlpapi -ldinput8 -lSDL2 -limm32 -lhid -lsetupapi -loleaut32 -lversion -lwinmm -static -lstdc++ ifneq ($(X64), y) LIBS += -Wl,--large-address-aware endif +ifneq ($(DINPUT), y) + LIBS += -lxinput +endif +LIBS += -static # Build module rules. ifeq ($(AUTODEP), y) @@ -629,7 +779,7 @@ $(PROG).exe: $(OBJ) 86Box.res @echo Linking $(PROG).exe .. @$(CC) -o $(PROG).exe $(OBJ) 86Box.res $(LIBS) ifneq ($(DEBUG), y) - @strip $(PROG).exe + @$(STRIP) $(PROG).exe endif pcap_if.res: pcap_if.rc @@ -640,13 +790,13 @@ pcap_if.exe: pcap_if.o win_dynld.o pcap_if.res @echo Linking pcap_if.exe .. @$(CC) -o pcap_if.exe pcap_if.o win_dynld.o pcap_if.res ifneq ($(DEBUG), y) - @strip pcap_if.exe + @$(STRIP) pcap_if.exe endif hello.exe: hello.o $(CXX) $(LDFLAGS) -o hello.exe hello.o $(WXLIBS) $(LIBS) ifneq ($(DEBUG), y) - @strip hello.exe + @$(STRIP) hello.exe endif diff --git a/src/win/Makefile_ndr.mingw b/src/win/Makefile_ndr.mingw new file mode 100644 index 000000000..facc55327 --- /dev/null +++ b/src/win/Makefile_ndr.mingw @@ -0,0 +1,844 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# Makefile for Win32 (MinGW32) environment. +# +# Version: @(#)Makefile.mingw 1.0.140 2019/12/21 +# +# Authors: Miran Grca, +# Fred N. van Kempen, +# + +# Various compile-time options. +ifndef STUFF +STUFF := +endif + +# Add feature selections here. +ifndef EXTRAS +EXTRAS := +endif + +ifndef DEV_BUILD +DEV_BUILD := n +endif +ifndef FLTO +FLTO := full +endif + +ifeq ($(DEV_BUILD), y) + ifndef DEBUG + DEBUG := y + endif + ifndef DEV_BRANCH + DEV_BRANCH := y + endif + ifndef AMD_K + AMD_K := y + endif + ifndef CL5422 + CL5422 := y + endif + ifndef CRASHDUMP + CRASHDUMP := y + endif + ifndef D2D + D2D := y + endif + ifndef I686 + I686 := y + endif + ifndef LASERXT + LASERXT := y + endif + ifndef MR495 + MR495 := y + endif + ifndef MRTHOR + MRTHOR := y + endif + ifndef PAS16 + PAS16 := n + endif + ifndef PORTABLE3 + PORTABLE3 := y + endif + ifndef PS1M2133 + PS1M2133 := y + endif + ifndef PS2M70T4 + PS2M70T4 := y + endif + ifndef TI + TI := y + endif + ifndef TC430HX + TC430HX := y + endif + ifndef VECTRA54 + VECTRA54 := y + endif + ifndef MICRONICS386 + MICRONICS386 := y + endif + ifndef VGAWONDER + VGAWONDER := y + endif + ifndef VNC + VNC := y + endif + ifndef XL24 + XL24 := y + endif +else + ifndef DEBUG + DEBUG := n + endif + ifndef DEV_BRANCH + DEV_BRANCH := n + endif + ifndef AMD_K + AMD_K := n + endif + ifndef CL5422 + CL5422 := n + endif + ifndef CRASHDUMP + CRASHDUMP := n + endif + ifndef D2D + D2D := n + endif + ifndef I686 + I686 := n + endif + ifndef LASERXT + LASERXT := n + endif + ifndef MR495 + MR495 := n + endif + ifndef MRTHOR + MRTHOR := n + endif + ifndef PAS16 + PAS16 := n + endif + ifndef PORTABLE3 + PORTABLE3 := n + endif + ifndef PS1M2133 + PS1M2133 := n + endif + ifndef PS2M70T4 + PS2M70T4 := n + endif + ifndef TI + TI := n + endif + ifndef TC430HX + TC430HX := n + endif + ifndef VECTRA54 + VECTRA54 := n + endif + ifndef MICRONICS386 + MICRONICS386 := n + endif + ifndef VGAWONDER + VGAWONDER := n + endif + ifndef VNC + VNC := n + endif + ifndef XL24 + XL24 := n + endif +endif + +# Defaults for several build options (possibly defined in a chained file.) +ifndef AUTODEP +AUTODEP := n +endif +ifndef OPTIM +OPTIM := n +endif +ifndef RELEASE +RELEASE := n +endif +ifndef X64 +X64 := n +endif +ifndef ARM +ARM := n +endif +ifndef ARM64 +ARM64 := n +endif +ifndef WX +WX := n +endif +ifndef USB +USB := n +endif +ifndef RDP +RDP := n +endif +ifndef DINPUT + DINPUT := n +endif +ifndef OPENAL +OPENAL := y +endif +ifndef FLUIDSYNTH +FLUIDSYNTH := y +endif +ifndef MUNT +MUNT := y +endif +ifndef DYNAREC + DYNAREC := y + ifeq ($(ARM), y) + DYNAREC := n + endif + ifeq ($(ARM64), y) + DYNAREC := n + endif +endif +ifndef DISCORD + DISCORD := y +endif + + +# Name of the executable. +ifndef PROG + ifneq ($(WX), n) + PROG := Wx86Box + else + PROG := 86Box + endif +endif + +# WxWidgets basic info. Extract using the config program. +ifneq ($(WX), n) + EXPATH += wx + WX_CONFIG := wx-config.exe + ifeq ($(WX), y) + WX_PATH := C:/MinGW32/WxWidgets + WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ + -I$(WX_PATH)/include/wx-3.0 \ + -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread +# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma + WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ + -lwx_mswu-3.0.dll \ + -lrpcrt4 -loleaut32 -lole32 -luuid \ + -lwinspool -lwinmm -lshell32 -lcomctl32 \ + -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 + endif + ifeq ($(WX), static) + WX_PATH := C:/MinGW32/WxWidgets + WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ + -I$(WX_PATH)/include/wx-3.0 \ + -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread +# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma + WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ + -lwx_mswu-3.0 -lwxscintilla-3.0 \ + -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 \ + -lwxregexu-3.0 -lwxexpat-3.0 \ + -lrpcrt4 -loleaut32 -lole32 -luuid \ + -lwinspool -lwinmm -lshell32 -lcomctl32 \ + -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 + endif +endif + + +######################################################################### +# Nothing should need changing from here on.. # +######################################################################### +VPATH := $(EXPATH) . cpu_new \ + cdrom chipset disk floppy game machine \ + printer \ + sound \ + sound/munt sound/munt/c_interface sound/munt/sha1 \ + sound/munt/srchelper \ + sound/resid-fp \ + scsi video network network/slirp win +ifeq ($(X64), y) +TOOL_PREFIX := x86_64-w64-mingw32- +else +TOOL_PREFIX := i686-w64-mingw32- +endif +CPP := ${TOOL_PREFIX}g++ +CC := ${TOOL_PREFIX}gcc +WINDRES := windres +STRIP := strip +ifeq ($(ARM64), y) +CPP := aarch64-w64-mingw32-g++ +CC := aarch64-w64-mingw32-gcc +WINDRES := aarch64-w64-mingw32-windres +STRIP := aarch64-w64-mingw32-strip +endif +ifeq ($(ARM), y) +CPP := armv7-w64-mingw32-g++ +CC := armv7-w64-mingw32-gcc +WINDRES := armv7-w64-mingw32-windres +STRIP := armv7-w64-mingw32-strip +endif +DEPS = -MMD -MF $*.d -c $< +DEPFILE := win/.depends + +# Set up the correct toolchain flags. +OPTS := $(EXTRAS) $(STUFF) +ifdef EXFLAGS +OPTS += $(EXFLAGS) +endif +ifdef EXINC +OPTS += -I$(EXINC) +endif +ifeq ($(X64), y) + ifeq ($(OPTIM), y) + DFLAGS := -march=native + else + DFLAGS := + endif +else + ifeq ($(OPTIM), y) + DFLAGS := -march=native + else + DFLAGS := -march=i686 + endif +endif +ifeq ($(DEBUG), y) + DFLAGS += -ggdb -DDEBUG + AOPTIM := + ifndef COPTIM + COPTIM := -Og + endif +else + DFLAGS += -g0 + ifeq ($(OPTIM), y) + AOPTIM := -mtune=native + ifndef COPTIM + COPTIM := -O3 -flto=$(FLTO) + endif + else + ifndef COPTIM + COPTIM := -O3 + endif + endif +endif +AFLAGS := -msse2 -mfpmath=sse +ifeq ($(ARM), y) + DFLAGS := -march=armv7-a + AOPTIM := + AFLAGS := -mfloat-abi=hard +endif +ifeq ($(ARM64), y) + DFLAGS := -march=armv8-a + AOPTIM := + AFLAGS := -mfloat-abi=hard +endif +RFLAGS := --input-format=rc -O coff +OPTS += -DUSE_NEW_DYNAREC +ifeq ($(RELEASE), y) +OPTS += -DRELEASE_BUILD +RFLAGS += -DRELEASE_BUILD +endif +ifeq ($(VRAMDUMP), y) +OPTS += -DENABLE_VRAM_DUMP +RFLAGS += -DENABLE_VRAM_DUMP +endif + + +# Optional modules. +ifeq ($(DYNAREC), y) +ifeq ($(X64), y) +PLATCG := codegen_backend_x86-64.o codegen_backend_x86-64_ops.o codegen_backend_x86-64_ops_sse.o \ + codegen_backend_x86-64_uops.o +else +PLATCG := 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 +endif + +OPTS += -DUSE_DYNAREC +RFLAGS += -DUSE_DYNAREC +DYNARECOBJ := 386_dynarec_ops.o \ + codegen.o codegen_accumulate.o codegen_allocator.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_k6.o codegen_timing_pentium.o \ + codegen_timing_winchip.o codegen_timing_winchip2.o $(PLATCG) +endif + +ifneq ($(WX), n) + OPTS += -DUSE_WX $(WX_FLAGS) + LIBS += $(WX_LIBS) + UIOBJ := wx_main.o wx_ui.o wx_stbar.o wx_render.o +else + UIOBJ := win_ui.o win_stbar.o \ + win_sdl.o \ + win_dialog.o win_about.o \ + win_settings.o win_devconf.o win_snd_gain.o \ + win_new_floppy.o win_jsconf.o +endif + +ifeq ($(OPENAL), y) +OPTS += -DUSE_OPENAL +endif +ifeq ($(FLUIDSYNTH), y) +OPTS += -DUSE_FLUIDSYNTH +FSYNTHOBJ := midi_fluidsynth.o +endif + +ifeq ($(MUNT), y) +OPTS += -DUSE_MUNT +MUNTOBJ := midi_mt32.o \ + Analog.o BReverbModel.o File.o FileStream.o LA32Ramp.o \ + LA32FloatWaveGenerator.o LA32WaveGenerator.o \ + MidiStreamParser.o Part.o Partial.o PartialManager.o \ + Poly.o ROMInfo.o SampleRateConverter_dummy.o Synth.o \ + Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o +endif + +ifeq ($(D2D), y) +OPTS += -DUSE_D2D +RFLAGS += -DUSE_D2D +D2DLIB := -ld2d1 +D2DOBJ := win_d2d.o +endif + +ifeq ($(VNC), y) +OPTS += -DUSE_VNC +RFLAGS += -DUSE_VNC + ifneq ($(VNC_PATH), ) + OPTS += -I$(VNC_PATH)\INCLUDE + VNCLIB := -L$(VNC_PATH)\LIB + endif +VNCLIB += -lvncserver +VNCOBJ := vnc.o vnc_keymap.o +endif + +ifeq ($(RDP), y) +OPTS += -DUSE_RDP +RFLAGS += -DUSE_RDP + ifneq ($(RDP_PATH), ) + OPTS += -I$(RDP_PATH)\INCLUDE + RDPLIB := -L$(RDP_PATH)\LIB + endif +RDPLIB += -lrdp +RDPOBJ := rdp.o +endif + +ifeq ($(DINPUT), y) +OPTS += -DUSE_DINPUT +endif + +ifeq ($(DISCORD), y) +OPTS += -DUSE_DISCORD +RFLAGS += -DUSE_DISCORD +DISCORDOBJ := win_discord.o +endif + +# Options for the DEV branch. +ifeq ($(DEV_BRANCH), y) +OPTS += -DDEV_BRANCH +DEVBROBJ := + +ifeq ($(AMD_K), y) +OPTS += -DUSE_AMD_K +endif + +ifeq ($(CL5422), y) +OPTS += -DUSE_CL5422 +endif + +ifeq ($(CRASHDUMPOBJ), y) +OPTS += -DUSE_CRASHDUMP +DEVBROBJ += win_crashdump.o +endif + +ifeq ($(I686), y) +OPTS += -DUSE_I686 +DEVBROBJ += m_at_socket8.o +endif + +ifeq ($(LASERXT), y) +OPTS += -DUSE_LASERXT +DEVBROBJ += m_xt_laserxt.o +endif + +ifeq ($(MR495), y) +OPTS += -DUSE_MR495 +endif + +ifeq ($(MRTHOR), y) +OPTS += -DUSE_MRTHOR +endif + +ifeq ($(PAS16), y) +OPTS += -DUSE_PAS16 +DEVBROBJ += snd_pas16.o +endif + +ifeq ($(PORTABLE3), y) +OPTS += -DUSE_PORTABLE3 +endif + +ifeq ($(PS1M2133), y) +OPTS += -DUSE_PS1M2133 +endif + +ifeq ($(PS2M70T4), y) +OPTS += -DUSE_PS2M70T4 +endif + +ifeq ($(TI), y) +OPTS += -DUSE_TI +endif + +ifeq ($(TC430HX), y) +OPTS += -DUSE_TC430HX +endif + +ifeq ($(VECTRA54), y) +OPTS += -DUSE_VECTRA54 +endif + +ifeq ($(MICRONICS386), y) +OPTS += -DUSE_MICRONICS386 +endif + +ifeq ($(VGAWONDER), y) +OPTS += -DUSE_VGAWONDER +endif + +ifeq ($(XL24), y) +OPTS += -DUSE_XL24 +endif + +endif + + +# Options for works-in-progress. +ifndef SERIAL +SERIAL := serial.o +endif + + +# Final versions of the toolchain flags. +CFLAGS := $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ + $(AFLAGS) -fomit-frame-pointer -mstackrealign -Wall \ + -fno-strict-aliasing -funroll-loops + +# Add freetyp2 references through pkgconfig +CFLAGS := $(CFLAGS) `pkg-config.exe --cflags freetype2` + +CXXFLAGS := $(CFLAGS) + + +######################################################################### +# Create the (final) list of objects to build. # +######################################################################### +MAINOBJ := pc.o config.o random.o timer.o io.o apm_new.o dma.o nmi.o \ + pic.o pit.o port_92.o ppi.o pci.o mca.o mcr.o mem_new.o \ + rom.o device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) + +INTELOBJ := intel_flash.o \ + intel_sio.o intel_piix.o + +CPUOBJ := cpu.o cpu_table.o \ + 808x.o 386.o 386_common.o \ + 386_dynarec.o \ + x86seg.o x87.o \ + $(DYNARECOBJ) + +CHIPSETOBJ := acc2168.o acer_m3a.o ali1429.o headland.o \ + intel_4x0.o neat.o opti495.o scat.o \ + sis_85c471.o sis_85c496.o \ + wd76c10.o + +MCHOBJ := machine.o machine_table_new.o \ + m_xt.o m_xt_compaq.o \ + m_xt_t1000.o m_xt_t1000_vid.o \ + m_xt_xi8088.o m_xt_zenith.o \ + m_pcjr.o \ + m_amstrad.o m_europc.o \ + m_olivetti_m24.o m_tandy.o \ + m_at.o m_at_commodore.o \ + m_at_t3100e.o m_at_t3100e_vid.o \ + m_ps1.o m_ps1_hdc.o \ + m_ps2_isa.o m_ps2_mca.o \ + m_at_compaq.o \ + m_at_286_386sx.o m_at_386dx_486.o \ + m_at_socket4_5.o m_at_socket7_s7.o + +DEVOBJ := bugger.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \ + sio_acc3221.o \ + sio_fdc37c66x.o sio_fdc37c669.o \ + sio_fdc37c93x.o \ + sio_pc87306.o sio_w83877f.o \ + sio_um8669f.o \ + keyboard.o \ + keyboard_xt.o keyboard_at.o \ + gameport.o \ + joystick_standard.o joystick_ch_flightstick_pro.o \ + joystick_sw_pad.o joystick_tm_fcs.o \ + mouse.o \ + mouse_bus.o \ + mouse_serial.o mouse_ps2.o + +FDDOBJ := fdd.o fdc.o fdi2raw.o \ + fdd_common.o fdd_86f.o \ + fdd_fdi.o fdd_imd.o fdd_img.o fdd_json.o \ + fdd_mfm.o fdd_td0.o + +HDDOBJ := hdd.o \ + hdd_image.o hdd_table.o \ + hdc.o \ + hdc_st506_xt.o hdc_st506_at.o \ + hdc_xta.o \ + hdc_esdi_at.o hdc_esdi_mca.o \ + hdc_xtide.o hdc_ide.o \ + hdc_ide_sff8038i.o + +CDROMOBJ := cdrom.o \ + cdrom_image_backend.o cdrom_image.o + +ZIPOBJ := zip.o + +ifeq ($(USB), y) +USBOBJ := usb.o +endif + +SCSIOBJ := scsi.o scsi_device.o \ + scsi_cdrom.o scsi_disk.o \ + scsi_x54x.o \ + scsi_aha154x.o scsi_buslogic.o \ + scsi_ncr5380.o scsi_ncr53c8xx.o + +NETOBJ := network.o \ + net_pcap.o \ + net_slirp.o \ + bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o \ + ip_input.o queue.o tcp_input.o debug.o ip_output.o \ + sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ + net_dp8390.o \ + net_3c503.o net_ne2000.o \ + net_pcnet.o net_wd8003.o + +PRINTOBJ := png.o prt_cpmap.o \ + prt_escp.o prt_text.o prt_ps.o + +SNDOBJ := sound.o \ + openal.o \ + snd_opl.o snd_opl_backend.o \ + nukedopl.o \ + snd_resid.o \ + 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 \ + midi.o midi_system.o \ + snd_speaker.o \ + snd_pssj.o \ + snd_lpt_dac.o snd_lpt_dss.o \ + snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ + snd_cms.o \ + snd_gus.o \ + snd_sb.o snd_sb_dsp.o \ + snd_emu8k.o snd_mpu401.o \ + snd_sn76489.o snd_ssi2001.o \ + snd_wss.o \ + snd_ym7128.o + +VIDOBJ := video.o \ + vid_table.o \ + vid_cga.o vid_cga_comp.o \ + vid_compaq_cga.o \ + vid_mda.o \ + vid_hercules.o vid_herculesplus.o vid_incolor.o \ + vid_colorplus.o \ + vid_genius.o \ + vid_pgc.o vid_im1024.o \ + vid_sigma.o \ + vid_wy700.o \ + vid_ega.o vid_ega_render.o \ + vid_svga.o vid_svga_render.o \ + vid_vga.o \ + vid_ati_eeprom.o \ + vid_ati18800.o vid_ati28800.o \ + vid_ati_mach64.o vid_ati68860_ramdac.o \ + vid_bt48x_ramdac.o \ + vid_av9194.o \ + vid_icd2061.o vid_ics2595.o \ + vid_cl54xx.o \ + vid_et4000.o vid_sc1502x_ramdac.o \ + vid_et4000w32.o vid_stg_ramdac.o \ + vid_ht216.o \ + vid_oak_oti.o \ + vid_paradise.o \ + vid_ti_cf62011.o \ + vid_tvga.o \ + vid_tgui9440.o vid_tkd8001_ramdac.o \ + vid_att20c49x_ramdac.o \ + vid_s3.o vid_s3_virge.o \ + vid_sdac_ramdac.o \ + vid_voodoo.o + +PLATOBJ := win.o \ + win_dynld.o win_thread.o \ + win_cdrom.o win_keyboard.o \ + win_midi.o \ + win_mouse.o win_joystick.o + +OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) \ + $(DEVOBJ) $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ + $(USBOBJ) $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ + $(PLATOBJ) $(UIOBJ) $(D2DOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ + $(DEVBROBJ) $(DISCORDOBJ) +ifdef EXOBJ +OBJ += $(EXOBJ) +endif + +LIBS := -mwindows -lcomctl32 \ + -lopenal -lole32 + +ifeq ($(D2D), y) +LIBS += $(D2DLIB) +endif +ifeq ($(VNC), y) +LIBS += $(VNCLIB) -lws2_32 +endif +ifeq ($(RDP), y) +LIBS += $(RDPLIB) +endif +ifneq ($(WX), n) +LIBS += $(WX_LIBS) -lm +endif +LIBS += -lpng -lz -lwsock32 -liphlpapi -ldinput8 -lSDL2 -limm32 -lhid -lsetupapi -loleaut32 -lversion -lwinmm -static -lstdc++ +ifneq ($(X64), y) +LIBS += -Wl,--large-address-aware +endif +ifneq ($(DINPUT), y) + LIBS += -lxinput +endif + +LIBS += -static + +# Build module rules. +ifeq ($(AUTODEP), y) +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -c $< +else +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CXXFLAGS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CXXFLAGS) -c $< + +%.d: %.c $(wildcard $*.d) + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cc $(wildcard $*.d) + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cpp $(wildcard $*.d) + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL +endif + + +all: $(PROG).exe pcap_if.exe + + +86Box.res: 86Box.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) $(EXTRAS) -i $< -o 86Box.res + +$(PROG).exe: $(OBJ) 86Box.res + @echo Linking $(PROG).exe .. + @$(CC) -o $(PROG).exe $(OBJ) 86Box.res $(LIBS) +ifneq ($(DEBUG), y) + @$(STRIP) $(PROG).exe +endif + +pcap_if.res: pcap_if.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) -i $< -o pcap_if.res + +pcap_if.exe: pcap_if.o win_dynld.o pcap_if.res + @echo Linking pcap_if.exe .. + @$(CC) -o pcap_if.exe pcap_if.o win_dynld.o pcap_if.res +ifneq ($(DEBUG), y) + @$(STRIP) pcap_if.exe +endif + +hello.exe: hello.o + $(CXX) $(LDFLAGS) -o hello.exe hello.o $(WXLIBS) $(LIBS) +ifneq ($(DEBUG), y) + @$(STRIP) hello.exe +endif + + +clean: + @echo Cleaning objects.. + @-rm -f *.o 2>NUL + @-rm -f *.res 2>NUL + +clobber: clean + @echo Cleaning executables.. + @-rm -f *.d 2>NUL + @-rm -f *.exe 2>NUL +# @-rm -f $(DEPFILE) 2>NUL + +ifneq ($(AUTODEP), y) +depclean: + @-rm -f $(DEPFILE) 2>NUL + @echo Creating dependencies.. + @echo # Run "make depends" to re-create this file. >$(DEPFILE) + +depends: DEPOBJ=$(OBJ:%.o=%.d) +depends: depclean $(OBJ:%.o=%.d) + @-cat $(DEPOBJ) >>$(DEPFILE) + @-rm -f $(DEPOBJ) + +$(DEPFILE): +endif + + +# Module dependencies. +ifeq ($(AUTODEP), y) +#-include $(OBJ:%.o=%.d) (better, but sloooowwwww) +-include *.d +else +include $(wildcard $(DEPFILE)) +endif + + +# End of Makefile.mingw. diff --git a/src/win/discord_game_sdk.h b/src/win/discord_game_sdk.h new file mode 100644 index 000000000..50aa13736 --- /dev/null +++ b/src/win/discord_game_sdk.h @@ -0,0 +1,653 @@ +/* + * This file is distributed as a part of the Discord Game SDK. + * Downloading, accessing, or using the API or SDK is bound by + * the Discord Developer Terms of Service: + * https://github.com/discordapp/discord-api-docs/blob/master/docs/Legal.md + */ + +#ifndef _DISCORD_GAME_SDK_H_ +#define _DISCORD_GAME_SDK_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#ifndef __cplusplus +#include +#endif + +#define DISCORD_VERSION 2 +#define DISCORD_APPLICATION_MANAGER_VERSION 1 +#define DISCORD_USER_MANAGER_VERSION 1 +#define DISCORD_IMAGE_MANAGER_VERSION 1 +#define DISCORD_ACTIVITY_MANAGER_VERSION 1 +#define DISCORD_RELATIONSHIP_MANAGER_VERSION 1 +#define DISCORD_LOBBY_MANAGER_VERSION 1 +#define DISCORD_NETWORK_MANAGER_VERSION 1 +#define DISCORD_OVERLAY_MANAGER_VERSION 1 +#define DISCORD_STORAGE_MANAGER_VERSION 1 +#define DISCORD_STORE_MANAGER_VERSION 1 +#define DISCORD_VOICE_MANAGER_VERSION 1 +#define DISCORD_ACHIEVEMENT_MANAGER_VERSION 1 + +enum EDiscordResult { + DiscordResult_Ok = 0, + DiscordResult_ServiceUnavailable = 1, + DiscordResult_InvalidVersion = 2, + DiscordResult_LockFailed = 3, + DiscordResult_InternalError = 4, + DiscordResult_InvalidPayload = 5, + DiscordResult_InvalidCommand = 6, + DiscordResult_InvalidPermissions = 7, + DiscordResult_NotFetched = 8, + DiscordResult_NotFound = 9, + DiscordResult_Conflict = 10, + DiscordResult_InvalidSecret = 11, + DiscordResult_InvalidJoinSecret = 12, + DiscordResult_NoEligibleActivity = 13, + DiscordResult_InvalidInvite = 14, + DiscordResult_NotAuthenticated = 15, + DiscordResult_InvalidAccessToken = 16, + DiscordResult_ApplicationMismatch = 17, + DiscordResult_InvalidDataUrl = 18, + DiscordResult_InvalidBase64 = 19, + DiscordResult_NotFiltered = 20, + DiscordResult_LobbyFull = 21, + DiscordResult_InvalidLobbySecret = 22, + DiscordResult_InvalidFilename = 23, + DiscordResult_InvalidFileSize = 24, + DiscordResult_InvalidEntitlement = 25, + DiscordResult_NotInstalled = 26, + DiscordResult_NotRunning = 27, + DiscordResult_InsufficientBuffer = 28, + DiscordResult_PurchaseCanceled = 29, + DiscordResult_InvalidGuild = 30, + DiscordResult_InvalidEvent = 31, + DiscordResult_InvalidChannel = 32, + DiscordResult_InvalidOrigin = 33, + DiscordResult_RateLimited = 34, + DiscordResult_OAuth2Error = 35, + DiscordResult_SelectChannelTimeout = 36, + DiscordResult_GetGuildTimeout = 37, + DiscordResult_SelectVoiceForceRequired = 38, + DiscordResult_CaptureShortcutAlreadyListening = 39, + DiscordResult_UnauthorizedForAchievement = 40, + DiscordResult_InvalidGiftCode = 41, + DiscordResult_PurchaseError = 42, + DiscordResult_TransactionAborted = 43, +}; + +enum EDiscordCreateFlags { + DiscordCreateFlags_Default = 0, + DiscordCreateFlags_NoRequireDiscord = 1, +}; + +enum EDiscordLogLevel { + DiscordLogLevel_Error = 1, + DiscordLogLevel_Warn, + DiscordLogLevel_Info, + DiscordLogLevel_Debug, +}; + +enum EDiscordUserFlag { + DiscordUserFlag_Partner = 2, + DiscordUserFlag_HypeSquadEvents = 4, + DiscordUserFlag_HypeSquadHouse1 = 64, + DiscordUserFlag_HypeSquadHouse2 = 128, + DiscordUserFlag_HypeSquadHouse3 = 256, +}; + +enum EDiscordPremiumType { + DiscordPremiumType_None = 0, + DiscordPremiumType_Tier1 = 1, + DiscordPremiumType_Tier2 = 2, +}; + +enum EDiscordImageType { + DiscordImageType_User, +}; + +enum EDiscordActivityType { + DiscordActivityType_Playing, + DiscordActivityType_Streaming, + DiscordActivityType_Listening, + DiscordActivityType_Watching, +}; + +enum EDiscordActivityActionType { + DiscordActivityActionType_Join = 1, + DiscordActivityActionType_Spectate, +}; + +enum EDiscordActivityJoinRequestReply { + DiscordActivityJoinRequestReply_No, + DiscordActivityJoinRequestReply_Yes, + DiscordActivityJoinRequestReply_Ignore, +}; + +enum EDiscordStatus { + DiscordStatus_Offline = 0, + DiscordStatus_Online = 1, + DiscordStatus_Idle = 2, + DiscordStatus_DoNotDisturb = 3, +}; + +enum EDiscordRelationshipType { + DiscordRelationshipType_None, + DiscordRelationshipType_Friend, + DiscordRelationshipType_Blocked, + DiscordRelationshipType_PendingIncoming, + DiscordRelationshipType_PendingOutgoing, + DiscordRelationshipType_Implicit, +}; + +enum EDiscordLobbyType { + DiscordLobbyType_Private = 1, + DiscordLobbyType_Public, +}; + +enum EDiscordLobbySearchComparison { + DiscordLobbySearchComparison_LessThanOrEqual = -2, + DiscordLobbySearchComparison_LessThan, + DiscordLobbySearchComparison_Equal, + DiscordLobbySearchComparison_GreaterThan, + DiscordLobbySearchComparison_GreaterThanOrEqual, + DiscordLobbySearchComparison_NotEqual, +}; + +enum EDiscordLobbySearchCast { + DiscordLobbySearchCast_String = 1, + DiscordLobbySearchCast_Number, +}; + +enum EDiscordLobbySearchDistance { + DiscordLobbySearchDistance_Local, + DiscordLobbySearchDistance_Default, + DiscordLobbySearchDistance_Extended, + DiscordLobbySearchDistance_Global, +}; + +enum EDiscordEntitlementType { + DiscordEntitlementType_Purchase = 1, + DiscordEntitlementType_PremiumSubscription, + DiscordEntitlementType_DeveloperGift, + DiscordEntitlementType_TestModePurchase, + DiscordEntitlementType_FreePurchase, + DiscordEntitlementType_UserGift, + DiscordEntitlementType_PremiumPurchase, +}; + +enum EDiscordSkuType { + DiscordSkuType_Application = 1, + DiscordSkuType_DLC, + DiscordSkuType_Consumable, + DiscordSkuType_Bundle, +}; + +enum EDiscordInputModeType { + DiscordInputModeType_VoiceActivity = 0, + DiscordInputModeType_PushToTalk, +}; + +typedef int64_t DiscordClientId; +typedef int32_t DiscordVersion; +typedef int64_t DiscordSnowflake; +typedef int64_t DiscordTimestamp; +typedef DiscordSnowflake DiscordUserId; +typedef char DiscordLocale[128]; +typedef char DiscordBranch[4096]; +typedef DiscordSnowflake DiscordLobbyId; +typedef char DiscordLobbySecret[128]; +typedef char DiscordMetadataKey[256]; +typedef char DiscordMetadataValue[4096]; +typedef uint64_t DiscordNetworkPeerId; +typedef uint8_t DiscordNetworkChannelId; +typedef char DiscordPath[4096]; +typedef char DiscordDateTime[64]; + +struct DiscordUser { + DiscordUserId id; + char username[256]; + char discriminator[8]; + char avatar[128]; + bool bot; +}; + +struct DiscordOAuth2Token { + char access_token[128]; + char scopes[1024]; + DiscordTimestamp expires; +}; + +struct DiscordImageHandle { + enum EDiscordImageType type; + int64_t id; + uint32_t size; +}; + +struct DiscordImageDimensions { + uint32_t width; + uint32_t height; +}; + +struct DiscordActivityTimestamps { + DiscordTimestamp start; + DiscordTimestamp end; +}; + +struct DiscordActivityAssets { + char large_image[128]; + char large_text[128]; + char small_image[128]; + char small_text[128]; +}; + +struct DiscordPartySize { + int32_t current_size; + int32_t max_size; +}; + +struct DiscordActivityParty { + char id[128]; + struct DiscordPartySize size; +}; + +struct DiscordActivitySecrets { + char match[128]; + char join[128]; + char spectate[128]; +}; + +struct DiscordActivity { + enum EDiscordActivityType type; + int64_t application_id; + char name[128]; + char state[128]; + char details[128]; + struct DiscordActivityTimestamps timestamps; + struct DiscordActivityAssets assets; + struct DiscordActivityParty party; + struct DiscordActivitySecrets secrets; + bool instance; +}; + +struct DiscordPresence { + enum EDiscordStatus status; + struct DiscordActivity activity; +}; + +struct DiscordRelationship { + enum EDiscordRelationshipType type; + struct DiscordUser user; + struct DiscordPresence presence; +}; + +struct DiscordLobby { + DiscordLobbyId id; + enum EDiscordLobbyType type; + DiscordUserId owner_id; + DiscordLobbySecret secret; + uint32_t capacity; + bool locked; +}; + +struct DiscordFileStat { + char filename[260]; + uint64_t size; + uint64_t last_modified; +}; + +struct DiscordEntitlement { + DiscordSnowflake id; + enum EDiscordEntitlementType type; + DiscordSnowflake sku_id; +}; + +struct DiscordSkuPrice { + uint32_t amount; + char currency[16]; +}; + +struct DiscordSku { + DiscordSnowflake id; + enum EDiscordSkuType type; + char name[256]; + struct DiscordSkuPrice price; +}; + +struct DiscordInputMode { + enum EDiscordInputModeType type; + char shortcut[256]; +}; + +struct DiscordUserAchievement { + DiscordSnowflake user_id; + DiscordSnowflake achievement_id; + uint8_t percent_complete; + DiscordDateTime unlocked_at; +}; + +struct IDiscordLobbyTransaction { + enum EDiscordResult (*set_type)(struct IDiscordLobbyTransaction* lobby_transaction, enum EDiscordLobbyType type); + enum EDiscordResult (*set_owner)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordUserId owner_id); + enum EDiscordResult (*set_capacity)(struct IDiscordLobbyTransaction* lobby_transaction, uint32_t capacity); + enum EDiscordResult (*set_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key, DiscordMetadataValue value); + enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, DiscordMetadataKey key); + enum EDiscordResult (*set_locked)(struct IDiscordLobbyTransaction* lobby_transaction, bool locked); +}; + +struct IDiscordLobbyMemberTransaction { + enum EDiscordResult (*set_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key, DiscordMetadataValue value); + enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyMemberTransaction* lobby_member_transaction, DiscordMetadataKey key); +}; + +struct IDiscordLobbySearchQuery { + enum EDiscordResult (*filter)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchComparison comparison, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value); + enum EDiscordResult (*sort)(struct IDiscordLobbySearchQuery* lobby_search_query, DiscordMetadataKey key, enum EDiscordLobbySearchCast cast, DiscordMetadataValue value); + enum EDiscordResult (*limit)(struct IDiscordLobbySearchQuery* lobby_search_query, uint32_t limit); + enum EDiscordResult (*distance)(struct IDiscordLobbySearchQuery* lobby_search_query, enum EDiscordLobbySearchDistance distance); +}; + +typedef void* IDiscordApplicationEvents; + +struct IDiscordApplicationManager { + void (*validate_or_exit)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*get_current_locale)(struct IDiscordApplicationManager* manager, DiscordLocale* locale); + void (*get_current_branch)(struct IDiscordApplicationManager* manager, DiscordBranch* branch); + void (*get_oauth2_token)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordOAuth2Token* oauth2_token)); + void (*get_ticket)(struct IDiscordApplicationManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, const char* data)); +}; + +struct IDiscordUserEvents { + void (*on_current_user_update)(void* event_data); +}; + +struct IDiscordUserManager { + enum EDiscordResult (*get_current_user)(struct IDiscordUserManager* manager, struct DiscordUser* current_user); + void (*get_user)(struct IDiscordUserManager* manager, DiscordUserId user_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordUser* user)); + enum EDiscordResult (*get_current_user_premium_type)(struct IDiscordUserManager* manager, enum EDiscordPremiumType* premium_type); + enum EDiscordResult (*current_user_has_flag)(struct IDiscordUserManager* manager, enum EDiscordUserFlag flag, bool* has_flag); +}; + +typedef void* IDiscordImageEvents; + +struct IDiscordImageManager { + void (*fetch)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, bool refresh, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordImageHandle handle_result)); + enum EDiscordResult (*get_dimensions)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, struct DiscordImageDimensions* dimensions); + enum EDiscordResult (*get_data)(struct IDiscordImageManager* manager, struct DiscordImageHandle handle, uint8_t* data, uint32_t data_length); +}; + +struct IDiscordActivityEvents { + void (*on_activity_join)(void* event_data, const char* secret); + void (*on_activity_spectate)(void* event_data, const char* secret); + void (*on_activity_join_request)(void* event_data, struct DiscordUser* user); + void (*on_activity_invite)(void* event_data, enum EDiscordActivityActionType type, struct DiscordUser* user, struct DiscordActivity* activity); +}; + +struct IDiscordActivityManager { + enum EDiscordResult (*register_command)(struct IDiscordActivityManager* manager, const char* command); + enum EDiscordResult (*register_steam)(struct IDiscordActivityManager* manager, uint32_t steam_id); + void (*update_activity)(struct IDiscordActivityManager* manager, struct DiscordActivity* activity, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*clear_activity)(struct IDiscordActivityManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*send_request_reply)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityJoinRequestReply reply, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*send_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, enum EDiscordActivityActionType type, const char* content, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*accept_invite)(struct IDiscordActivityManager* manager, DiscordUserId user_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); +}; + +struct IDiscordRelationshipEvents { + void (*on_refresh)(void* event_data); + void (*on_relationship_update)(void* event_data, struct DiscordRelationship* relationship); +}; + +struct IDiscordRelationshipManager { + void (*filter)(struct IDiscordRelationshipManager* manager, void* filter_data, bool (*filter)(void* filter_data, struct DiscordRelationship* relationship)); + enum EDiscordResult (*count)(struct IDiscordRelationshipManager* manager, int32_t* count); + enum EDiscordResult (*get)(struct IDiscordRelationshipManager* manager, DiscordUserId user_id, struct DiscordRelationship* relationship); + enum EDiscordResult (*get_at)(struct IDiscordRelationshipManager* manager, uint32_t index, struct DiscordRelationship* relationship); +}; + +struct IDiscordLobbyEvents { + void (*on_lobby_update)(void* event_data, int64_t lobby_id); + void (*on_lobby_delete)(void* event_data, int64_t lobby_id, uint32_t reason); + void (*on_member_connect)(void* event_data, int64_t lobby_id, int64_t user_id); + void (*on_member_update)(void* event_data, int64_t lobby_id, int64_t user_id); + void (*on_member_disconnect)(void* event_data, int64_t lobby_id, int64_t user_id); + void (*on_lobby_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t* data, uint32_t data_length); + void (*on_speaking)(void* event_data, int64_t lobby_id, int64_t user_id, bool speaking); + void (*on_network_message)(void* event_data, int64_t lobby_id, int64_t user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length); +}; + +struct IDiscordLobbyManager { + enum EDiscordResult (*get_lobby_create_transaction)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult (*get_lobby_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult (*get_member_update_transaction)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction** transaction); + void (*create_lobby)(struct IDiscordLobbyManager* manager, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); + void (*update_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct IDiscordLobbyTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*delete_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*connect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret secret, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); + void (*connect_lobby_with_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbySecret activity_secret, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, struct DiscordLobby* lobby)); + void (*disconnect_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*get_lobby)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, struct DiscordLobby* lobby); + enum EDiscordResult (*get_lobby_activity_secret)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordLobbySecret* secret); + enum EDiscordResult (*get_lobby_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordMetadataKey key, DiscordMetadataValue* value); + enum EDiscordResult (*get_lobby_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordMetadataKey* key); + enum EDiscordResult (*lobby_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count); + enum EDiscordResult (*member_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t* count); + enum EDiscordResult (*get_member_user_id)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, int32_t index, DiscordUserId* user_id); + enum EDiscordResult (*get_member_user)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct DiscordUser* user); + enum EDiscordResult (*get_member_metadata_value)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, DiscordMetadataKey key, DiscordMetadataValue* value); + enum EDiscordResult (*get_member_metadata_key)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t index, DiscordMetadataKey* key); + enum EDiscordResult (*member_metadata_count)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, int32_t* count); + void (*update_member)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, struct IDiscordLobbyMemberTransaction* transaction, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*send_lobby_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t* data, uint32_t data_length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*get_search_query)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery** query); + void (*search)(struct IDiscordLobbyManager* manager, struct IDiscordLobbySearchQuery* query, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*lobby_count)(struct IDiscordLobbyManager* manager, int32_t* count); + enum EDiscordResult (*get_lobby_id)(struct IDiscordLobbyManager* manager, int32_t index, DiscordLobbyId* lobby_id); + void (*connect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*disconnect_voice)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*connect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id); + enum EDiscordResult (*disconnect_network)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id); + enum EDiscordResult (*flush_network)(struct IDiscordLobbyManager* manager); + enum EDiscordResult (*open_network_channel)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, uint8_t channel_id, bool reliable); + enum EDiscordResult (*send_network_message)(struct IDiscordLobbyManager* manager, DiscordLobbyId lobby_id, DiscordUserId user_id, uint8_t channel_id, uint8_t* data, uint32_t data_length); +}; + +struct IDiscordNetworkEvents { + void (*on_message)(void* event_data, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length); + void (*on_route_update)(void* event_data, const char* route_data); +}; + +struct IDiscordNetworkManager { + /** + * Get the local peer ID for this process. + */ + void (*get_peer_id)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId* peer_id); + /** + * Send pending network messages. + */ + enum EDiscordResult (*flush)(struct IDiscordNetworkManager* manager); + /** + * Open a connection to a remote peer. + */ + enum EDiscordResult (*open_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data); + /** + * Update the route data for a connected peer. + */ + enum EDiscordResult (*update_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, const char* route_data); + /** + * Close the connection to a remote peer. + */ + enum EDiscordResult (*close_peer)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id); + /** + * Open a message channel to a connected peer. + */ + enum EDiscordResult (*open_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, bool reliable); + /** + * Close a message channel to a connected peer. + */ + enum EDiscordResult (*close_channel)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id); + /** + * Send a message to a connected peer over an opened message channel. + */ + enum EDiscordResult (*send_message)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId peer_id, DiscordNetworkChannelId channel_id, uint8_t* data, uint32_t data_length); +}; + +struct IDiscordOverlayEvents { + void (*on_toggle)(void* event_data, bool locked); +}; + +struct IDiscordOverlayManager { + void (*is_enabled)(struct IDiscordOverlayManager* manager, bool* enabled); + void (*is_locked)(struct IDiscordOverlayManager* manager, bool* locked); + void (*set_locked)(struct IDiscordOverlayManager* manager, bool locked, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*open_activity_invite)(struct IDiscordOverlayManager* manager, enum EDiscordActivityActionType type, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*open_guild_invite)(struct IDiscordOverlayManager* manager, const char* code, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*open_voice_settings)(struct IDiscordOverlayManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); +}; + +typedef void* IDiscordStorageEvents; + +struct IDiscordStorageManager { + enum EDiscordResult (*read)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, uint32_t* read); + void (*read_async)(struct IDiscordStorageManager* manager, const char* name, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length)); + void (*read_async_partial)(struct IDiscordStorageManager* manager, const char* name, uint64_t offset, uint64_t length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result, uint8_t* data, uint32_t data_length)); + enum EDiscordResult (*write)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length); + void (*write_async)(struct IDiscordStorageManager* manager, const char* name, uint8_t* data, uint32_t data_length, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*delete_)(struct IDiscordStorageManager* manager, const char* name); + enum EDiscordResult (*exists)(struct IDiscordStorageManager* manager, const char* name, bool* exists); + void (*count)(struct IDiscordStorageManager* manager, int32_t* count); + enum EDiscordResult (*stat)(struct IDiscordStorageManager* manager, const char* name, struct DiscordFileStat* stat); + enum EDiscordResult (*stat_at)(struct IDiscordStorageManager* manager, int32_t index, struct DiscordFileStat* stat); + enum EDiscordResult (*get_path)(struct IDiscordStorageManager* manager, DiscordPath* path); +}; + +struct IDiscordStoreEvents { + void (*on_entitlement_create)(void* event_data, struct DiscordEntitlement* entitlement); + void (*on_entitlement_delete)(void* event_data, struct DiscordEntitlement* entitlement); +}; + +struct IDiscordStoreManager { + void (*fetch_skus)(struct IDiscordStoreManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*count_skus)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult (*get_sku)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, struct DiscordSku* sku); + enum EDiscordResult (*get_sku_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordSku* sku); + void (*fetch_entitlements)(struct IDiscordStoreManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*count_entitlements)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult (*get_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake entitlement_id, struct DiscordEntitlement* entitlement); + enum EDiscordResult (*get_entitlement_at)(struct IDiscordStoreManager* manager, int32_t index, struct DiscordEntitlement* entitlement); + enum EDiscordResult (*has_sku_entitlement)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, bool* has_entitlement); + void (*start_purchase)(struct IDiscordStoreManager* manager, DiscordSnowflake sku_id, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); +}; + +struct IDiscordVoiceEvents { + void (*on_settings_update)(void* event_data); +}; + +struct IDiscordVoiceManager { + enum EDiscordResult (*get_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode* input_mode); + void (*set_input_mode)(struct IDiscordVoiceManager* manager, struct DiscordInputMode input_mode, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*is_self_mute)(struct IDiscordVoiceManager* manager, bool* mute); + enum EDiscordResult (*set_self_mute)(struct IDiscordVoiceManager* manager, bool mute); + enum EDiscordResult (*is_self_deaf)(struct IDiscordVoiceManager* manager, bool* deaf); + enum EDiscordResult (*set_self_deaf)(struct IDiscordVoiceManager* manager, bool deaf); + enum EDiscordResult (*is_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool* mute); + enum EDiscordResult (*set_local_mute)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, bool mute); + enum EDiscordResult (*get_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t* volume); + enum EDiscordResult (*set_local_volume)(struct IDiscordVoiceManager* manager, DiscordSnowflake user_id, uint8_t volume); +}; + +struct IDiscordAchievementEvents { + void (*on_user_achievement_update)(void* event_data, struct DiscordUserAchievement* user_achievement); +}; + +struct IDiscordAchievementManager { + void (*set_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake achievement_id, uint8_t percent_complete, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*fetch_user_achievements)(struct IDiscordAchievementManager* manager, void* callback_data, void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*count_user_achievements)(struct IDiscordAchievementManager* manager, int32_t* count); + enum EDiscordResult (*get_user_achievement)(struct IDiscordAchievementManager* manager, DiscordSnowflake user_achievement_id, struct DiscordUserAchievement* user_achievement); + enum EDiscordResult (*get_user_achievement_at)(struct IDiscordAchievementManager* manager, int32_t index, struct DiscordUserAchievement* user_achievement); +}; + +typedef void* IDiscordCoreEvents; + +struct IDiscordCore { + void (*destroy)(struct IDiscordCore* core); + enum EDiscordResult (*run_callbacks)(struct IDiscordCore* core); + void (*set_log_hook)(struct IDiscordCore* core, enum EDiscordLogLevel min_level, void* hook_data, void (*hook)(void* hook_data, enum EDiscordLogLevel level, const char* message)); + struct IDiscordApplicationManager* (*get_application_manager)(struct IDiscordCore* core); + struct IDiscordUserManager* (*get_user_manager)(struct IDiscordCore* core); + struct IDiscordImageManager* (*get_image_manager)(struct IDiscordCore* core); + struct IDiscordActivityManager* (*get_activity_manager)(struct IDiscordCore* core); + struct IDiscordRelationshipManager* (*get_relationship_manager)(struct IDiscordCore* core); + struct IDiscordLobbyManager* (*get_lobby_manager)(struct IDiscordCore* core); + struct IDiscordNetworkManager* (*get_network_manager)(struct IDiscordCore* core); + struct IDiscordOverlayManager* (*get_overlay_manager)(struct IDiscordCore* core); + struct IDiscordStorageManager* (*get_storage_manager)(struct IDiscordCore* core); + struct IDiscordStoreManager* (*get_store_manager)(struct IDiscordCore* core); + struct IDiscordVoiceManager* (*get_voice_manager)(struct IDiscordCore* core); + struct IDiscordAchievementManager* (*get_achievement_manager)(struct IDiscordCore* core); +}; + +struct DiscordCreateParams { + DiscordClientId client_id; + uint64_t flags; + IDiscordCoreEvents* events; + void* event_data; + IDiscordApplicationEvents* application_events; + DiscordVersion application_version; + struct IDiscordUserEvents* user_events; + DiscordVersion user_version; + IDiscordImageEvents* image_events; + DiscordVersion image_version; + struct IDiscordActivityEvents* activity_events; + DiscordVersion activity_version; + struct IDiscordRelationshipEvents* relationship_events; + DiscordVersion relationship_version; + struct IDiscordLobbyEvents* lobby_events; + DiscordVersion lobby_version; + struct IDiscordNetworkEvents* network_events; + DiscordVersion network_version; + struct IDiscordOverlayEvents* overlay_events; + DiscordVersion overlay_version; + IDiscordStorageEvents* storage_events; + DiscordVersion storage_version; + struct IDiscordStoreEvents* store_events; + DiscordVersion store_version; + struct IDiscordVoiceEvents* voice_events; + DiscordVersion voice_version; + struct IDiscordAchievementEvents* achievement_events; + DiscordVersion achievement_version; +}; + +#ifdef __cplusplus +inline +#else +static +#endif +void DiscordCreateParamsSetDefault(struct DiscordCreateParams* params) +{ + memset(params, 0, sizeof(struct DiscordCreateParams)); + params->application_version = DISCORD_APPLICATION_MANAGER_VERSION; + params->user_version = DISCORD_USER_MANAGER_VERSION; + params->image_version = DISCORD_IMAGE_MANAGER_VERSION; + params->activity_version = DISCORD_ACTIVITY_MANAGER_VERSION; + params->relationship_version = DISCORD_RELATIONSHIP_MANAGER_VERSION; + params->lobby_version = DISCORD_LOBBY_MANAGER_VERSION; + params->network_version = DISCORD_NETWORK_MANAGER_VERSION; + params->overlay_version = DISCORD_OVERLAY_MANAGER_VERSION; + params->storage_version = DISCORD_STORAGE_MANAGER_VERSION; + params->store_version = DISCORD_STORE_MANAGER_VERSION; + params->voice_version = DISCORD_VOICE_MANAGER_VERSION; + params->achievement_version = DISCORD_ACHIEVEMENT_MANAGER_VERSION; +} + +enum EDiscordResult DiscordCreate(DiscordVersion version, struct DiscordCreateParams* params, struct IDiscordCore** result); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/win/icons/cdrom.ico b/src/win/icons/cdrom.ico index a3fb90a8b..bfb69e438 100644 Binary files a/src/win/icons/cdrom.ico and b/src/win/icons/cdrom.ico differ diff --git a/src/win/icons/cdrom_active.ico b/src/win/icons/cdrom_active.ico index 91f4f3ec7..95d39b84d 100644 Binary files a/src/win/icons/cdrom_active.ico and b/src/win/icons/cdrom_active.ico differ diff --git a/src/win/icons/cdrom_disabled.ico b/src/win/icons/cdrom_disabled.ico index 02220893c..b755e789a 100644 Binary files a/src/win/icons/cdrom_disabled.ico and b/src/win/icons/cdrom_disabled.ico differ diff --git a/src/win/icons/cdrom_empty.ico b/src/win/icons/cdrom_empty.ico index 647ebeae6..78e6d15b1 100644 Binary files a/src/win/icons/cdrom_empty.ico and b/src/win/icons/cdrom_empty.ico differ diff --git a/src/win/icons/cdrom_empty_active.ico b/src/win/icons/cdrom_empty_active.ico index f14b71145..b3b27574c 100644 Binary files a/src/win/icons/cdrom_empty_active.ico and b/src/win/icons/cdrom_empty_active.ico differ diff --git a/src/win/icons/floppy_525.ico b/src/win/icons/floppy_525.ico index 81fc78571..7ea15d84d 100644 Binary files a/src/win/icons/floppy_525.ico and b/src/win/icons/floppy_525.ico differ diff --git a/src/win/icons/floppy_525_active.ico b/src/win/icons/floppy_525_active.ico index 204053b3a..3bedb572a 100644 Binary files a/src/win/icons/floppy_525_active.ico and b/src/win/icons/floppy_525_active.ico differ diff --git a/src/win/icons/floppy_525_empty.ico b/src/win/icons/floppy_525_empty.ico index 2b20861a3..017c9dc0e 100644 Binary files a/src/win/icons/floppy_525_empty.ico and b/src/win/icons/floppy_525_empty.ico differ diff --git a/src/win/icons/floppy_525_empty_active.ico b/src/win/icons/floppy_525_empty_active.ico index 71a2ef751..2224ae502 100644 Binary files a/src/win/icons/floppy_525_empty_active.ico and b/src/win/icons/floppy_525_empty_active.ico differ diff --git a/src/win/icons/floppy_disabled.ico b/src/win/icons/floppy_disabled.ico index 7a0e1bb7c..8b20f4f51 100644 Binary files a/src/win/icons/floppy_disabled.ico and b/src/win/icons/floppy_disabled.ico differ diff --git a/src/win/icons/floppy_drives.ico b/src/win/icons/floppy_drives.ico index 4c11a9966..58c96091f 100644 Binary files a/src/win/icons/floppy_drives.ico and b/src/win/icons/floppy_drives.ico differ diff --git a/src/win/icons/hard_disk.ico b/src/win/icons/hard_disk.ico index 9b4a5fd7f..36439eb31 100644 Binary files a/src/win/icons/hard_disk.ico and b/src/win/icons/hard_disk.ico differ diff --git a/src/win/icons/hard_disk_active.ico b/src/win/icons/hard_disk_active.ico index 1adee78a9..52be00623 100644 Binary files a/src/win/icons/hard_disk_active.ico and b/src/win/icons/hard_disk_active.ico differ diff --git a/src/win/resource.h b/src/win/resource.h index cbe7a5505..8e11ed62a 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -8,14 +8,16 @@ * * Windows resource defines. * - * Version: @(#)resource.h 1.0.26 2018/07/19 + * Version: @(#)resource.h 1.0.32 2019/12/21 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, + * David HrdliÄka, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 David HrdliÄka. */ #ifndef WIN_RESOURCE_H # define WIN_RESOURCE_H @@ -52,12 +54,13 @@ #define IDT_1710 1710 /* Joystick: */ #define IDT_1711 1711 /* Sound card: */ #define IDT_1712 1712 /* MIDI Out Device: */ -#define IDT_1713 1713 /* Network type: */ -#define IDT_1714 1714 /* PCap device: */ -#define IDT_1715 1715 /* Network adapter: */ -#define IDT_1716 1716 /* SCSI Controller: */ -#define IDT_1717 1717 /* HD Controller: */ -#define IDT_1718 1718 +#define IDT_1713 1713 /* MIDI In Device: */ +#define IDT_1714 1714 /* Network type: */ +#define IDT_1715 1715 /* PCap device: */ +#define IDT_1716 1716 /* Network adapter: */ +#define IDT_1717 1717 /* SCSI Controller: */ +#define IDT_1718 1718 /* HD Controller: */ +#define IDT_1719 1719 #define IDT_1720 1720 /* Hard disks: */ #define IDT_1721 1721 /* Bus: */ #define IDT_1722 1722 /* Channel: */ @@ -90,6 +93,11 @@ #define IDT_1757 1757 /* Progress: */ #define IDT_1758 1758 /* Speed: */ #define IDT_1759 1759 /* ZIP drives: */ +#define IDT_1763 1763 /* Board #1: */ +#define IDT_1764 1764 /* Board #2: */ +#define IDT_1765 1765 /* Board #3: */ +#define IDT_1766 1766 /* Board #4: */ +#define IDT_1767 1767 /* ISA RTC: */ /* @@ -99,7 +107,10 @@ */ #define IDC_SETTINGSCATLIST 1001 /* generic config */ #define IDC_CFILE 1002 /* Select File dialog */ -#define IDC_CHECK_SYNC 1008 +#define IDC_TIME_SYNC 1005 +#define IDC_RADIO_TS_DISABLED 1006 +#define IDC_RADIO_TS_LOCAL 1007 +#define IDC_RADIO_TS_UTC 1008 /* Leave this as is until we finally get into localization in 86Box 3.00(?). */ #if 0 #define IDC_COMBO_LANG 1009 @@ -134,11 +145,12 @@ #define IDC_CHECK_SSI 1072 #define IDC_CHECK_CMS 1073 #define IDC_CHECK_GUS 1074 -#define IDC_CHECK_NUKEDOPL 1075 -#define IDC_COMBO_MIDI 1076 -#define IDC_CHECK_MPU401 1077 -#define IDC_CONFIGURE_MPU401 1078 -#define IDC_CHECK_FLOAT 1079 +#define IDC_COMBO_MIDI 1075 +#define IDC_CHECK_MPU401 1076 +#define IDC_CONFIGURE_MPU401 1077 +#define IDC_CHECK_FLOAT 1078 +#define IDC_CONFIGURE_GUS 1079 +#define IDC_COMBO_MIDI_IN 1080 #define IDC_COMBO_NET_TYPE 1090 /* network config */ #define IDC_COMBO_PCAP 1091 @@ -149,7 +161,9 @@ #define IDC_COMBO_LPT3 1112 #define IDC_CHECK_SERIAL1 1113 #define IDC_CHECK_SERIAL2 1114 -#define IDC_CHECK_PARALLEL 1115 +#define IDC_CHECK_PARALLEL1 1115 +#define IDC_CHECK_PARALLEL2 1116 +#define IDC_CHECK_PARALLEL3 1117 #define IDC_OTHER_PERIPH 1120 /* other periph config */ #define IDC_COMBO_SCSI 1121 @@ -161,69 +175,82 @@ #define IDC_CHECK_IDE_QUA 1127 #define IDC_BUTTON_IDE_QUA 1128 #define IDC_CHECK_BUGGER 1129 +#define IDC_CONFIGURE_BUGGER 1130 +#define IDC_COMBO_ISARTC 1131 +#define IDC_CONFIGURE_ISARTC 1132 +#define IDC_GROUP_ISAMEM 1140 +#define IDC_COMBO_ISAMEM_1 1141 +#define IDC_COMBO_ISAMEM_2 1142 +#define IDC_COMBO_ISAMEM_3 1143 +#define IDC_COMBO_ISAMEM_4 1144 +#define IDC_CONFIGURE_ISAMEM_1 1145 +#define IDC_CONFIGURE_ISAMEM_2 1146 +#define IDC_CONFIGURE_ISAMEM_3 1147 +#define IDC_CONFIGURE_ISAMEM_4 1148 -#define IDC_HARD_DISKS 1130 /* hard disk config */ -#define IDC_LIST_HARD_DISKS 1131 -#define IDC_BUTTON_HDD_ADD_NEW 1132 -#define IDC_BUTTON_HDD_ADD 1133 -#define IDC_BUTTON_HDD_REMOVE 1134 -#define IDC_COMBO_HD_BUS 1135 -#define IDC_COMBO_HD_CHANNEL 1136 -#define IDC_COMBO_HD_ID 1137 -#define IDC_COMBO_HD_LUN 1138 -#define IDC_COMBO_HD_CHANNEL_IDE 1139 +#define IDC_HARD_DISKS 1150 /* hard disk config */ +#define IDC_LIST_HARD_DISKS 1151 +#define IDC_BUTTON_HDD_ADD_NEW 1152 +#define IDC_BUTTON_HDD_ADD 1153 +#define IDC_BUTTON_HDD_REMOVE 1154 +#define IDC_COMBO_HD_BUS 1155 +#define IDC_COMBO_HD_CHANNEL 1156 +#define IDC_COMBO_HD_ID 1157 +#define IDC_COMBO_HD_LUN 1158 +#define IDC_COMBO_HD_CHANNEL_IDE 1159 -#define IDC_EDIT_HD_FILE_NAME 1140 /* add hard disk dialog */ -#define IDC_EDIT_HD_SPT 1141 -#define IDC_EDIT_HD_HPC 1142 -#define IDC_EDIT_HD_CYL 1143 -#define IDC_EDIT_HD_SIZE 1144 -#define IDC_COMBO_HD_TYPE 1145 -#define IDC_PBAR_IMG_CREATE 1146 +#define IDC_EDIT_HD_FILE_NAME 1160 /* add hard disk dialog */ +#define IDC_EDIT_HD_SPT 1161 +#define IDC_EDIT_HD_HPC 1162 +#define IDC_EDIT_HD_CYL 1163 +#define IDC_EDIT_HD_SIZE 1164 +#define IDC_COMBO_HD_TYPE 1165 +#define IDC_PBAR_IMG_CREATE 1166 -#define IDC_REMOV_DEVICES 1150 /* removable dev config */ -#define IDC_LIST_FLOPPY_DRIVES 1151 -#define IDC_COMBO_FD_TYPE 1152 -#define IDC_CHECKTURBO 1153 -#define IDC_CHECKBPB 1154 -#define IDC_LIST_CDROM_DRIVES 1155 -#define IDC_COMBO_CD_BUS 1156 -#define IDC_COMBO_CD_ID 1157 -#define IDC_COMBO_CD_LUN 1158 -#define IDC_COMBO_CD_CHANNEL_IDE 1159 -#define IDC_LIST_ZIP_DRIVES 1160 -#define IDC_COMBO_ZIP_BUS 1161 -#define IDC_COMBO_ZIP_ID 1162 -#define IDC_COMBO_ZIP_LUN 1163 -#define IDC_COMBO_ZIP_CHANNEL_IDE 1164 -#define IDC_CHECK250 1165 -#define IDC_COMBO_CD_SPEED 1166 +#define IDC_REMOV_DEVICES 1170 /* removable dev config */ +#define IDC_LIST_FLOPPY_DRIVES 1171 +#define IDC_COMBO_FD_TYPE 1172 +#define IDC_CHECKTURBO 1173 +#define IDC_CHECKBPB 1174 +#define IDC_LIST_CDROM_DRIVES 1175 +#define IDC_COMBO_CD_BUS 1176 +#define IDC_COMBO_CD_ID 1177 +#define IDC_COMBO_CD_LUN 1178 +#define IDC_COMBO_CD_CHANNEL_IDE 1179 +#define IDC_LIST_ZIP_DRIVES 1180 +#define IDC_COMBO_ZIP_BUS 1181 +#define IDC_COMBO_ZIP_ID 1182 +#define IDC_COMBO_ZIP_LUN 1183 +#define IDC_COMBO_ZIP_CHANNEL_IDE 1184 +#define IDC_CHECK250 1185 +#define IDC_COMBO_CD_SPEED 1186 -#define IDC_SLIDER_GAIN 1180 /* sound gain dialog */ +#define IDC_SLIDER_GAIN 1190 /* sound gain dialog */ -#define IDC_EDIT_FILE_NAME 1190 /* new floppy image dialog */ -#define IDC_COMBO_DISK_SIZE 1191 -#define IDC_COMBO_RPM_MODE 1192 +#define IDC_EDIT_FILE_NAME 1200 /* new floppy image dialog */ +#define IDC_COMBO_DISK_SIZE 1201 +#define IDC_COMBO_RPM_MODE 1202 /* For the DeviceConfig code, re-do later. */ -#define IDC_CONFIG_BASE 1200 -#define IDC_CONFIGURE_VID 1200 -#define IDC_CONFIGURE_SND 1201 -#define IDC_CONFIGURE_VOODOO 1202 -#define IDC_CONFIGURE_MOD 1203 -#define IDC_CONFIGURE_NET_TYPE 1204 -#define IDC_CONFIGURE_BUSLOGIC 1205 -#define IDC_CONFIGURE_PCAP 1206 -#define IDC_CONFIGURE_NET 1207 -#define IDC_CONFIGURE_MIDI 1208 -#define IDC_JOY1 1210 -#define IDC_JOY2 1211 -#define IDC_JOY3 1212 -#define IDC_JOY4 1213 -#define IDC_HDTYPE 1280 -#define IDC_RENDER 1281 -#define IDC_STATUS 1282 +#define IDC_CONFIG_BASE 1300 +#define IDC_CONFIGURE_VID 1300 +#define IDC_CONFIGURE_SND 1301 +#define IDC_CONFIGURE_VOODOO 1302 +#define IDC_CONFIGURE_MOD 1303 +#define IDC_CONFIGURE_NET_TYPE 1304 +#define IDC_CONFIGURE_BUSLOGIC 1305 +#define IDC_CONFIGURE_PCAP 1306 +#define IDC_CONFIGURE_NET 1307 +#define IDC_CONFIGURE_MIDI 1308 +#define IDC_CONFIGURE_MIDI_IN 1309 +#define IDC_JOY1 1310 +#define IDC_JOY2 1311 +#define IDC_JOY3 1312 +#define IDC_JOY4 1313 +#define IDC_HDTYPE 1380 +#define IDC_RENDER 1381 +#define IDC_STATUS 1382 #define IDM_ABOUT 40001 @@ -241,11 +268,18 @@ #define IDM_UPDATE_ICONS 40030 #define IDM_VID_RESIZE 40040 #define IDM_VID_REMEMBER 40041 -#define IDM_VID_DDRAW 40050 -#define IDM_VID_D2D 40051 -#define IDM_VID_D3D 40052 -#define IDM_VID_SDL 40053 -#define IDM_VID_VNC 40054 +#define IDM_VID_SDL_SW 40050 +#define IDM_VID_SDL_HW 40051 +#ifdef USE_D2D +#define IDM_VID_D2D 40052 +#ifdef USE_VNC +#define IDM_VID_VNC 40053 +#endif +#else +#ifdef USE_VNC +#define IDM_VID_VNC 40052 +#endif +#endif #define IDM_VID_SCALE_1X 40055 #define IDM_VID_SCALE_2X 40056 #define IDM_VID_SCALE_3X 40057 @@ -253,9 +287,8 @@ #define IDM_VID_FULLSCREEN 40060 #define IDM_VID_FS_FULL 40061 #define IDM_VID_FS_43 40062 -#define IDM_VID_FS_SQ 40063 +#define IDM_VID_FS_KEEPRATIO 40063 #define IDM_VID_FS_INT 40064 -#define IDM_VID_FS_KEEPRATIO 40065 #define IDM_VID_FORCE43 40066 #define IDM_VID_OVERSCAN 40067 #define IDM_VID_INVERT 40069 @@ -269,6 +302,10 @@ #define IDM_VID_GRAY_GREEN 40083 #define IDM_VID_GRAY_WHITE 40084 +#ifdef USE_DISCORD +#define IDM_DISCORD 40090 +#endif + #define IDM_LOG_BREAKPOINT 51201 #define IDM_DUMP_VRAM 51202 // should be an Action diff --git a/src/win/win.c b/src/win/win.c index 68ac81093..2f421412b 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -8,18 +8,19 @@ * * Platform main support module for Windows. * - * Version: @(#)win.c 1.0.51 2018/07/19 + * Version: @(#)win.c 1.0.60 2019/12/05 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #define UNICODE #include +#include #include #include #include @@ -32,6 +33,7 @@ #include "../86box.h" #include "../config.h" #include "../device.h" +#include "../keyboard.h" #include "../mouse.h" #include "../video/video.h" #define GLOBAL @@ -41,9 +43,7 @@ #ifdef USE_VNC # include "../vnc.h" #endif -# include "win_ddraw.h" # include "win_d2d.h" -# include "win_d3d.h" # include "win_sdl.h" #include "win.h" @@ -75,30 +75,33 @@ static rc_str_t *lpRCstr2048, static int vid_api_inited = 0; -static struct { - char *name; +static const struct { + const char *name; int local; int (*init)(void *); void (*close)(void); void (*resize)(int x, int y); int (*pause)(void); + void (*enable)(int enable); } vid_apis[2][RENDERERS_NUM] = { { - { "DDraw", 1, (int(*)(void*))ddraw_init, ddraw_close, NULL, ddraw_pause }, - { "D2D", 1, (int(*)(void*))d2d_init, d2d_close, NULL, d2d_pause }, - { "D3D", 1, (int(*)(void*))d3d_init, d3d_close, d3d_resize, d3d_pause }, - { "SDL", 1, (int(*)(void*))sdl_init, sdl_close, NULL, sdl_pause } + { "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable }, + { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable } +#ifdef USE_D2D + ,{ "D2D", 1, (int(*)(void*))d2d_init, d2d_close, NULL, d2d_pause, d2d_enable } +#endif #ifdef USE_VNC - ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause } + ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL } #endif }, { - { "DDraw", 1, (int(*)(void*))ddraw_init_fs, ddraw_close, NULL, ddraw_pause }, - { "D2D", 1, (int(*)(void*))d2d_init_fs, d2d_close, NULL, d2d_pause }, - { "D3D", 1, (int(*)(void*))d3d_init_fs, d3d_close, NULL, d3d_pause }, - { "SDL", 1, (int(*)(void*))sdl_init_fs, sdl_close, sdl_resize, sdl_pause } + { "SDL_Software", 1, (int(*)(void*))sdl_inits_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable }, + { "SDL_Hardware", 1, (int(*)(void*))sdl_inith_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable } +#ifdef USE_D2D + ,{ "D2D", 1, (int(*)(void*))d2d_init_fs, d2d_close, NULL, d2d_pause, d2d_enable } +#endif #ifdef USE_VNC - ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause } + ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL } #endif }, }; @@ -106,13 +109,11 @@ static struct { #ifdef ENABLE_WIN_LOG int win_do_log = ENABLE_WIN_LOG; -#endif static void win_log(const char *fmt, ...) { -#ifdef ENABLE_WIN_LOG va_list ap; if (win_do_log) { @@ -120,8 +121,10 @@ win_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define win_log(fmt, ...) +#endif static void @@ -190,11 +193,6 @@ set_language(int id) /* Load the strings table for this ID. */ LoadCommonStrings(); - -#if 0 - /* Update the menus for this ID. */ - MenuUpdate(); -#endif } } @@ -343,6 +341,9 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) { wchar_t **argw = NULL; int argc, i; + wchar_t * AppID = L"86Box.86Box\0"; + + SetCurrentProcessExplicitAppUserModelID(AppID); /* Set this to the default value (windowed mode). */ video_fullscreen = 0; @@ -371,6 +372,10 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) if (! pc_init(argc, argw)) { /* Detach from console. */ CreateConsole(0); + + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_HAS_SHUTDOWN, (WPARAM) 0, (LPARAM) hwndMain); + return(1); } @@ -418,6 +423,9 @@ do_stop(void) plat_delay_ms(100); + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_HAS_SHUTDOWN, (WPARAM) 0, (LPARAM) hwndMain); + pc_close(thMain); thMain = NULL; @@ -431,6 +439,27 @@ plat_get_exe_name(wchar_t *s, int size) } +void +plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix) +{ + SYSTEMTIME SystemTime; + char temp[1024]; + + if (prefix != NULL) + sprintf(temp, "%ls-", prefix); + else + strcpy(temp, ""); + + GetSystemTime(&SystemTime); + sprintf(&temp[strlen(temp)], "%d%02d%02d-%02d%02d%02d-%03d%ls", + SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, + SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, + SystemTime.wMilliseconds, + suffix); + mbstowcs(bufp, temp, strlen(temp)+1); +} + + int plat_getcwd(wchar_t *bufp, int max) { @@ -454,6 +483,14 @@ plat_fopen(wchar_t *path, wchar_t *mode) } +/* Open a file, using Unicode pathname, with 64bit pointers. */ +FILE * +plat_fopen64(const wchar_t *path, const wchar_t *mode) +{ + return(_wfopen(path, mode)); +} + + void plat_remove(wchar_t *path) { @@ -483,6 +520,46 @@ plat_path_abs(wchar_t *path) } +/* Return the last element of a pathname. */ +wchar_t * +plat_get_basename(const wchar_t *path) +{ + int c = (int)wcslen(path); + + while (c > 0) { + if (path[c] == L'/' || path[c] == L'\\') + return((wchar_t *)&path[c]); + c--; + } + + return((wchar_t *)path); +} + + +/* Return the 'directory' element of a pathname. */ +void +plat_get_dirname(wchar_t *dest, const wchar_t *path) +{ + int c = (int)wcslen(path); + wchar_t *ptr; + + ptr = (wchar_t *)path; + + while (c > 0) { + if (path[c] == L'/' || path[c] == L'\\') { + ptr = (wchar_t *)&path[c]; + break; + } + c--; + } + + /* Copy to destination. */ + while (path < ptr) + *dest++ = *path++; + *dest = L'\0'; +} + + wchar_t * plat_get_filename(wchar_t *s) { @@ -520,6 +597,7 @@ void plat_append_filename(wchar_t *dest, wchar_t *s1, wchar_t *s2) { wcscat(dest, s1); + plat_path_slash(dest); wcscat(dest, s2); } @@ -547,7 +625,7 @@ plat_dir_check(wchar_t *path) int plat_dir_create(wchar_t *path) { - return((int)CreateDirectory(path, NULL)); + return((int)SHCreateDirectory(hwndMain, path)); } @@ -582,7 +660,11 @@ plat_vidapi(char *name) { int i; - if (!strcasecmp(name, "default") || !strcasecmp(name, "system")) return(0); + /* Default/System is SDL Hardware. */ + if (!strcasecmp(name, "default") || !strcasecmp(name, "system")) return(1); + + /* If DirectDraw or plain SDL was specified, return SDL Software. */ + if (!strcasecmp(name, "ddraw") || !strcasecmp(name, "sdl")) return(1); for (i = 0; i < RENDERERS_NUM; i++) { if (vid_apis[0][i].name && @@ -590,7 +672,7 @@ plat_vidapi(char *name) } /* Default value. */ - return(0); + return(1); } @@ -602,30 +684,29 @@ plat_vidapi_name(int api) switch(api) { case 0: -#if 0 - /* DirectDraw is default. */ - name = "ddraw"; -#endif + name = "sdl_software"; + break; + case 1: break; - case 1: +#ifdef USE_D2D + case 2: name = "d2d"; break; - - case 2: - name = "d3d"; - break; - - case 3: - name = "sdl"; - break; +#endif #ifdef USE_VNC - case 4: +#ifdef USE_D2D + case 3: +#else + case 2: +#endif name = "vnc"; break; - #endif + default: + fatal("Unknown renderer: %i\n", api); + break; } return(name); @@ -676,6 +757,17 @@ plat_vidsize(int x, int y) } +void +plat_vidapi_enable(int enable) +{ + if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].enable) return; + + startblit(); + video_wait_for_blit(); + vid_apis[video_fullscreen][vid_api].enable(enable); + endblit(); +} + int get_vidpause(void) { @@ -703,6 +795,8 @@ plat_setfullscreen(int on) startblit(); video_wait_for_blit(); + plat_vidapi_enable(0); + win_mouse_close(); /* Close the current mode, and open the new one. */ @@ -713,10 +807,15 @@ plat_setfullscreen(int on) win_mouse_init(); + plat_vidapi_enable(1); + /* Release video and make it redraw the screen. */ endblit(); device_force_redraw(); + /* Send a CTRL break code so CTRL does not get stuck. */ + keyboard_input(0, 0x01D); + /* Finally, handle the host's mouse cursor. */ /* win_log("%s full screen, %s cursor\n", on ? "enter" : "leave", on ? "hide" : "show"); */ show_cursor(video_fullscreen ? 0 : -1); @@ -726,52 +825,10 @@ plat_setfullscreen(int on) void take_screenshot(void) { - wchar_t path[1024], fn[128]; - struct tm *info; - time_t now; - - win_log("Screenshot: video API is: %i\n", vid_api); - if ((vid_api < 0) || (vid_api > 2)) return; - - memset(fn, 0, sizeof(fn)); - memset(path, 0, sizeof(path)); - - (void)time(&now); - info = localtime(&now); - - plat_append_filename(path, usr_path, SCREENSHOT_PATH); - - if (! plat_dir_check(path)) - plat_dir_create(path); - - wcscat(path, L"\\"); - - wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); - wcscat(path, fn); - - switch(vid_api) { - case 0: /* ddraw */ - ddraw_take_screenshot(path); - break; - - case 1: /* d2d */ - d2d_take_screenshot(path); - break; - - case 2: /* d3d9 */ - d3d_take_screenshot(path); - break; - - case 3: /* sdl */ - sdl_take_screenshot(path); - break; - -#ifdef USE_VNC - case 4: /* vnc */ - vnc_take_screenshot(path); - break; -#endif - } + startblit(); + screenshots++; + endblit(); + device_force_redraw(); } diff --git a/src/win/win.h b/src/win/win.h index 098cda60a..c3717e72b 100644 --- a/src/win/win.h +++ b/src/win/win.h @@ -8,15 +8,15 @@ * * Platform support defintions for Win32. * - * Version: @(#)win.h 1.0.19 2018/07/19 + * Version: @(#)win.h 1.0.29 2019/12/05 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef PLAT_WIN_H # define PLAT_WIN_H @@ -43,18 +43,39 @@ #define SB_MENU_NAME L"StatusBarMenu" #define FS_CLASS_NAME L"86BoxFullScreen" -/* Application-specific window messages. */ -#define WM_RESETD3D WM_USER -#define WM_LEAVEFULLSCREEN WM_USER+1 +/* Application-specific window messages. + + A dialog sends 0x8895 with WPARAM = 1 followed by 0x8896 with WPARAM = 1 on open, + and 0x8895 with WPARAM = followed by 0x8896 with WPARAM = 0. + + All shutdowns will send an 0x8897. */ +#define WM_LEAVEFULLSCREEN WM_USER #define WM_SAVESETTINGS 0x8888 #define WM_SHOWSETTINGS 0x8889 #define WM_PAUSE 0x8890 #define WM_SENDHWND 0x8891 +#define WM_HARDRESET 0x8892 +#define WM_SHUTDOWN 0x8893 +#define WM_CTRLALTDEL 0x8894 +/* Pause/resume status: WPARAM = 1 for paused, 0 for resumed. */ +#define WM_SENDSTATUS 0x8895 +/* Dialog (Settings or message box) status: WPARAM = 1 for open, 0 for closed. */ +#define WM_SENDDLGSTATUS 0x8896 +/* The emulator has shut down. */ +#define WM_HAS_SHUTDOWN 0x8897 #ifdef USE_VNC -#define RENDERERS_NUM 5 -#else +#ifdef USE_D2D #define RENDERERS_NUM 4 +#else +#define RENDERERS_NUM 3 +#endif +#else +#ifdef USE_D2D +#define RENDERERS_NUM 3 +#else +#define RENDERERS_NUM 2 +#endif #endif @@ -97,6 +118,12 @@ extern void keyboard_handle(LPARAM lParam, int infocus); extern void win_mouse_init(void); extern void win_mouse_close(void); +#ifndef USE_DINPUT +extern void win_mouse_handle(LPARAM lParam, int infocus); +#endif + +extern void win_notify_dlg_open(void); +extern void win_notify_dlg_closed(void); extern LPARAM win_get_string(int id); @@ -104,14 +131,13 @@ extern intptr_t fdd_type_to_icon(int type); #ifdef EMU_DEVICE_H extern uint8_t deviceconfig_open(HWND hwnd, const device_t *device); +extern uint8_t deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst); #endif extern uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type); extern int getfile(HWND hwnd, char *f, char *fn); extern int getsfile(HWND hwnd, char *f, char *fn); -extern void win_settings_open(HWND hwnd); - extern void hard_disk_add_open(HWND hwnd, int is_existing); extern int hard_disk_was_added(void); @@ -133,6 +159,22 @@ extern void SoundGainDialogCreate(HWND hwnd); extern void NewFloppyDialogCreate(HWND hwnd, int id, int part); +/* Functions in win_settings.c: */ +#define SETTINGS_PAGE_MACHINE 0 +#define SETTINGS_PAGE_VIDEO 1 +#define SETTINGS_PAGE_INPUT 2 +#define SETTINGS_PAGE_SOUND 3 +#define SETTINGS_PAGE_NETWORK 4 +#define SETTINGS_PAGE_PORTS 5 +#define SETTINGS_PAGE_PERIPHERALS 6 +#define SETTINGS_PAGE_HARD_DISKS 7 +#define SETTINGS_PAGE_FLOPPY_DRIVES 8 +#define SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES 9 + +extern void win_settings_open(HWND hwnd); +extern void win_settings_open_ex(HWND hwnd, int category); + + /* Functions in win_stbar.c: */ extern HWND hwndSBAR; extern void StatusBarCreate(HWND hwndParent, uintptr_t idStatus, HINSTANCE hInst); diff --git a/src/win/win_about.c b/src/win/win_about.c index 355dd313d..ae0eea162 100644 --- a/src/win/win_about.c +++ b/src/win/win_about.c @@ -31,7 +31,7 @@ #include "win.h" -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK diff --git a/src/win/win_cdrom.c b/src/win/win_cdrom.c index 012772655..b027f463f 100644 --- a/src/win/win_cdrom.c +++ b/src/win/win_cdrom.c @@ -8,7 +8,7 @@ * * Handle the platform-side of CDROM drives. * - * Version: @(#)win_cdrom.c 1.0.8 2018/06/02 + * Version: @(#)win_cdrom.c 1.0.12 2018/10/26 * * Authors: Sarah Walker, * Miran Grca, @@ -29,11 +29,9 @@ #include #include "../config.h" #include "../disk/hdd.h" -#include "../scsi/scsi.h" +#include "../scsi/scsi_device.h" #include "../cdrom/cdrom.h" #include "../disk/zip.h" -#include "../cdrom/cdrom_image.h" -#include "../cdrom/cdrom_null.h" #include "../scsi/scsi_disk.h" #include "../plat.h" #include "../ui.h" @@ -41,90 +39,34 @@ void -cdrom_eject(uint8_t id) +plat_cdrom_ui_update(uint8_t id, uint8_t reload) { - if (cdrom_drives[id].host_drive == 0) { - /* Switch from empty to empty. Do nothing. */ - return; + cdrom_t *drv = &cdrom[id]; + + if (drv->host_drive == 0) { + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); + ui_sb_update_icon_state(SB_CDROM|id, 1); + } else { + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_UNCHECKED); + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_CHECKED); + ui_sb_update_icon_state(SB_CDROM|id, 0); } - if (cdrom_image[id].prev_image_path) { - free(cdrom_image[id].prev_image_path); - cdrom_image[id].prev_image_path = NULL; - } - - if (cdrom_drives[id].host_drive == 200) { - cdrom_image[id].prev_image_path = (wchar_t *) malloc(1024); - wcscpy(cdrom_image[id].prev_image_path, cdrom_image[id].image_path); - } - cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; - cdrom[id]->handler->exit(id); - cdrom_close_handler(id); - memset(cdrom_image[id].image_path, 0, 2048); - cdrom_null_open(id); - if (cdrom_drives[id].bus_type) { - /* Signal disc change to the emulated machine. */ - cdrom_insert(cdrom[id]); - } - - ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); - cdrom_drives[id].host_drive=0; - ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); - ui_sb_update_icon_state(SB_CDROM|id, 1); - ui_sb_enable_menu_item(SB_CDROM|id, IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); + ui_sb_enable_menu_item(SB_CDROM|id, IDM_CDROM_RELOAD | id, MF_BYCOMMAND | (reload ? MF_GRAYED : MF_ENABLED)); ui_sb_update_tip(SB_CDROM|id); - - config_save(); -} - - -void -cdrom_reload(uint8_t id) -{ - if ((cdrom_drives[id].host_drive == cdrom_drives[id].prev_host_drive) || (cdrom_drives[id].prev_host_drive == 0) || (cdrom_drives[id].host_drive != 0)) { - /* Switch from empty to empty. Do nothing. */ - return; - } - - cdrom_close_handler(id); - memset(cdrom_image[id].image_path, 0, 2048); - - if (cdrom_drives[id].prev_host_drive == 200) { - wcscpy(cdrom_image[id].image_path, cdrom_image[id].prev_image_path); - free(cdrom_image[id].prev_image_path); - cdrom_image[id].prev_image_path = NULL; - image_open(id, cdrom_image[id].image_path); - if (cdrom_drives[id].bus_type) { - /* Signal disc change to the emulated machine. */ - cdrom_insert(cdrom[id]); - } - if (wcslen(cdrom_image[id].image_path) == 0) { - ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); - cdrom_drives[id].host_drive = 0; - ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); - ui_sb_update_icon_state(SB_CDROM|id, 1); - } else { - ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_UNCHECKED); - cdrom_drives[id].host_drive = 200; - ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_CHECKED); - ui_sb_update_icon_state(SB_CDROM|id, 0); - } - } - - ui_sb_enable_menu_item(SB_CDROM|id, IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); - ui_sb_update_tip(SB_CDROM|id); - - config_save(); } void zip_eject(uint8_t id) { - zip_disk_close(zip[id]); + zip_t *dev = (zip_t *) zip_drives[id].priv; + + zip_disk_close(dev); if (zip_drives[id].bus_type) { /* Signal disk change to the emulated machine. */ - zip_insert(zip[id]); + zip_insert(dev); } ui_sb_update_icon_state(SB_ZIP | id, 1); @@ -138,7 +80,9 @@ zip_eject(uint8_t id) void zip_reload(uint8_t id) { - zip_disk_reload(zip[id]); + zip_t *dev = (zip_t *) zip_drives[id].priv; + + zip_disk_reload(dev); if (wcslen(zip_drives[id].image_path) == 0) { ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_EJECT | id, MF_BYCOMMAND | MF_GRAYED); ui_sb_update_icon_state(SB_ZIP|id, 1); diff --git a/src/win/win_d2d.c b/src/win/win_d2d.c new file mode 100644 index 000000000..038ef739c --- /dev/null +++ b/src/win/win_d2d.c @@ -0,0 +1,470 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Rendering module for Microsoft Direct2D. + * + * Version: @(#)win_d2d.c 1.0.7 2019/12/13 + * + * Authors: David HrdliÄka, + * + * Copyright 2018,2019 David HrdliÄka. + */ +#include +#include +#include +#include +#include +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#include +#undef BITMAP + +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../video/video.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../ui.h" +#include "win.h" +#include "win_d2d.h" + + +static HWND d2d_hwnd, old_hwndMain; +static ID2D1Factory *d2d_factory; +static ID2D1HwndRenderTarget *d2d_target; +static ID2D1Bitmap *d2d_buffer; +static int d2d_width, d2d_height, d2d_screen_width, + d2d_screen_height, d2d_fs; +static volatile int d2d_enabled = 0; + + +/* Pointers to the real functions. */ +static HRESULT WINAPI (*D2D1_CreateFactory)( + D2D1_FACTORY_TYPE facType, + REFIID riid, + const D2D1_FACTORY_OPTIONS *pFacOptions, + void **ppIFactory); + +static dllimp_t d2d_imports[] = { + { "D2D1CreateFactory", &D2D1_CreateFactory }, + { NULL, NULL } +}; + + +static volatile void *d2d_handle; /* handle to Direct2D DLL */ + + +#ifdef ENABLE_D2D_LOG +int d2d_do_log = ENABLE_D2D_LOG; + + +static void +d2d_log(const char *fmt, ...) +{ + va_list ap; + + if (d2d_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define d2d_log(fmt, ...) +#endif + + +static void +d2d_stretch(float *w, float *h, float *x, float *y) +{ + double dw, dh, dx, dy, temp, temp2, ratio_w, ratio_h, gsr, hsr; + + switch (video_fullscreen_scale) + { + case FULLSCR_SCALE_FULL: + *w = d2d_screen_width; + *h = d2d_screen_height; + *x = 0; + *y = 0; + break; + + case FULLSCR_SCALE_43: + case FULLSCR_SCALE_KEEPRATIO: + dw = (double) d2d_screen_width; + dh = (double) d2d_screen_height; + hsr = dw / dh; + if (video_fullscreen_scale == FULLSCR_SCALE_43) + gsr = 4.0 / 3.0; + else + gsr = ((double) *w) / ((double) *h); + if (gsr <= hsr) + { + temp = dh * gsr; + dx = (dw - temp) / 2.0; + dw = temp; + *w = (float) dw; + *h = (float) dh; + *x = (float) dx; + *y = 0; + } + else + { + temp = dw / gsr; + dy = (dh - temp) / 2.0; + dh = temp; + *w = (float) dw; + *h = (float) dh; + *x = 0; + *y = (float) dy; + } + break; + + case FULLSCR_SCALE_INT: + dw = (double) d2d_screen_width; + dh = (double) d2d_screen_height; + temp = ((double) *w); + temp2 = ((double) *h); + ratio_w = dw / ((double) *w); + ratio_h = dh / ((double) *h); + if (ratio_h < ratio_w) + { + ratio_w = ratio_h; + } + dx = (dw / 2.0) - ((temp * ratio_w) / 2.0); + dy = (dh / 2.0) - ((temp2 * ratio_h) / 2.0); + dw -= (dx * 2.0); + dh -= (dy * 2.0); + *w = (float) dw; + *h = (float) dh; + *x = (float) dx; + *y = (float) dy; + break; + } +} + + +static void +d2d_blit(int x, int y, int y1, int y2, int w, int h) +{ + HRESULT hr = S_OK; + + d2d_log("Direct2D: d2d_blit(x=%d, y=%d, y1=%d, y2=%d, w=%d, h=%d)\n", + x, y, y1, y2, w, h); + + if (!d2d_enabled) { + video_blit_complete(); + return; + } + + if ((w != d2d_width || h != d2d_height) && !d2d_fs) + { + D2D1_SIZE_U size = { .width = w, .height = h }; + hr = ID2D1HwndRenderTarget_Resize(d2d_target, &size); + + if (SUCCEEDED(hr)) + { + d2d_width = w; + d2d_height = h; + } + } + + if (y1 == y2) { + video_blit_complete(); + return; + } + + if (render_buffer == NULL) { + video_blit_complete(); + return; + } + + /* Create a bitmap to store intermediate data */ + if (d2d_buffer == NULL) { + if (SUCCEEDED(hr)) { + D2D1_SIZE_U size = { + .width = render_buffer->w, + .height = render_buffer->h }; + + D2D1_BITMAP_PROPERTIES bitmap_props = { + .pixelFormat = { + .format = DXGI_FORMAT_B8G8R8A8_UNORM, + .alphaMode = D2D1_ALPHA_MODE_IGNORE + }, + .dpiX = 96.0f, + .dpiY = 96.0f + }; + + hr = ID2D1HwndRenderTarget_CreateBitmap( + d2d_target, + size, + NULL, + 0, + &bitmap_props, + &d2d_buffer); + } + } + + /* Copy data from render_buffer */ + if (SUCCEEDED(hr)) { + D2D1_RECT_U rectU = { + .left = x, + .top = y + y1, + .right = x + w, + .bottom = y + y2 + }; + + hr = ID2D1Bitmap_CopyFromMemory( + d2d_buffer, + &rectU, + &(render_buffer->line[y + y1][x]), + render_buffer->w << 2); + } + + video_blit_complete(); + + /* Draw! */ + if (SUCCEEDED(hr)) { + D2D1_RECT_F destRect; + ID2D1HwndRenderTarget_BeginDraw(d2d_target); + + if (d2d_fs) { + float fs_x = 0, fs_y = 0, fs_w = 0, fs_h = 0; + + D2D1_COLOR_F black = { + .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 }; + + ID2D1HwndRenderTarget_Clear( + d2d_target, + &black + ); + + d2d_stretch(&fs_w, &fs_h, &fs_x, &fs_y); + + destRect = (D2D1_RECT_F) { + .left = fs_x, + .top = fs_y, + .right = fs_x + fs_w, + .bottom = fs_y + fs_h + }; + } else { + destRect = (D2D1_RECT_F) { + .left = 0, + .top = 0, + .right = w, + .bottom = h + }; + } + + D2D1_RECT_F srcRect = { + .left = x, + .top = y, + .right = x + w, + .bottom = y + h + }; + + ID2D1HwndRenderTarget_DrawBitmap( + d2d_target, + d2d_buffer, + &destRect, + 1.0f, + D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, + &srcRect); + + hr = ID2D1HwndRenderTarget_EndDraw(d2d_target, NULL, NULL); + } + + if (FAILED(hr)) + { + d2d_log("Direct2D: d2d_blit: error 0x%08lx\n", hr); + } +} + + +void +d2d_close(void) +{ + d2d_log("Direct2D: d2d_close()\n"); + + /* Unregister our renderer! */ + video_setblit(NULL); + + if (d2d_enabled) + d2d_enabled = 0; + + if (d2d_buffer) + { + ID2D1Bitmap_Release(d2d_buffer); + d2d_buffer = NULL; + } + + if (d2d_target) + { + ID2D1HwndRenderTarget_Release(d2d_target); + d2d_target = NULL; + } + + if (d2d_factory) + { + ID2D1Factory_Release(d2d_factory); + d2d_factory = NULL; + } + + if (d2d_hwnd) + { + hwndMain = old_hwndMain; + plat_set_input(hwndMain); + DestroyWindow(d2d_hwnd); + d2d_hwnd = NULL; + old_hwndMain = NULL; + } + + /* Unload the DLL if possible. */ + if (d2d_handle != NULL) { + dynld_close((void *)d2d_handle); + d2d_handle = NULL; + } +} + + +static int +d2d_init_common(int fs) +{ + HRESULT hr = S_OK; + WCHAR title[200]; + + d2d_log("Direct2D: d2d_init_common(fs=%d)\n", fs); + + d2d_handle = dynld_module("d2d1.dll", d2d_imports); + + if (fs) + { + d2d_screen_width = GetSystemMetrics(SM_CXSCREEN); + d2d_screen_height = GetSystemMetrics(SM_CYSCREEN); + + // Direct2D seems to lack any proper fullscreen mode, + // therefore we just create a full screen window + // and pass its handle to a HwndRenderTarget + + mbstowcs(title, emu_version, sizeof_w(title)); + + d2d_hwnd = CreateWindow( + SUB_CLASS_NAME, + title, + WS_POPUP, + 0, 0, d2d_screen_width, d2d_screen_height, + HWND_DESKTOP, + NULL, + hinstance, + NULL); + + old_hwndMain = hwndMain; + hwndMain = d2d_hwnd; + + plat_set_input(d2d_hwnd); + + SetFocus(d2d_hwnd); + SetWindowPos( + d2d_hwnd, HWND_TOPMOST, + 0, 0, d2d_screen_width, d2d_screen_height, + SWP_SHOWWINDOW); + } + + hr = D2D1_CreateFactory( + D2D1_FACTORY_TYPE_MULTI_THREADED, + &IID_ID2D1Factory, NULL, (void **) &d2d_factory); + + if (SUCCEEDED(hr)) + { + D2D1_HWND_RENDER_TARGET_PROPERTIES hwnd_props; + + if (fs) + { + hwnd_props = (D2D1_HWND_RENDER_TARGET_PROPERTIES) { + .hwnd = d2d_hwnd, + .pixelSize = { + .width = d2d_screen_width, + .height = d2d_screen_height + } + }; + } + else + { + // HwndRenderTarget will get resized appropriately by d2d_blit, + // so it's fine to let D2D imply size of 0x0 for now + hwnd_props = (D2D1_HWND_RENDER_TARGET_PROPERTIES) { + .hwnd = hwndRender + }; + } + + D2D1_RENDER_TARGET_PROPERTIES target_props = { 0 }; + + hr = ID2D1Factory_CreateHwndRenderTarget( + d2d_factory, &target_props, &hwnd_props, &d2d_target); + } + + if (SUCCEEDED(hr)) + { + d2d_fs = fs; + + d2d_width = 0; + d2d_height = 0; + + // Make sure we get a clean exit. + atexit(d2d_close); + + // Register our renderer! + video_setblit(d2d_blit); + } + + if (FAILED(hr)) + { + d2d_log("Direct2D: d2d_init_common: error 0x%08lx\n", hr); + d2d_close(); + return(0); + } + + d2d_enabled = 1; + + return(1); +} + + +int +d2d_init(HWND h) +{ + d2d_log("Direct2D: d2d_init(h=0x%08lx)\n", h); + return d2d_init_common(0); +} + + +int +d2d_init_fs(HWND h) +{ + d2d_log("Direct2D: d2d_init_fs(h=0x%08lx)\n", h); + return d2d_init_common(1); +} + + +int +d2d_pause(void) +{ + // Not implemented in any renderer. The heck is this even for? + + d2d_log("Direct2D: d2d_pause()\n"); + return(0); +} + + +void +d2d_enable(int enable) +{ + d2d_enabled = enable; +} diff --git a/src/win/win_d2d.cpp b/src/win/win_d2d.cpp deleted file mode 100644 index 548a34f64..000000000 --- a/src/win/win_d2d.cpp +++ /dev/null @@ -1,490 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Rendering module for Microsoft Direct2D. - * - * Version: @(#)win_d2d.cpp 1.0.0 2018/07/19 - * - * Authors: David HrdliÄka, - * - * Copyright 2018 David HrdliÄka. - */ -#include -#include -#include -#include -#define UNICODE -#define BITMAP WINDOWS_BITMAP -#include -#include -#include -#undef BITMAP - -#define PNG_DEBUG 0 -#include - -#define HAVE_STDARG_H -#include "../86box.h" -#include "../device.h" -#include "../video/video.h" -#include "../plat.h" -#include "../ui.h" -#include "win.h" -#include "win_d2d.h" - - -static HWND d2d_hwnd, old_hwndMain; -static ID2D1Factory *d2d_factory; -static ID2D1HwndRenderTarget *d2d_hwndRT; -static ID2D1BitmapRenderTarget *d2d_btmpRT; -static ID2D1Bitmap *d2d_bitmap; -static int d2d_width, d2d_height, d2d_screen_width, d2d_screen_height, d2d_fs; - - -#ifdef ENABLE_D2D_LOG -int d2d_do_log = ENABLE_D2D_LOG; -#endif - - -static void -d2d_log(const char *fmt, ...) -{ -#ifdef ENABLE_D2D_LOG - va_list ap; - - if (d2d_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - -static void -d2d_stretch(float *w, float *h, float *x, float *y) -{ - double dw, dh, dx, dy, temp, temp2, ratio_w, ratio_h, gsr, hsr; - - switch (video_fullscreen_scale) - { - case FULLSCR_SCALE_FULL: - *w = d2d_screen_width; - *h = d2d_screen_height; - *x = 0; - *y = 0; - break; - - case FULLSCR_SCALE_43: - dw = (double) d2d_screen_width; - dh = (double) d2d_screen_height; - temp = (dh / 3.0) * 4.0; - dx = (dw - temp) / 2.0; - dw = temp; - *w = (float) dw; - *h = (float) dh; - *x = (float) dx; - *y = 0; - break; - - case FULLSCR_SCALE_SQ: - dw = (double) d2d_screen_width; - dh = (double) d2d_screen_height; - temp = ((double) *w); - temp2 = ((double) *h); - dx = (dw / 2.0) - ((dh * temp) / (temp2 * 2.0)); - dy = 0.0; - if (dx < 0.0) - { - dx = 0.0; - dy = (dw / 2.0) - ((dh * temp2) / (temp * 2.0)); - } - dw -= (dx * 2.0); - dh -= (dy * 2.0); - *w = (float) dw; - *h = (float) dh; - *x = (float) dx; - *y = (float) dy; - break; - - case FULLSCR_SCALE_INT: - dw = (double) d2d_screen_width; - dh = (double) d2d_screen_height; - temp = ((double) *w); - temp2 = ((double) *h); - ratio_w = dw / ((double) *w); - ratio_h = dh / ((double) *h); - if (ratio_h < ratio_w) - { - ratio_w = ratio_h; - } - dx = (dw / 2.0) - ((temp * ratio_w) / 2.0); - dy = (dh / 2.0) - ((temp2 * ratio_h) / 2.0); - dw -= (dx * 2.0); - dh -= (dy * 2.0); - *w = (float) dw; - *h = (float) dh; - *x = (float) dx; - *y = (float) dy; - break; - - case FULLSCR_SCALE_KEEPRATIO: - dw = (double) d2d_screen_width; - dh = (double) d2d_screen_height; - hsr = dw / dh; - gsr = ((double) *w) / ((double) *h); - if (gsr <= hsr) - { - temp = dh * gsr; - dx = (dw - temp) / 2.0; - dw = temp; - *w = (float) dw; - *h = (float) dh; - *x = (float) dx; - *y = 0; - } - else - { - temp = dw / gsr; - dy = (dh - temp) / 2.0; - dh = temp; - *w = (float) dw; - *h = (float) dh; - *x = 0; - *y = (float) dy; - } - break; - } -} - - -static void -d2d_blit(int x, int y, int y1, int y2, int w, int h) -{ - HRESULT hr = S_OK; - - void *srcdata; - int yy; - D2D1_RECT_U rectU; - - ID2D1Bitmap *fs_bitmap; - ID2D1RenderTarget *RT; - - float fs_x, fs_y; - float fs_w = w; - float fs_h = h; - - d2d_log("Direct2D: d2d_blit(x=%d, y=%d, y1=%d, y2=%d, w=%d, h=%d)\n", x, y, y1, y2, w, h); - - // TODO: Detect double scanned mode and resize render target - // appropriately for more clear picture - - if (w != d2d_width || h != d2d_height) - { - if (d2d_fs) - { - if (d2d_btmpRT) - { - d2d_btmpRT->Release(); - d2d_btmpRT = NULL; - } - - hr = d2d_hwndRT->CreateCompatibleRenderTarget( - D2D1::SizeF(w, h), - &d2d_btmpRT); - - if (SUCCEEDED(hr)) - { - d2d_width = w; - d2d_height = h; - } - } - else - { - hr = d2d_hwndRT->Resize(D2D1::SizeU(w, h)); - - if (SUCCEEDED(hr)) - { - d2d_width = w; - d2d_height = h; - } - } - } - - if (y1 == y2) { - video_blit_complete(); - return; - } - - if (buffer32 == NULL) { - video_blit_complete(); - return; - } - - // TODO: Copy data directly from buffer32 to d2d_bitmap - - srcdata = malloc(h * w * 4); - - for (yy = y1; yy < y2; yy++) - { - if ((y + yy) >= 0 && (y + yy) < buffer32->h) - { - if (video_grayscale || invert_display) - video_transform_copy( - (uint32_t *) &(((uint8_t *)srcdata)[yy * w * 4]), - &(((uint32_t *)buffer32->line[y + yy])[x]), - w); - else - memcpy( - (uint32_t *) &(((uint8_t *)srcdata)[yy * w * 4]), - &(((uint32_t *)buffer32->line[y + yy])[x]), - w * 4); - } - } - - video_blit_complete(); - - rectU = D2D1::RectU(0, 0, w, h); - hr = d2d_bitmap->CopyFromMemory(&rectU, srcdata, w * 4); - - // In fullscreen mode we first draw offscreen to an intermediate - // BitmapRenderTarget, which then gets rendered to the actual - // HwndRenderTarget in order to implement different scaling modes - - // In windowed mode we draw directly to the HwndRenderTarget - - if (SUCCEEDED(hr)) - { - RT = d2d_fs ? (ID2D1RenderTarget *) d2d_btmpRT : (ID2D1RenderTarget *) d2d_hwndRT; - - RT->BeginDraw(); - - RT->DrawBitmap( - d2d_bitmap, - D2D1::RectF(0, y1, w, y2), - 1.0f, - D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, - D2D1::RectF(0, y1, w, y2)); - - hr = RT->EndDraw(); - } - - if (d2d_fs) - { - if (SUCCEEDED(hr)) - { - hr = d2d_btmpRT->GetBitmap(&fs_bitmap); - } - - if (SUCCEEDED(hr)) - { - d2d_stretch(&fs_w, &fs_h, &fs_x, &fs_y); - - d2d_hwndRT->BeginDraw(); - - d2d_hwndRT->Clear( - D2D1::ColorF(D2D1::ColorF::Black)); - - d2d_hwndRT->DrawBitmap( - fs_bitmap, - D2D1::RectF(fs_x, fs_y, fs_x + fs_w, fs_y + fs_h), - 1.0f, - D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, - D2D1::RectF(0, 0, w, h)); - - hr = d2d_hwndRT->EndDraw(); - } - } - - if (FAILED(hr)) - { - d2d_log("Direct2D: d2d_blit: error 0x%08lx\n", hr); - } - - // Tidy up - free(srcdata); - srcdata = NULL; -} - - -void -d2d_close(void) -{ - d2d_log("Direct2D: d2d_close()\n"); - - if (d2d_bitmap) - { - d2d_bitmap->Release(); - d2d_bitmap = NULL; - } - - if (d2d_btmpRT) - { - d2d_btmpRT->Release(); - d2d_btmpRT = NULL; - } - - if (d2d_hwndRT) - { - d2d_hwndRT->Release(); - d2d_hwndRT = NULL; - } - - if (d2d_factory) - { - d2d_factory->Release(); - d2d_factory = NULL; - } - - if (d2d_hwnd) - { - hwndMain = old_hwndMain; - plat_set_input(hwndMain); - DestroyWindow(d2d_hwnd); - d2d_hwnd = NULL; - old_hwndMain = NULL; - } -} - - -static int -d2d_init_common(int fs) -{ - HRESULT hr = S_OK; - WCHAR title[200]; - D2D1_HWND_RENDER_TARGET_PROPERTIES props; - - d2d_log("Direct2D: d2d_init_common(fs=%d)\n", fs); - - cgapal_rebuild(); - - if (fs) - { - d2d_screen_width = GetSystemMetrics(SM_CXSCREEN); - d2d_screen_height = GetSystemMetrics(SM_CYSCREEN); - - // Direct2D seems to lack any proper fullscreen mode, - // therefore we just create a full screen window - // and pass its handle to a HwndRenderTarget - - mbstowcs(title, emu_version, sizeof_w(title)); - - d2d_hwnd = CreateWindow( - SUB_CLASS_NAME, - title, - WS_POPUP, - 0, 0, d2d_screen_width, d2d_screen_height, - HWND_DESKTOP, - NULL, - hinstance, - NULL); - - old_hwndMain = hwndMain; - hwndMain = d2d_hwnd; - - plat_set_input(d2d_hwnd); - - SetFocus(d2d_hwnd); - SetWindowPos(d2d_hwnd, HWND_TOPMOST, 0, 0, d2d_screen_width, d2d_screen_height, SWP_SHOWWINDOW); - } - - if (SUCCEEDED(hr)) - { - hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &d2d_factory); - } - - if (fs) - { - props = D2D1::HwndRenderTargetProperties(d2d_hwnd, - D2D1::SizeU(d2d_screen_width, d2d_screen_height)); - } - else - { - // HwndRenderTarget will get resized appropriately by d2d_blit, - // so it's fine to let D2D imply size of 0x0 for now - props = D2D1::HwndRenderTargetProperties(hwndRender); - } - - if (SUCCEEDED(hr)) - { - hr = d2d_factory->CreateHwndRenderTarget( - D2D1::RenderTargetProperties(), - props, - &d2d_hwndRT); - } - - if (SUCCEEDED(hr)) - { - // Create a bitmap for storing intermediate data - hr = d2d_hwndRT->CreateBitmap( - D2D1::SizeU(2048, 2048), - D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)), - &d2d_bitmap); - } - - if (SUCCEEDED(hr)) - { - d2d_fs = fs; - - d2d_width = 0; - d2d_height = 0; - - // Make sure we get a clean exit. - atexit(d2d_close); - - // Register our renderer! - video_setblit(d2d_blit); - } - - if (FAILED(hr)) - { - d2d_log("Direct2D: d2d_init_common: error 0x%08lx\n", hr); - d2d_close(); - return(0); - } - - return(1); -} - - -int -d2d_init(HWND h) -{ - d2d_log("Direct2D: d2d_init(h=0x%08lx)\n", h); - return d2d_init_common(0); -} - - -int -d2d_init_fs(HWND h) -{ - d2d_log("Direct2D: d2d_init_fs(h=0x%08lx)\n", h); - return d2d_init_common(1); -} - - -int -d2d_pause(void) -{ - // Not implemented in any renderer. The heck is this even for? - - d2d_log("Direct2D: d2d_pause()\n"); - return(0); -} - - -void -d2d_take_screenshot(wchar_t *fn) -{ - // Saving a screenshot of a Direct2D render target is harder than - // one would think. Keeping this stubbed for the moment - // -ryu - - d2d_log("Direct2D: d2d_take_screenshot(%s)\n", fn); - return; -} \ No newline at end of file diff --git a/src/win/win_d2d.h b/src/win/win_d2d.h index 00bfe0887..cc3fe4881 100644 --- a/src/win/win_d2d.h +++ b/src/win/win_d2d.h @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -8,28 +8,19 @@ * * Definitions for the Direct2D rendering module. * - * Version: @(#)win_d2d.h 1.0.0 2018/07/19 + * Version: @(#)win_d2d.h 1.0.2 2019/12/13 * * Authors: David HrdliÄka, * - * Copyright 2018 David HrdliÄka. + * Copyright 2018,2019 David HrdliÄka. */ #ifndef WIN_D2D_H # define WIN_D2D_H -#ifdef __cplusplus -extern "C" { -#endif - extern void d2d_close(void); extern int d2d_init(HWND h); extern int d2d_init_fs(HWND h); extern int d2d_pause(void); -extern void d2d_take_screenshot(wchar_t *fn); - -#ifdef __cplusplus -} -#endif - +extern void d2d_enable(int enable); #endif /*WIN_D2D_H*/ \ No newline at end of file diff --git a/src/win/win_d3d.cpp b/src/win/win_d3d.cpp deleted file mode 100644 index fe18d587c..000000000 --- a/src/win/win_d3d.cpp +++ /dev/null @@ -1,648 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Rendering module for Microsoft Direct3D 9. - * - * Version: @(#)win_d3d.cpp 1.0.11 2018/05/26 - * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. - */ -#include -#include -#include "../86box.h" -#include "../device.h" -#include "../video/video.h" -#include "../plat.h" -#include "win.h" -#include "win_d3d.h" - - -struct CUSTOMVERTEX { - FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag - DWORD color; - FLOAT tu, tv; -}; - - -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_w, - d3d_h; - -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} -}; - - -static void -d3d_size_default(RECT w_rect, double *l, double *t, double *r, double *b) -{ - *l = -0.5; - *t = -0.5; - *r = (w_rect.right - w_rect.left) - 0.5; - *b = (w_rect.bottom - w_rect.top) - 0.5; -} - - -static void -d3d_size(RECT w_rect, double *l, double *t, double *r, double *b, int w, int h) -{ - int ratio_w, ratio_h; - double hsr, gsr, ra, d; - - switch (video_fullscreen_scale) { - case FULLSCR_SCALE_FULL: - d3d_size_default(w_rect, l, t, r, b); - break; - - case FULLSCR_SCALE_43: - *t = -0.5; - *b = (w_rect.bottom - w_rect.top) - 0.5; - *l = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)) - 0.5; - *r = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)) - 0.5; - if (*l < -0.5) { - *l = -0.5; - *r = (w_rect.right - w_rect.left) - 0.5; - *t = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * 3) / (4 * 2)) - 0.5; - *b = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * 3) / (4 * 2)) - 0.5; - } - break; - - case FULLSCR_SCALE_SQ: - *t = -0.5; - *b = (w_rect.bottom - w_rect.top) - 0.5; - *l = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * w) / (h * 2)) - 0.5; - *r = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * w) / (h * 2)) - 0.5; - if (*l < -0.5) { - *l = -0.5; - *r = (w_rect.right - w_rect.left) - 0.5; - *t = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * h) / (w * 2)) - 0.5; - *b = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * h) / (w * 2)) - 0.5; - } - break; - - case FULLSCR_SCALE_INT: - ratio_w = (w_rect.right - w_rect.left) / w; - ratio_h = (w_rect.bottom - w_rect.top) / h; - if (ratio_h < ratio_w) - ratio_w = ratio_h; - *l = ((w_rect.right - w_rect.left) / 2) - ((w * ratio_w) / 2) - 0.5; - *r = ((w_rect.right - w_rect.left) / 2) + ((w * ratio_w) / 2) - 0.5; - *t = ((w_rect.bottom - w_rect.top) / 2) - ((h * ratio_w) / 2) - 0.5; - *b = ((w_rect.bottom - w_rect.top) / 2) + ((h * ratio_w) / 2) - 0.5; - break; - - case FULLSCR_SCALE_KEEPRATIO: - hsr = ((double) (w_rect.right - w_rect.left)) / ((double) (w_rect.bottom - w_rect.top)); - gsr = ((double) w) / ((double) h); - - if (hsr > gsr) { - /* Host ratio is bigger than guest ratio. */ - ra = ((double) (w_rect.bottom - w_rect.top)) / ((double) h); - - d = ((double) w) * ra; - d = (((double) (w_rect.right - w_rect.left)) - d) / 2.0; - - *l = ((int) d) - 0.5; - *r = (w_rect.right - w_rect.left) - ((int) d) - 0.5; - *t = -0.5; - *b = (w_rect.bottom - w_rect.top) - 0.5; - } else if (hsr < gsr) { - /* Host ratio is smaller or rqual than guest ratio. */ - ra = ((double) (w_rect.right - w_rect.left)) / ((double) w); - - d = ((double) h) * ra; - d = (((double) (w_rect.bottom - w_rect.top)) - d) / 2.0; - - *l = -0.5; - *r = (w_rect.right - w_rect.left) - 0.5; - *t = ((int) d) - 0.5; - *b = (w_rect.bottom - w_rect.top) - ((int) d) - 0.5; - } else { - /* Host ratio is equal to guest ratio. */ - d3d_size_default(w_rect, l, t, r, b); - } - break; - } -} - - -static void -d3d_blit_fs(int x, int y, int y1, int y2, int w, int h) -{ - HRESULT hr = D3D_OK; - HRESULT hbsr = D3D_OK; - VOID* pVoid; - D3DLOCKED_RECT dr; - RECT w_rect; - int yy; - double l = 0, t = 0, r = 0, b = 0; - - if ((y1 == y2) || (h <= 0)) { - 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; - - hr = d3dTexture->LockRect(0, &dr, &lock_rect, 0); - if (hr == D3D_OK) { - for (yy = y1; yy < y2; yy++) { - if (buffer32) { - if (video_grayscale || invert_display) - video_transform_copy((uint32_t *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w); - else - 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(); - return; - } - } 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, &w_rect); - d3d_size(w_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) - hbsr = 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 (hbsr == 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(hwndMain, WM_RESETD3D, 0, 0); -} - - -static void -d3d_blit(int x, int y, int y1, int y2, int w, int h) -{ - HRESULT hr = D3D_OK; - HRESULT hbsr = D3D_OK; - VOID* pVoid; - D3DLOCKED_RECT dr; - RECT r; - int yy; - - if ((y1 == y2) || (h <= 0)) { - video_blit_complete(); - return; /*Nothing to do*/ - } - - r.top = y1; - r.left = 0; - r.bottom = y2; - r.right = 2047; - - hr = d3dTexture->LockRect(0, &dr, &r, 0); - if (hr == D3D_OK) { - for (yy = y1; yy < y2; yy++) { - if (buffer32) { - if ((y + yy) >= 0 && (y + yy) < buffer32->h) { - if (video_grayscale || invert_display) - video_transform_copy((uint32_t *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w); - else - 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(); - return; - } - - 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) - hbsr = 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 (hbsr == 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); -} - - -static void -d3d_init_objects(void) -{ - D3DLOCKED_RECT dr; - RECT r; - int y; - - if (FAILED(d3ddev->CreateVertexBuffer(12*sizeof(CUSTOMVERTEX), - 0, - D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1, - D3DPOOL_MANAGED, - &v_buffer, - NULL))) - fatal("CreateVertexBuffer failed\n"); - - if (FAILED(d3ddev->CreateTexture(2048, 2048, 1, 0, - D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL))) - fatal("CreateTexture failed\n"); - - 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); -} - - -int -d3d_init(HWND h) -{ - d3d_hwnd = h; - - cgapal_rebuild(); - - 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; - - if (FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, h, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &d3dpp, &d3ddev))) - fatal("CreateDevice failed\n"); - - d3d_init_objects(); - - video_setblit(d3d_blit); - - return(1); -} - - -int -d3d_init_fs(HWND h) -{ - WCHAR title[200]; - - cgapal_rebuild(); - - d3d_w = GetSystemMetrics(SM_CXSCREEN); - d3d_h = GetSystemMetrics(SM_CYSCREEN); - - d3d_hwnd = h; - - /*FIXME: should be done once, in win.c */ - _swprintf(title, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); - d3d_device_window = CreateWindowEx ( - 0, - SUB_CLASS_NAME, - title, - 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_w; - d3dpp.BackBufferHeight = d3d_h; - - if (FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, h, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &d3dpp, &d3ddev))) - fatal("CreateDevice failed\n"); - - d3d_init_objects(); - - video_setblit(d3d_blit_fs); - - return(1); -} - - -static void -d3d_close_objects(void) -{ - if (d3dTexture) { - d3dTexture->Release(); - d3dTexture = NULL; - } - if (v_buffer) { - v_buffer->Release(); - v_buffer = NULL; - } -} - - -void -d3d_close(void) -{ - video_setblit(NULL); - - d3d_close_objects(); - - if (d3ddev) { - d3ddev->Release(); - d3ddev = NULL; - } - if (d3d) { - d3d->Release(); - d3d = NULL; - } - - if (d3d_device_window != NULL) { - DestroyWindow(d3d_device_window); - d3d_device_window = NULL; - } -} - - -void -d3d_reset(void) -{ - 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_reset_fs(void) -{ - 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_w; - d3dpp.BackBufferHeight = d3d_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_resize(int x, int y) -{ - d3dpp.BackBufferWidth = x; - d3dpp.BackBufferHeight = y; - - d3d_reset(); -} - - -int -d3d_pause(void) -{ - return(0); -} - - -void -d3d_take_screenshot(wchar_t *fn) -{ - LPDIRECT3DSURFACE9 d3dSurface = NULL; - - if (! d3dTexture) return; - - d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); - D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); - - d3dSurface->Release(); - d3dSurface = NULL; -} diff --git a/src/win/win_d3d.h b/src/win/win_d3d.h deleted file mode 100644 index 18c7c9161..000000000 --- a/src/win/win_d3d.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Direct3D 9 rendererer and screenshots taking. - * - * Version: @(#)win_d3d.h 1.0.3 2017/11/12 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. - */ -#ifndef WIN_D3D_H -# define WIN_D3D_H -# define UNICODE -# define BITMAP WINDOWS_BITMAP -# include -# include -# undef BITMAP - - -#ifdef __cplusplus -extern "C" { -#endif - -extern int d3d_init(HWND h); -extern int d3d_init_fs(HWND h); -extern void d3d_close(void); -extern void d3d_reset(void); -extern void d3d_reset_fs(void); -extern int d3d_pause(void); -extern void d3d_resize(int x, int y); -extern void d3d_take_screenshot(wchar_t *fn); - -#ifdef __cplusplus -} -#endif - - -#endif /*WIN_D3D_H*/ diff --git a/src/win/win_ddraw.cpp b/src/win/win_ddraw.cpp deleted file mode 100644 index 5168be9e2..000000000 --- a/src/win/win_ddraw.cpp +++ /dev/null @@ -1,691 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Rendering module for Microsoft DirectDraw 9. - * - * NOTES: This code should be re-merged into a single init() with a - * 'fullscreen' argument, indicating FS mode is requested. - * - * Version: @(#)win_ddraw.cpp 1.0.10 2018/07/17 - * - * Authors: Sarah Walker, - * Miran Grca, - * Fred N. van Kempen, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. - */ -#include -#include -#include -#define UNICODE -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP - -#define PNG_DEBUG 0 -#include - -#define HAVE_STDARG_H -#include "../86box.h" -#include "../device.h" -#include "../video/video.h" -#include "../plat.h" -#include "../ui.h" -#include "win_ddraw.h" -#include "win.h" - - -static LPDIRECTDRAW lpdd = NULL; -static LPDIRECTDRAW4 lpdd4 = NULL; -static LPDIRECTDRAWSURFACE4 lpdds_pri = NULL, - lpdds_back = NULL, - lpdds_back2 = NULL; -static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; -static DDSURFACEDESC2 ddsd; -static HWND ddraw_hwnd; -static HBITMAP hbitmap; -static int ddraw_w, ddraw_h, - xs, ys, ys2; - -static png_structp png_ptr; -static png_infop info_ptr; - - -#ifdef ENABLE_DDRAW_LOG -int ddraw_do_log = ENABLE_DDRAW_LOG; -#endif - - -static void -ddraw_log(const char *fmt, ...) -{ -#ifdef ENABLE_DDRAW_LOG - va_list ap; - - if (ddraw_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - -static void -CopySurface(IDirectDrawSurface4 *pDDSurface) -{ - HDC hdc, hmemdc; - HBITMAP hprevbitmap; - DDSURFACEDESC2 ddsd2; - - pDDSurface->GetDC(&hdc); - hmemdc = CreateCompatibleDC(hdc); - ZeroMemory(&ddsd2 ,sizeof( ddsd2 )); // better to clear before using - ddsd2.dwSize = sizeof( ddsd2 ); //initialize with size - pDDSurface->GetSurfaceDesc(&ddsd2); - hbitmap = CreateCompatibleBitmap( hdc ,xs ,ys); - hprevbitmap = (HBITMAP) SelectObject( hmemdc, hbitmap ); - BitBlt(hmemdc,0 ,0 ,xs ,ys ,hdc ,0 ,0,SRCCOPY); - SelectObject(hmemdc,hprevbitmap); // restore the old bitmap - DeleteDC(hmemdc); - pDDSurface->ReleaseDC(hdc); -} - - -static void -bgra_to_rgb(png_bytep *b_rgb, uint8_t *bgra, int width, int height) -{ - int i, j; - uint8_t *r, *b; - - if (video_grayscale || invert_display) - *bgra = video_color_transform(*bgra); - - for (i = 0; i < height; i++) { - for (j = 0; j < width; j++) { - r = &b_rgb[(height - 1) - i][j * 3]; - b = &bgra[((i * width) + j) * 4]; - r[0] = b[2]; - r[1] = b[1]; - r[2] = b[0]; - } - } -} - - -static void -DoubleLines(uint8_t *dst, uint8_t *src) -{ - int i = 0; - - for (i = 0; i < ys; i++) { - memcpy(dst + (i * xs * 8), src + (i * xs * 4), xs * 4); - memcpy(dst + ((i * xs * 8) + (xs * 4)), src + (i * xs * 4), xs * 4); - } -} - - -static void -SavePNG(wchar_t *szFilename, HBITMAP hBitmap) -{ - BITMAPINFO bmpInfo; - HDC hdc; - LPVOID pBuf = NULL; - LPVOID pBuf2 = NULL; - png_bytep *b_rgb = NULL; - int i; - - /* create file */ - FILE *fp = plat_fopen(szFilename, (wchar_t *) L"wb"); - if (!fp) { - ddraw_log("[SavePNG] File %ls could not be opened for writing", szFilename); - return; - } - - /* initialize stuff */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!png_ptr) { - ddraw_log("[SavePNG] png_create_write_struct failed"); - fclose(fp); - return; - } - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - ddraw_log("[SavePNG] png_create_info_struct failed"); - fclose(fp); - return; - } - - png_init_io(png_ptr, fp); - - hdc = GetDC(NULL); - - ZeroMemory(&bmpInfo, sizeof(BITMAPINFO)); - bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - - GetDIBits(hdc, hBitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS); - - if (bmpInfo.bmiHeader.biSizeImage <= 0) - bmpInfo.bmiHeader.biSizeImage = - bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; - - if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { - ddraw_log("[SavePNG] Unable to Allocate Bitmap Memory"); - fclose(fp); - return; - } - - if (ys2 <= 250) { - bmpInfo.bmiHeader.biSizeImage <<= 1; - - if ((pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { - ddraw_log("[SavePNG] Unable to Allocate Secondary Bitmap Memory"); - free(pBuf); - fclose(fp); - return; - } - - bmpInfo.bmiHeader.biHeight <<= 1; - } - - ddraw_log("save png w=%i h=%i\n", bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); - - bmpInfo.bmiHeader.biCompression = BI_RGB; - - GetDIBits(hdc, hBitmap, 0, bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS); - - png_set_IHDR(png_ptr, info_ptr, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight, - 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - if ((b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * bmpInfo.bmiHeader.biHeight)) == NULL) { - ddraw_log("[SavePNG] Unable to Allocate RGB Bitmap Memory"); - free(pBuf2); - free(pBuf); - fclose(fp); - return; - } - - for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) - b_rgb[i] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); - - if (pBuf2) { - DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf); - bgra_to_rgb(b_rgb, (uint8_t *) pBuf2, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); - } else - bgra_to_rgb(b_rgb, (uint8_t *) pBuf, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); - - png_write_info(png_ptr, info_ptr); - - png_write_image(png_ptr, b_rgb); - - png_write_end(png_ptr, NULL); - - /* cleanup heap allocation */ - if (hdc) ReleaseDC(NULL,hdc); - - for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) - if (b_rgb[i]) free(b_rgb[i]); - - if (b_rgb) free(b_rgb); - - if (pBuf2) free(pBuf2); - - if (pBuf) free(pBuf); - - if (fp) fclose(fp); -} - - -static void -ddraw_fs_size_default(RECT w_rect, RECT *r_dest) -{ - r_dest->left = 0; - r_dest->top = 0; - r_dest->right = (w_rect.right - w_rect.left) - 1; - r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; -} - - -static void -ddraw_fs_size(RECT w_rect, RECT *r_dest, int w, int h) -{ - int ratio_w, ratio_h; - double hsr, gsr, ra, d; - - ddraw_log("video_fullscreen_scale = %i\n", video_fullscreen_scale); - - switch (video_fullscreen_scale) { - case FULLSCR_SCALE_FULL: - ddraw_fs_size_default(w_rect, r_dest); - break; - - case FULLSCR_SCALE_43: - r_dest->top = 0; - r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; - r_dest->left = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)); - r_dest->right = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)) - 1; - if (r_dest->left < 0) { - r_dest->left = 0; - r_dest->right = (w_rect.right - w_rect.left) - 1; - r_dest->top = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * 3) / (4 * 2)); - r_dest->bottom = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * 3) / (4 * 2)) - 1; - } - break; - - case FULLSCR_SCALE_SQ: - r_dest->top = 0; - r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; - r_dest->left = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * w) / (h * 2)); - r_dest->right = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * w) / (h * 2)) - 1; - if (r_dest->left < 0) { - r_dest->left = 0; - r_dest->right = (w_rect.right - w_rect.left) - 1; - r_dest->top = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * h) / (w * 2)); - r_dest->bottom = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * h) / (w * 2)) - 1; - } - break; - - case FULLSCR_SCALE_INT: - ratio_w = (w_rect.right - w_rect.left) / w; - ratio_h = (w_rect.bottom - w_rect.top) / h; - if (ratio_h < ratio_w) - ratio_w = ratio_h; - r_dest->left = ((w_rect.right - w_rect.left) / 2) - ((w * ratio_w) / 2); - r_dest->right = ((w_rect.right - w_rect.left) / 2) + ((w * ratio_w) / 2) - 1; - r_dest->top = ((w_rect.bottom - w_rect.top) / 2) - ((h * ratio_w) / 2); - r_dest->bottom = ((w_rect.bottom - w_rect.top) / 2) + ((h * ratio_w) / 2) - 1; - break; - - case FULLSCR_SCALE_KEEPRATIO: - hsr = ((double) (w_rect.right - w_rect.left)) / ((double) (w_rect.bottom - w_rect.top)); - gsr = ((double) w) / ((double) h); - - if (hsr > gsr) { - /* Host ratio is bigger than guest ratio. */ - ra = ((double) (w_rect.bottom - w_rect.top)) / ((double) h); - - d = ((double) w) * ra; - d = (((double) (w_rect.right - w_rect.left)) - d) / 2.0; - - r_dest->left = ((int) d); - r_dest->right = (w_rect.right - w_rect.left) - ((int) d) - 1; - r_dest->top = 0; - r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; - } else if (hsr < gsr) { - /* Host ratio is smaller or rqual than guest ratio. */ - ra = ((double) (w_rect.right - w_rect.left)) / ((double) w); - - d = ((double) h) * ra; - d = (((double) (w_rect.bottom - w_rect.top)) - d) / 2.0; - - r_dest->left = 0; - r_dest->right = (w_rect.right - w_rect.left) - 1; - r_dest->top = ((int) d); - r_dest->bottom = (w_rect.bottom - w_rect.top) - ((int) d) - 1; - } else { - /* Host ratio is equal to guest ratio. */ - ddraw_fs_size_default(w_rect, r_dest); - } - break; - } -} - - -static void -ddraw_blit_fs(int x, int y, int y1, int y2, int w, int h) -{ - RECT r_src; - RECT r_dest; - RECT w_rect; - int yy; - HRESULT hr; - DDBLTFX ddbltfx; - - if (lpdds_back == NULL) { - video_blit_complete(); - return; /*Nothing to do*/ - } - - if ((y1 == y2) || (h <= 0)) { - video_blit_complete(); - return; - } - - 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 (buffer32) { - if (video_grayscale || invert_display) - video_transform_copy((uint32_t *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)), &(((uint32_t *)buffer32->line[y + yy])[x]), w); - else - 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); - - w_rect.left = 0; - w_rect.top = 0; - w_rect.right = ddraw_w; - w_rect.bottom = ddraw_h; - ddraw_fs_size(w_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(&w_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); - } - - hr = lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); - if (hr == DDERR_SURFACELOST) { - lpdds_pri->Restore(); - lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); - } -} - - -static void -ddraw_blit(int x, int y, int y1, int y2, int w, int h) -{ - RECT r_src; - RECT r_dest; - POINT po; - HRESULT hr; - int yy; - - if (lpdds_back == NULL) { - video_blit_complete(); - return; /*Nothing to do*/ - } - - if ((y1 == y2) || (h <= 0)) { - video_blit_complete(); - return; - } - - 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 (buffer32) { - if ((y + yy) >= 0 && (y + yy) < buffer32->h) { - if (video_grayscale || invert_display) - video_transform_copy((uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w); - else - memcpy((uint32_t *) &(((uint8_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); - } - - lpdds_back2->Unlock(NULL); - - 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); - } -} - - -void -ddraw_take_screenshot(wchar_t *fn) -{ -#if 0 - xs = xsize; - ys = ys2 = ysize; - - /* For EGA/(S)VGA, the size is NOT adjusted for overscan. */ - if ((overscan_y > 16) && enable_overscan) { - xs += overscan_x; - ys += overscan_y; - } - - /* For CGA, the width is adjusted for overscan, but the height is not. */ - if (overscan_y == 16) { - if (ys2 <= 250) - ys += (overscan_y >> 1); - else - ys += overscan_y; - } -#endif - - xs = get_actual_size_x(); - ys = ys2 = get_actual_size_y(); - - if (ysize <= 250) { - ys >>= 1; - ys2 >>= 1; - } - - CopySurface(lpdds_back2); - - SavePNG(fn, hbitmap); -} - - -int -ddraw_init(HWND h) -{ - cgapal_rebuild(); - - if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) return(0); - - if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) - return(0); - - lpdd->Release(); - lpdd = NULL; - - atexit(ddraw_close); - - if (FAILED(lpdd4->SetCooperativeLevel(h, DDSCL_NORMAL))) return(0); - - 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))) return(0); - - 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))) { - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.dwWidth = 2048; - ddsd.dwHeight = 2048; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; - 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))) { - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.dwWidth = 2048; - ddsd.dwHeight = 2048; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; - if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL))) - fatal("CreateSurface back failed\n"); - } - - if (FAILED(lpdd4->CreateClipper(0, &lpdd_clipper, NULL))) return(0); - - if (FAILED(lpdd_clipper->SetHWnd(0, h))) return(0); - - if (FAILED(lpdds_pri->SetClipper(lpdd_clipper))) return(0); - - ddraw_hwnd = h; - - video_setblit(ddraw_blit); - - return(1); -} - - -int -ddraw_init_fs(HWND h) -{ - ddraw_w = GetSystemMetrics(SM_CXSCREEN); - ddraw_h = GetSystemMetrics(SM_CYSCREEN); - - cgapal_rebuild(); - - if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) return 0; - - if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) return 0; - - lpdd->Release(); - lpdd = NULL; - - atexit(ddraw_close); - - if (FAILED(lpdd4->SetCooperativeLevel(h, - DDSCL_SETFOCUSWINDOW | \ - DDSCL_CREATEDEVICEWINDOW | \ - DDSCL_EXCLUSIVE | \ - DDSCL_FULLSCREEN | \ - DDSCL_ALLOWREBOOT))) return 0; - - if (FAILED(lpdd4->SetDisplayMode(ddraw_w, ddraw_h, 32, 0 ,0))) return 0; - - 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))) return 0; - - ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; - if (FAILED(lpdds_pri->GetAttachedSurface(&ddsd.ddsCaps, &lpdds_back2))) return 0; - - 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))) { - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.dwWidth = 2048; - ddsd.dwHeight = 2048; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; - if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) return 0; - } - - ddraw_hwnd = h; - - video_setblit(ddraw_blit_fs); - - return(1); -} - - -void -ddraw_close(void) -{ - video_setblit(NULL); - - 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; - } -} - - -int -ddraw_pause(void) -{ - return(0); -} diff --git a/src/win/win_ddraw.h b/src/win/win_ddraw.h deleted file mode 100644 index 357ba4906..000000000 --- a/src/win/win_ddraw.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Definitions for the DirectDraw 9 rendering module. - * - * Version: @(#)win_ddraw.h 1.0.1 2017/11/12 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. - */ -#ifndef WIN_DDRAW_H -# define WIN_DDRAW_H -# define UNICODE -# define BITMAP WINDOWS_BITMAP -# include -# undef BITMAP - - -#ifdef __cplusplus -extern "C" { -#endif - -extern int ddraw_init(HWND h); -extern int ddraw_init_fs(HWND h); -extern void ddraw_close(void); -extern int ddraw_pause(void); -extern void ddraw_take_screenshot(wchar_t *fn); - -#ifdef __cplusplus -} -#endif - - -#endif /*WIN_DDRAW_H*/ diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index 203fd2f32..e5e379d6c 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -8,7 +8,7 @@ * * Windows device configuration dialog implementation. * - * Version: @(#)win_devconf.c 1.0.18 2018/04/01 + * Version: @(#)win_devconf.c 1.0.20 2018/10/23 * * Authors: Sarah Walker, * Miran Grca, @@ -18,6 +18,7 @@ */ #include #include +#include #include #include #include "../86box.h" @@ -30,703 +31,704 @@ #include -static const device_t *config_device; +static device_context_t config_device; static uint8_t deviceconfig_changed = 0; -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK #endif deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; + HWND h; - int val_int; - int id; - int c; - int num; - int changed; - int cid; - const device_config_t *config; - char s[80]; - wchar_t ws[512]; - LPTSTR lptsTemp; + int val_int, id, c, d, num; + int changed, cid; + const device_config_t *config; + const device_config_selection_t *selection; + char s[512], file_filter[512]; + char *str; + wchar_t ws[512], *wstr; + LPTSTR lptsTemp; - switch (message) - { - case WM_INITDIALOG: - { - id = IDC_CONFIG_BASE; - config = config_device->config; + config = config_device.dev->config; - lptsTemp = (LPTSTR) malloc(512); + switch (message) { + case WM_INITDIALOG: + id = IDC_CONFIG_BASE; + config = config_device.dev->config; - while (config->type != -1) - { - const device_config_selection_t *selection = config->selection; - h = GetDlgItem(hdlg, id); - - switch (config->type) - { - case CONFIG_BINARY: - val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); - - SendMessage(h, BM_SETCHECK, val_int, 0); - - id++; - break; + lptsTemp = (LPTSTR) malloc(512); - case CONFIG_SELECTION: - val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); - - c = 0; - while (selection->description && selection->description[0]) - { - mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); - if (val_int == selection->value) - SendMessage(h, CB_SETCURSEL, c, 0); - selection++; - c++; - } - - id += 2; - break; + while (config->type != -1) { + selection = config->selection; + h = GetDlgItem(hdlg, id); - case CONFIG_MIDI: - val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); - - num = plat_midi_get_num_devs(); - for (c = 0; c < num; c++) - { - plat_midi_get_dev_name(c, s); + switch (config->type) { + case CONFIG_BINARY: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); + + SendMessage(h, BM_SETCHECK, val_int, 0); + + id++; + break; + case CONFIG_SELECTION: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); + + c = 0; + while (selection->description && selection->description[0]) { + mbstowcs(lptsTemp, selection->description, + strlen(selection->description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; + case CONFIG_MIDI: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); + + num = plat_midi_get_num_devs(); + for (c = 0; c < num; c++) { + plat_midi_get_dev_name(c, s); mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); - if (val_int == c) - SendMessage(h, CB_SETCURSEL, c, 0); - } - - id += 2; - break; + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == c) + SendMessage(h, CB_SETCURSEL, c, 0); + } - case CONFIG_SPINNER: - val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + id += 2; + break; + case CONFIG_MIDI_IN: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); - _swprintf(ws, L"%i", val_int); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)ws); + num = plat_midi_in_get_num_devs(); + for (c = 0; c < num; c++) { + plat_midi_in_get_dev_name(c, s); + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == c) + SendMessage(h, CB_SETCURSEL, c, 0); + } - id += 2; - break; + id += 2; + break; + case CONFIG_SPINNER: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); - case CONFIG_FNAME: - { - wchar_t* str = config_get_wstring((char *) config_device->name, (char *) config->name, 0); - if (str) - SendMessage(h, WM_SETTEXT, 0, (LPARAM)str); - id += 3; - } - break; + _swprintf(ws, L"%i", val_int); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ws); - case CONFIG_HEX16: - val_int = config_get_hex16((char *) config_device->name, (char *) config->name, config->default_int); - - c = 0; - while (selection->description && selection->description[0]) - { - mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); - if (val_int == selection->value) - SendMessage(h, CB_SETCURSEL, c, 0); - selection++; - c++; - } - - id += 2; - break; + id += 2; + break; + case CONFIG_FNAME: + wstr = config_get_wstring((char *) config_device.name, + (char *) config->name, 0); + if (wstr) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)wstr); + id += 3; + break; + case CONFIG_HEX16: + val_int = config_get_hex16((char *) config_device.name, + (char *) config->name, config->default_int); - case CONFIG_HEX20: - val_int = config_get_hex20((char *) config_device->name, (char *) config->name, config->default_int); - - c = 0; - while (selection->description && selection->description[0]) - { - mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); - if (val_int == selection->value) - SendMessage(h, CB_SETCURSEL, c, 0); - selection++; - c++; - } - - id += 2; - break; - } - config++; - } + c = 0; + while (selection->description && selection->description[0]) { + mbstowcs(lptsTemp, selection->description, + strlen(selection->description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } - free(lptsTemp); - } - return TRUE; - - case WM_COMMAND: - { - cid = LOWORD(wParam); - if (cid == IDOK) - { - id = IDC_CONFIG_BASE; - config = config_device->config; - changed = 0; - char s[512]; - - while (config->type != -1) - { - const device_config_selection_t *selection = config->selection; - h = GetDlgItem(hdlg, id); - - switch (config->type) - { - case CONFIG_BINARY: - val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + id += 2; + break; + case CONFIG_HEX20: + val_int = config_get_hex20((char *) config_device.name, + (char *) config->name, config->default_int); - if (val_int != SendMessage(h, BM_GETCHECK, 0, 0)) - changed = 1; - - id++; - break; + c = 0; + while (selection->description && selection->description[0]) { + mbstowcs(lptsTemp, selection->description, + strlen(selection->description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } - case CONFIG_SELECTION: - val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + id += 2; + break; + } + config++; + } + free(lptsTemp); + return TRUE; + case WM_COMMAND: + cid = LOWORD(wParam); + if (cid == IDOK) { + id = IDC_CONFIG_BASE; + config = config_device.dev->config; + changed = 0; + char s[512]; - c = SendMessage(h, CB_GETCURSEL, 0, 0); + while (config->type != -1) { + const device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); - for (; c > 0; c--) - selection++; + switch (config->type) { + case CONFIG_BINARY: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); - if (val_int != selection->value) - changed = 1; - - id += 2; - break; + if (val_int != SendMessage(h, BM_GETCHECK, 0, 0)) + changed = 1; - case CONFIG_MIDI: - val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + id++; + break; + case CONFIG_SELECTION: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); - c = SendMessage(h, CB_GETCURSEL, 0, 0); + c = SendMessage(h, CB_GETCURSEL, 0, 0); - if (val_int != c) - changed = 1; - - id += 2; - break; + for (; c > 0; c--) + selection++; - case CONFIG_FNAME: - { - char* str = config_get_string((char *) config_device->name, (char *) config->name, (char*)""); - SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); - if (strcmp(str, s)) - changed = 1; + if (val_int != selection->value) + changed = 1; - id += 3; - } - break; + id += 2; + break; + case CONFIG_MIDI: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); - case CONFIG_SPINNER: - val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); - if (val_int > config->spinner.max) - val_int = config->spinner.max; - else if (val_int < config->spinner.min) - val_int = config->spinner.min; + c = SendMessage(h, CB_GETCURSEL, 0, 0); - SendMessage(h, WM_GETTEXT, 79, (LPARAM)ws); + if (val_int != c) + changed = 1; + + id += 2; + break; + case CONFIG_MIDI_IN: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (val_int != c) + changed = 1; + + id += 2; + break; + case CONFIG_FNAME: + str = config_get_string((char *) config_device.name, + (char *) config->name, (char*)""); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); + if (strcmp(str, s)) + changed = 1; + + id += 3; + break; + case CONFIG_SPINNER: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); + if (val_int > config->spinner.max) + val_int = config->spinner.max; + else if (val_int < config->spinner.min) + val_int = config->spinner.min; + + SendMessage(h, WM_GETTEXT, 79, (LPARAM)ws); wcstombs(s, ws, 512); - sscanf(s, "%i", &c); + sscanf(s, "%i", &c); - if (val_int != c) - changed = 1; + if (val_int != c) + changed = 1; - id += 2; - break; + id += 2; + break; + case CONFIG_HEX16: + val_int = config_get_hex16((char *) config_device.name, + (char *) config->name, config->default_int); - case CONFIG_HEX16: - val_int = config_get_hex16((char *) config_device->name, (char *) config->name, config->default_int); + c = SendMessage(h, CB_GETCURSEL, 0, 0); - c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; - for (; c > 0; c--) - selection++; + if (val_int != selection->value) + changed = 1; - if (val_int != selection->value) - changed = 1; - - id += 2; - break; + id += 2; + break; + case CONFIG_HEX20: + val_int = config_get_hex20((char *) config_device.name, + (char *) config->name, config->default_int); - case CONFIG_HEX20: - val_int = config_get_hex20((char *) config_device->name, (char *) config->name, config->default_int); + c = SendMessage(h, CB_GETCURSEL, 0, 0); - c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; - for (; c > 0; c--) - selection++; + if (val_int != selection->value) + changed = 1; - if (val_int != selection->value) - changed = 1; - - id += 2; - break; - } - config++; - } - - if (!changed) - { - deviceconfig_changed = 0; - EndDialog(hdlg, 0); - return TRUE; - } - - deviceconfig_changed = 1; - - id = IDC_CONFIG_BASE; - config = config_device->config; - - while (config->type != -1) - { - const device_config_selection_t *selection = config->selection; - h = GetDlgItem(hdlg, id); - - switch (config->type) - { - case CONFIG_BINARY: - config_set_int((char *) config_device->name, (char *) 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((char *) config_device->name, (char *) config->name, selection->value); - - id += 2; - break; - - case CONFIG_MIDI: - c = SendMessage(h, CB_GETCURSEL, 0, 0); - config_set_int((char *) config_device->name, (char *) config->name, c); - - id += 2; - break; - - case CONFIG_FNAME: - SendMessage(h, WM_GETTEXT, 511, (LPARAM)ws); - config_set_wstring((char *) config_device->name, (char *) config->name, ws); - - id += 3; - break; - - case CONFIG_SPINNER: - SendMessage(h, WM_GETTEXT, 79, (LPARAM)ws); - wcstombs(s, ws, 512); - sscanf(s, "%i", &c); - if (c > config->spinner.max) - c = config->spinner.max; - else if (c < config->spinner.min) - c = config->spinner.min; - - config_set_int((char *) config_device->name, (char *) config->name, c); - - id += 2; - break; - - case CONFIG_HEX16: - c = SendMessage(h, CB_GETCURSEL, 0, 0); - for (; c > 0; c--) - selection++; - config_set_hex16((char *) config_device->name, (char *) config->name, selection->value); - - id += 2; - break; - - case CONFIG_HEX20: - c = SendMessage(h, CB_GETCURSEL, 0, 0); - for (; c > 0; c--) - selection++; - config_set_hex20((char *) config_device->name, (char *) config->name, selection->value); - - id += 2; - break; - } - config++; - } - - EndDialog(hdlg, 0); - return TRUE; - } - else if (cid == IDCANCEL) - { - deviceconfig_changed = 0; - EndDialog(hdlg, 0); - return TRUE; - } - else - { - int id = IDC_CONFIG_BASE; - const device_config_t *config = config_device->config; - - while (config->type != -1) - { - switch (config->type) - { - case CONFIG_BINARY: - id++; - break; - - case CONFIG_SELECTION: - case CONFIG_MIDI: - case CONFIG_SPINNER: - id += 2; - break; - - case CONFIG_FNAME: - { - if (cid == id+1) - { - char s[512]; - s[0] = 0; - int c, d; - HWND h = GetDlgItem(hdlg, id); - SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); - char file_filter[512]; - file_filter[0] = 0; - - c = 0; - while (config->file_filter[c].description && config->file_filter[c].description[0]) - { - if (c > 0) - strcat(file_filter, "|"); - strcat(file_filter, config->file_filter[c].description); - strcat(file_filter, " ("); - d = 0; - while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) - { - if (d > 0) - strcat(file_filter, ";"); - strcat(file_filter, "*."); - strcat(file_filter, config->file_filter[c].extensions[d]); - d++; - } - strcat(file_filter, ")|"); - d = 0; - while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) - { - if (d > 0) - strcat(file_filter, ";"); - strcat(file_filter, "*."); - strcat(file_filter, config->file_filter[c].extensions[d]); - d++; - } - c++; - } - strcat(file_filter, "|All files (*.*)|*.*|"); - mbstowcs(ws, file_filter, strlen(file_filter) + 1); - d = strlen(file_filter); - - /* replace | with \0 */ - for (c = 0; c < d; ++c) - if (ws[c] == L'|') - ws[c] = 0; - - if (!file_dlg(hdlg, ws, s, 0)) - SendMessage(h, WM_SETTEXT, 0, (LPARAM)wopenfilestring); - } - } - break; - } - config++; - } - } + id += 2; + break; } - break; - } - return FALSE; + config++; + } + + if (!changed) { + deviceconfig_changed = 0; + EndDialog(hdlg, 0); + return TRUE; + } + + deviceconfig_changed = 1; + + id = IDC_CONFIG_BASE; + config = config_device.dev->config; + + while (config->type != -1) { + selection = config->selection; + h = GetDlgItem(hdlg, id); + + switch (config->type) { + case CONFIG_BINARY: + config_set_int((char *) config_device.name, + (char *) 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((char *) config_device.name, (char *) config->name, selection->value); + + id += 2; + break; + case CONFIG_MIDI: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + config_set_int((char *) config_device.name, (char *) config->name, c); + + id += 2; + break; + case CONFIG_MIDI_IN: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + config_set_int((char *) config_device.name, (char *) config->name, c); + + id += 2; + break; + case CONFIG_FNAME: + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ws); + config_set_wstring((char *) config_device.name, (char *) config->name, ws); + + id += 3; + break; + case CONFIG_SPINNER: + SendMessage(h, WM_GETTEXT, 79, (LPARAM)ws); + wcstombs(s, ws, 512); + sscanf(s, "%i", &c); + if (c > config->spinner.max) + c = config->spinner.max; + else if (c < config->spinner.min) + c = config->spinner.min; + + config_set_int((char *) config_device.name, (char *) config->name, c); + + id += 2; + break; + case CONFIG_HEX16: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_hex16((char *) config_device.name, (char *) config->name, selection->value); + + id += 2; + break; + case CONFIG_HEX20: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_hex20((char *) config_device.name, (char *) config->name, selection->value); + + id += 2; + break; + } + config++; + } + + EndDialog(hdlg, 0); + return TRUE; + } else if (cid == IDCANCEL) { + deviceconfig_changed = 0; + EndDialog(hdlg, 0); + return TRUE; + } else { + id = IDC_CONFIG_BASE; + while (config->type != -1) { + switch (config->type) { + case CONFIG_BINARY: + id++; + break; + case CONFIG_SELECTION: + case CONFIG_MIDI: + case CONFIG_MIDI_IN: + case CONFIG_SPINNER: + id += 2; + break; + case CONFIG_FNAME: + if (cid == id+1) { + s[0] = 0; + h = GetDlgItem(hdlg, id); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); + file_filter[0] = 0; + + c = 0; + while (config->file_filter[c].description && config->file_filter[c].description[0]) { + if (c > 0) + strcat(file_filter, "|"); + strcat(file_filter, config->file_filter[c].description); + strcat(file_filter, " ("); + d = 0; + while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) { + if (d > 0) + strcat(file_filter, ";"); + strcat(file_filter, "*."); + strcat(file_filter, config->file_filter[c].extensions[d]); + d++; + } + strcat(file_filter, ")|"); + d = 0; + while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) { + if (d > 0) + strcat(file_filter, ";"); + strcat(file_filter, "*."); + strcat(file_filter, config->file_filter[c].extensions[d]); + d++; + } + c++; + } + strcat(file_filter, "|All files (*.*)|*.*|"); + mbstowcs(ws, file_filter, strlen(file_filter) + 1); + d = strlen(file_filter); + + /* replace | with \0 */ + for (c = 0; c < d; ++c) { + if (ws[c] == L'|') + ws[c] = 0; + } + + if (!file_dlg(hdlg, ws, s, 0)) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)wopenfilestring); + } + break; + } + config++; + } + } + break; + } + return FALSE; } -uint8_t deviceconfig_open(HWND hwnd, const device_t *device) + +uint8_t +deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) { - const 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; + const device_config_t *config = device->config; + uint16_t *data_block; + uint16_t *data; + DLGTEMPLATE *dlg; + DLGITEMTEMPLATE *item; - deviceconfig_changed = 0; + data_block = malloc(16384); + dlg = (DLGTEMPLATE *)data_block; + int y = 10; + int id = IDC_CONFIG_BASE; - memset(data_block, 0, 16384); - - 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, 120); + deviceconfig_changed = 0; - *data++ = 9; /*Point*/ - data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 120); - - if (((uintptr_t)data) & 2) - data++; + memset(data_block, 0, 16384); - 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; + 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; - item->style = WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX; + data = (uint16_t *)(dlg + 1); - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0080; /* button class */ + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 120); - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); - *data++ = 0; /* no creation data */ + *data++ = 9; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 120); - y += 20; - break; + if (((uintptr_t)data) & 2) + data++; - case CONFIG_SELECTION: - case CONFIG_MIDI: - case CONFIG_HEX16: - case CONFIG_HEX20: - /*Combo box*/ - item = (DLGITEMTEMPLATE *)data; - item->x = 70; - item->y = y; - item->id = id++; - - item->cx = 140; - item->cy = 150; + while (config->type != -1) { + switch (config->type) { + case CONFIG_BINARY: + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; - item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + item->cx = 80; + item->cy = 15; - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0085; /* combo box class */ + item->style = WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX; - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); - *data++ = 0; /* no creation data */ - - if (((uintptr_t)data) & 2) - data++; + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ - /*Static text*/ - item = (DLGITEMTEMPLATE *)data; - item->x = 10; - item->y = y; - item->id = id++; - - item->cx = 60; - item->cy = 15; + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ - item->style = WS_CHILD | WS_VISIBLE; + y += 20; + break; - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0082; /* static class */ + case CONFIG_SELECTION: + case CONFIG_MIDI: + case CONFIG_MIDI_IN: + case CONFIG_HEX16: + case CONFIG_HEX20: + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); - *data++ = 0; /* no creation data */ - - if (((uintptr_t)data) & 2) - data++; + item->cx = 140; + item->cy = 150; - y += 20; - break; + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; - case CONFIG_SPINNER: - /*Spinner*/ - item = (DLGITEMTEMPLATE *)data; - item->x = 70; - item->y = y; - item->id = id++; + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ - item->cx = 140; - item->cy = 14; + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ - item->style = WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_NUMBER; - item->dwExtendedStyle = WS_EX_CLIENTEDGE; + if (((uintptr_t)data) & 2) + data++; - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0081; /* edit text class */ + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; - data += MultiByteToWideChar(CP_ACP, 0, "", -1, data, 256); - *data++ = 0; /* no creation data */ + item->cx = 60; + item->cy = 15; - if (((uintptr_t)data) & 2) - data++; + item->style = WS_CHILD | WS_VISIBLE; - /* TODO: add up down class */ - /*Static text*/ - item = (DLGITEMTEMPLATE *)data; - item->x = 10; - item->y = y; - item->id = id++; + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ - item->cx = 60; - item->cy = 15; + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ - item->style = WS_CHILD | WS_VISIBLE; + if (((uintptr_t)data) & 2) + data++; - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0082; /* static class */ + y += 20; + break; + case CONFIG_SPINNER: + /*Spinner*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); - *data++ = 0; /* no creation data */ + item->cx = 140; + item->cy = 14; - if (((uintptr_t)data) & 2) - data++; + item->style = WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_NUMBER; + item->dwExtendedStyle = WS_EX_CLIENTEDGE; - y += 20; - break; + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0081; /* edit text class */ - case CONFIG_FNAME: - /*File*/ - item = (DLGITEMTEMPLATE *)data; - item->x = 70; - item->y = y; - item->id = id++; + data += MultiByteToWideChar(CP_ACP, 0, "", -1, data, 256); + *data++ = 0; /* no creation data */ - item->cx = 100; - item->cy = 14; + if (((uintptr_t)data) & 2) + data++; - item->style = WS_CHILD | WS_VISIBLE | ES_READONLY; - item->dwExtendedStyle = WS_EX_CLIENTEDGE; + /* TODO: add up down class */ + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0081; /* edit text class */ + item->cx = 60; + item->cy = 15; - data += MultiByteToWideChar(CP_ACP, 0, "", -1, data, 256); - *data++ = 0; /* no creation data */ + item->style = WS_CHILD | WS_VISIBLE; - if (((uintptr_t)data) & 2) - data++; + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ - /* Button */ - item = (DLGITEMTEMPLATE *)data; - item->x = 175; - item->y = y; - item->id = id++; + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ - item->cx = 35; - item->cy = 14; + if (((uintptr_t)data) & 2) + data++; - item->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON; + y += 20; + break; + case CONFIG_FNAME: + /*File*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0080; /* button class */ + item->cx = 100; + item->cy = 14; - data += MultiByteToWideChar(CP_ACP, 0, "Browse", -1, data, 256); - *data++ = 0; /* no creation data */ + item->style = WS_CHILD | WS_VISIBLE | ES_READONLY; + item->dwExtendedStyle = WS_EX_CLIENTEDGE; - if (((uintptr_t)data) & 2) - data++; + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0081; /* edit text class */ - /*Static text*/ - item = (DLGITEMTEMPLATE *)data; - item->x = 10; - item->y = y; - item->id = id++; + data += MultiByteToWideChar(CP_ACP, 0, "", -1, data, 256); + *data++ = 0; /* no creation data */ - item->cx = 60; - item->cy = 15; + if (((uintptr_t)data) & 2) + data++; - item->style = WS_CHILD | WS_VISIBLE; + /* Button */ + item = (DLGITEMTEMPLATE *)data; + item->x = 175; + item->y = y; + item->id = id++; - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0082; /* static class */ + item->cx = 35; + item->cy = 14; - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); - *data++ = 0; /* no creation data */ + item->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON; - if (((uintptr_t)data) & 2) - data++; + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ - y += 20; - break; - } + data += MultiByteToWideChar(CP_ACP, 0, "Browse", -1, data, 256); + *data++ = 0; /* no creation data */ - if (((uintptr_t)data) & 2) - data++; + if (((uintptr_t)data) & 2) + data++; - config++; - } + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; - dlg->cdit = (id - IDC_CONFIG_BASE) + 2; + item->cx = 60; + item->cy = 15; - 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; + item->style = WS_CHILD | WS_VISIBLE; - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0080; /* button class */ + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ - data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); - *data++ = 0; /* no creation data */ + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *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; + if (((uintptr_t)data) & 2) + data++; - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0080; /* button class */ + y += 20; + break; + } - data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); - *data++ = 0; /* no creation data */ + if (((uintptr_t)data) & 2) + data++; - dlg->cy = y + 20; - - config_device = device; - - DialogBoxIndirect(hinstance, dlg, hwnd, deviceconfig_dlgproc); + config++; + } - free(data_block); + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; - return deviceconfig_changed; + 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; + + device_set_context(&config_device, device, inst); + + DialogBoxIndirect(hinstance, dlg, hwnd, deviceconfig_dlgproc); + + free(data_block); + + return deviceconfig_changed; +} + + +uint8_t +deviceconfig_open(HWND hwnd, const device_t *device) +{ + return deviceconfig_inst_open(hwnd, device, 0); } diff --git a/src/win/win_dialog.c b/src/win/win_dialog.c index b5c0167b4..729be881e 100644 --- a/src/win/win_dialog.c +++ b/src/win/win_dialog.c @@ -8,13 +8,13 @@ * * Several dialogs for the application. * - * Version: @(#)win_dialog.c 1.0.10 2018/04/29 + * Version: @(#)win_dialog.c 1.0.11 2019/09/22 * * Author: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #define UNICODE #include @@ -67,6 +67,11 @@ ui_msgbox(int flags, void *arg) fl = (MB_YESNOCANCEL | MB_ICONQUESTION); cap = plat_get_string(IDS_STRINGS); /* "86Box" */ break; + + case MBX_QUESTION_YN: /* question */ + fl = (MB_YESNO | MB_ICONQUESTION); + cap = plat_get_string(IDS_STRINGS); /* "86Box" */ + break; } /* If ANSI string, convert it. */ diff --git a/src/win/win_discord.c b/src/win/win_discord.c new file mode 100644 index 000000000..b402f10e8 --- /dev/null +++ b/src/win/win_discord.c @@ -0,0 +1,183 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Discord integration module. + * + * Version: @(#)win_discord.c 1.0.0 2019/12/05 + * + * Authors: David HrdliÄka, + * + * Copyright 2019 David HrdliÄka. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#ifdef USE_NEW_DYNAREC + #include "../cpu_new/cpu.h" +#else + #include "../cpu/cpu.h" +#endif +#include "../machine/machine.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "win_discord.h" +#include "discord_game_sdk.h" + +#define PATH_DISCORD_DLL "discord_game_sdk.dll" + +int discord_loaded = 0; + +static void *discord_handle = NULL; +static struct IDiscordCore *discord_core = NULL; +static struct IDiscordActivityManager *discord_activities = NULL; + +static enum EDiscordResult (*discord_create)(DiscordVersion version, struct DiscordCreateParams* params, struct IDiscordCore** result); + +static dllimp_t discord_imports[] = { + { "DiscordCreate", &discord_create }, + { NULL, NULL } +}; + +#ifndef ENABLE_DISCORD_LOG +int discord_do_log = 1; + + +static void +discord_log(const char *fmt, ...) +{ + va_list ap; + + if (discord_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define discord_log(fmt, ...) +#endif + +void +discord_update_activity(int paused) +{ + struct DiscordActivity activity; + wchar_t config_name_w[1024]; + char config_name[128]; + + if(discord_activities == NULL) + return; + + discord_log("win_discord: discord_update_activity(paused=%d)\n", paused); + + memset(&activity, 0x00, sizeof(activity)); + + plat_get_dirname(config_name_w, usr_path); + if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, plat_get_filename(config_name_w), -1, config_name, 128, NULL, NULL) > 0) + { + sprintf_s(activity.details, 128, "Running \"%s\"", config_name); + sprintf_s(activity.state, 128, "%s (%s)", strchr(machine_getname(), ']') + 2, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name); + } + else + { + strcpy(activity.details, strchr(machine_getname(), ']') + 2); + strcpy(activity.state, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name); + } + + activity.timestamps.start = time(NULL); + +#ifdef RELEASE_BUILD + strcpy(activity.assets.large_image, "86box-rb"); +#else + strcpy(activity.assets.large_image, "86box"); +#endif + + if (paused) + { + strcpy(activity.assets.small_image, "status-paused"); + strcpy(activity.assets.small_text, "Paused"); + } + else + { + strcpy(activity.assets.small_image, "status-running"); + strcpy(activity.assets.small_text, "Running"); + } + + discord_activities->update_activity(discord_activities, &activity, NULL, NULL); +} + +int +discord_load() +{ + if (discord_handle != NULL) + return(1); + + // Try to load the DLL + discord_handle = dynld_module(PATH_DISCORD_DLL, discord_imports); + + if (discord_handle == NULL) + { + discord_log("win_discord: couldn't load " PATH_DISCORD_DLL "\n"); + discord_close(); + + return(0); + } + + discord_loaded = 1; + return(1); +} + +void +discord_init() +{ + enum EDiscordResult result; + struct DiscordCreateParams params; + + if(discord_handle == NULL) + return; + + DiscordCreateParamsSetDefault(¶ms); + params.client_id = 651478134352248832; + params.flags = DiscordCreateFlags_NoRequireDiscord; + + result = discord_create(DISCORD_VERSION, ¶ms, &discord_core); + if (result != DiscordResult_Ok) + { + discord_log("win_discord: DiscordCreate returned %d\n", result); + discord_close(); + return; + } + + discord_activities = discord_core->get_activity_manager(discord_core); + + return; +} + +void +discord_close() +{ + if (discord_core != NULL) + discord_core->destroy(discord_core); + + discord_core = NULL; + discord_activities = NULL; +} + +void +discord_run_callbacks() +{ + if(discord_core == NULL) + return; + + discord_core->run_callbacks(discord_core); +} diff --git a/src/win/win_discord.h b/src/win/win_discord.h new file mode 100644 index 000000000..944ac8ff2 --- /dev/null +++ b/src/win/win_discord.h @@ -0,0 +1,28 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the Discord integration module. + * + * Version: @(#)win_discord.h 1.0.0 2019/12/05 + * + * Authors: David HrdliÄka, + * + * Copyright 2019 David HrdliÄka. + */ +#ifndef WIN_DISCORD_H +# define WIN_DISCORD_H + +extern int discord_loaded; + +extern int discord_load(); +extern void discord_init(); +extern void discord_close(); +extern void discord_update_activity(int paused); +extern void discord_run_callbacks(); + +#endif \ No newline at end of file diff --git a/src/win/win_dynld.c b/src/win/win_dynld.c index a8901c4fc..6043e36d6 100644 --- a/src/win/win_dynld.c +++ b/src/win/win_dynld.c @@ -8,7 +8,7 @@ * * Try to load a support DLL. * - * Version: @(#)win_dynld.c 1.0.7 2018/04/29 + * Version: @(#)win_dynld.c 1.0.8 2018/10/18 * * Author: Fred N. van Kempen, * @@ -28,13 +28,11 @@ #ifdef ENABLE_DYNLD_LOG int dynld_do_log = ENABLE_DYNLD_LOG; -#endif static void dynld_log(const char *fmt, ...) { -#ifdef ENABLE_DYNLD_LOG va_list ap; if (dynld_do_log) { @@ -42,8 +40,10 @@ dynld_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define dynld_log(fmt, ...) +#endif void * diff --git a/src/win/win_joystick.cpp b/src/win/win_joystick.cpp index 5cba358e1..d073cd37c 100644 --- a/src/win/win_joystick.cpp +++ b/src/win/win_joystick.cpp @@ -8,13 +8,13 @@ * * Joystick interface to host device. * - * Version: @(#)win_joystick.cpp 1.0.9 2018/04/29 + * Version: @(#)win_joystick.cpp 1.0.12 2019/10/23 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #define DIRECTINPUT_VERSION 0x0800 #include @@ -42,13 +42,11 @@ static GUID joystick_guids[MAX_JOYSTICKS]; #ifdef ENABLE_JOYSTICK_LOG int joystick_do_log = ENABLE_JOYSTICK_LOG; -#endif static void joystick_log(const char *fmt, ...) { -#ifdef ENABLE_JOYSTICK_LOG va_list ap; if (joystick_do_log) { @@ -56,8 +54,10 @@ joystick_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define joystick_log(fmt, ...) +#endif static BOOL CALLBACK joystick_enum_callback(LPCDIDEVICEINSTANCE lpddi, UNUSED(LPVOID data)) @@ -85,7 +85,7 @@ BOOL CALLBACK DIEnumDeviceObjectsCallback( 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)); + memcpy(state->axis[state->nr_axes].name, lpddoi->tszName, strlen(lpddoi->tszName) + 1); joystick_log("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; @@ -103,13 +103,13 @@ BOOL CALLBACK DIEnumDeviceObjectsCallback( } else if (lpddoi->guidType == GUID_Button) { - strncpy(state->button[state->nr_buttons].name, lpddoi->tszName, sizeof(state->button[state->nr_buttons].name)); + memcpy(state->button[state->nr_buttons].name, lpddoi->tszName, strlen(lpddoi->tszName) + 1); joystick_log("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)); + memcpy(state->pov[state->nr_povs].name, lpddoi->tszName, strlen(lpddoi->tszName) + 1); joystick_log("POV %i : %s %x %x\n", state->nr_povs, state->pov[state->nr_povs].name, lpddoi->dwOfs, lpddoi->dwType); state->nr_povs++; } @@ -121,8 +121,6 @@ void joystick_init() { int c; - if (joystick_type == 7) return; - atexit(joystick_close); joysticks_present = 0; @@ -155,7 +153,7 @@ void joystick_init() joystick_log("Joystick %i :\n", c); joystick_log(" tszInstanceName = %s\n", device_instance.tszInstanceName); joystick_log(" tszProductName = %s\n", device_instance.tszProductName); - strncpy(plat_joystick_state[c].name, device_instance.tszInstanceName, 64); + memcpy(plat_joystick_state[c].name, device_instance.tszInstanceName, strlen(device_instance.tszInstanceName) + 1); memset(&devcaps, 0, sizeof(devcaps)); devcaps.dwSize = sizeof(devcaps); diff --git a/src/win/win_joystick_xinput.cpp b/src/win/win_joystick_xinput.cpp new file mode 100644 index 000000000..6be292c13 --- /dev/null +++ b/src/win/win_joystick_xinput.cpp @@ -0,0 +1,262 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Xinput joystick interface. + * + * Version: @(#)win_joystick_xinput.cpp 1.0.0 2019/3/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * GH Cao, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2019 GH Cao. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../plat.h" +#include "../game/gameport.h" +#include "win.h" + +#define XINPUT_MAX_JOYSTICKS 4 +#define XINPUT_NAME "Xinput compatiable controller" +#define XINPUT_NAME_LX "Left Stick X" +#define XINPUT_NAME_LY "Left Stick Y" +#define XINPUT_NAME_RX "Right Stick X" +#define XINPUT_NAME_RY "Right Stick Y" +#define XINPUT_NAME_DPAD_X "D-pad X" +#define XINPUT_NAME_DPAD_Y "D-pad Y" +#define XINPUT_NAME_LB "LB" +#define XINPUT_NAME_RB "RB" +#define XINPUT_NAME_LT "LT" +#define XINPUT_NAME_RT "RT" +#define XINPUT_NAME_A "A" +#define XINPUT_NAME_B "B" +#define XINPUT_NAME_X "X" +#define XINPUT_NAME_Y "Y" +#define XINPUT_NAME_BACK "Back/View" +#define XINPUT_NAME_START "Start/Menu" +#define XINPUT_NAME_LS "Left Stick" +#define XINPUT_NAME_RS "Right Stick" + +#ifdef ENABLE_JOYSTICK_LOG +int joystick_do_log = ENABLE_JOYSTICK_LOG; + + +static void +joystick_log(const char *fmt, ...) +{ + va_list ap; + + if (joystick_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define joystick_log(fmt, ...) +#endif + +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; +int joysticks_present = 0; + +XINPUT_STATE controllers[XINPUT_MAX_JOYSTICKS]; + +void joystick_init() +{ + int c; + + atexit(joystick_close); + + joysticks_present = 0; + + memset(controllers, 0, sizeof(XINPUT_STATE) * XINPUT_MAX_JOYSTICKS); + + for (c=0; c 127) ? 128 : 0; + plat_joystick_state[c].b[7] = (controllers[c].Gamepad.bRightTrigger > 127) ? 128 : 0; + plat_joystick_state[c].b[8] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_BACK) ? 128 : 0; + plat_joystick_state[c].b[9] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 128 : 0; + plat_joystick_state[c].b[10] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) ? 128 : 0; + plat_joystick_state[c].b[11] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) ? 128 : 0; + + int dpad_x = 0, dpad_y = 0; + if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) + dpad_y-=32767; + if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) + dpad_y+=32767; + if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) + dpad_x-=32767; + if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) + dpad_x+=32767; + + plat_joystick_state[c].a[2] = dpad_x; + plat_joystick_state[c].a[5] = dpad_y; + + for (int a=0; a<8; a++) { + if (plat_joystick_state[c].a[a] == -32768) + plat_joystick_state[c].a[a] = -32767; + if (plat_joystick_state[c].a[a] == 32768) + plat_joystick_state[c].a[a] = 32767; + } + } +} + +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_process(void) +{ + int c, d; + + if (joystick_type == 7) return; + + joystick_poll(); + + 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/win_jsconf.c b/src/win/win_jsconf.c index 39a02740b..1ca6f5ef8 100644 --- a/src/win/win_jsconf.c +++ b/src/win/win_jsconf.c @@ -29,6 +29,7 @@ static void rebuild_axis_button_selections(HWND hdlg) HWND h; int joystick; int c, d; + char s[269]; h = GetDlgItem(hdlg, IDC_CONFIG_BASE); joystick = SendMessage(h, CB_GETCURSEL, 0, 0); @@ -53,8 +54,6 @@ static void rebuild_axis_button_selections(HWND hdlg) } 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); @@ -98,8 +97,6 @@ static void rebuild_axis_button_selections(HWND hdlg) { 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); @@ -153,7 +150,7 @@ static int get_pov(HWND hdlg, int id) return axis_sel - nr_povs; } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -294,6 +291,7 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) int y = 10; int id = IDC_CONFIG_BASE; int c; + char s[269]; joystickconfig_changed = 0; @@ -462,8 +460,6 @@ uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) for (c = 0; c < joystick_get_pov_count(type)*2; c++) { - char s[80]; - /*Combo box*/ item = (DLGITEMTEMPLATE *)data; item->x = 70; diff --git a/src/win/win_keyboard.c b/src/win/win_keyboard.c index 7c08f6ca9..eaf4ddac4 100644 --- a/src/win/win_keyboard.c +++ b/src/win/win_keyboard.c @@ -39,17 +39,16 @@ static uint16_t scancode_map[768]; static UINT16 convert_scan_code(UINT16 scan_code) { - if ((scan_code & 0xFF00) == 0xE000) { - scan_code &= 0x00FF; - scan_code |= 0x0100; - } else if (scan_code == 0xE11D) - scan_code = 0xE000; + if ((scan_code & 0xff00) == 0xe000) + scan_code = (scan_code & 0xff) | 0x0100; + + if (scan_code == 0xE11D) + scan_code = 0x0100; /* E0 00 is sent by some USB keyboards for their special keys, as it is an invalid scan code (it has no untranslated set 2 equivalent), we mark it appropriately so it does not get passed through. */ - else if ((scan_code > 0x00FF) || (scan_code == 0xE000)) { + else if ((scan_code > 0x01FF) || (scan_code == 0x0100)) scan_code = 0xFFFF; - } return scan_code; } @@ -138,12 +137,14 @@ keyboard_handle(LPARAM lParam, int infocus) /* 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); + scancode |= 0x100; /* Translate the scan code to 9-bit */ scancode = convert_scan_code(scancode); /* Remap it according to the list from the Registry */ + if (scancode != scancode_map[scancode]) + pclog("Scan code remap: %03X -> %03X\n", scancode, scancode); scancode = scancode_map[scancode]; /* If it's not 0xFFFF, send it to the emulated diff --git a/src/win/win_midi.c b/src/win/win_midi.c index 6df91ca5d..256ab6a5e 100644 --- a/src/win/win_midi.c +++ b/src/win/win_midi.c @@ -11,117 +11,242 @@ #include "../plat_midi.h" -int midi_id = 0; -HANDLE m_event; - -static HMIDIOUT midi_out_device = NULL; -static uint8_t midi_rt_buf[1024]; -static uint8_t midi_cmd_buf[1024]; -static int midi_cmd_pos = 0; -static int midi_cmd_len = 0; -static uint8_t midi_status = 0; -static unsigned int midi_sysex_start = 0; -static unsigned int midi_sysex_delay = 0; - -void plat_midi_init() +typedef struct { - /* This is for compatibility with old configuration files. */ - midi_id = config_get_int("Sound", "midi_host_device", -1); - if (midi_id == -1) - { - midi_id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); - } - else - { - config_delete_var("Sound", "midi_host_device"); - config_set_int(SYSTEM_MIDI_NAME, "midi", midi_id); - } + int midi_id, midi_input_id; - MMRESULT hr = MMSYSERR_NOERROR; + HANDLE m_event; - memset(midi_rt_buf, 0, sizeof(midi_rt_buf)); - memset(midi_cmd_buf, 0, sizeof(midi_cmd_buf)); + HMIDIOUT midi_out_device; + HMIDIIN midi_in_device; - midi_cmd_pos = midi_cmd_len = 0; - midi_status = 0; + MIDIHDR m_hdr; +} plat_midi_t; - midi_sysex_start = midi_sysex_delay = 0; +plat_midi_t *pm = NULL, *pm_in = NULL; - m_event = CreateEvent(NULL, TRUE, TRUE, NULL); - hr = midiOutOpen(&midi_out_device, midi_id, (uintptr_t) m_event, - 0, CALLBACK_EVENT); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n",hr); - midi_id = 0; - hr = midiOutOpen(&midi_out_device, midi_id, (uintptr_t) m_event, - 0, CALLBACK_EVENT); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n",hr); - return; - } - } - - midiOutReset(midi_out_device); -} - -void plat_midi_close() +void +plat_midi_init(void) { - if (midi_out_device != NULL) - { - midiOutReset(midi_out_device); - midiOutClose(midi_out_device); - /* midi_out_device = NULL; */ - CloseHandle(m_event); - } -} + MMRESULT hr; -int plat_midi_get_num_devs() -{ - return midiOutGetNumDevs(); -} -void plat_midi_get_dev_name(int num, char *s) -{ - MIDIOUTCAPS caps; + pm = (plat_midi_t *) malloc(sizeof(plat_midi_t)); + memset(pm, 0, sizeof(plat_midi_t)); - midiOutGetDevCaps(num, &caps, sizeof(caps)); - strcpy(s, caps.szPname); -} + pm->midi_id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); -void plat_midi_play_msg(uint8_t *msg) -{ - midiOutShortMsg(midi_out_device, *(uint32_t *) msg); -} + hr = MMSYSERR_NOERROR; -MIDIHDR m_hdr; + pm->m_event = CreateEvent(NULL, TRUE, TRUE, NULL); -void plat_midi_play_sysex(uint8_t *sysex, unsigned int len) -{ - MMRESULT result; - - if (WaitForSingleObject(m_event, 2000) == WAIT_TIMEOUT) - return; - - midiOutUnprepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); - - m_hdr.lpData = (char *) sysex; - m_hdr.dwBufferLength = len; - m_hdr.dwBytesRecorded = len; - m_hdr.dwUser = 0; - - result = midiOutPrepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); - - if (result != MMSYSERR_NOERROR) return; - ResetEvent(m_event); - result = midiOutLongMsg(midi_out_device, &m_hdr, sizeof(m_hdr)); - if (result != MMSYSERR_NOERROR) - { - SetEvent(m_event); + hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, + (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n", hr); + pm->midi_id = 0; + hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, + (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n", hr); return; } + } + + midiOutReset(pm->midi_out_device); } -int plat_midi_write(uint8_t val) + +void +plat_midi_close(void) { - return 0; + if (pm) { + if (pm->midi_out_device != NULL) { + midiOutReset(pm->midi_out_device); + midiOutClose(pm->midi_out_device); + CloseHandle(pm->m_event); + } + + free(pm); + pm = NULL; + } } + + +int +plat_midi_get_num_devs(void) +{ + return midiOutGetNumDevs(); +} + + +void +plat_midi_get_dev_name(int num, char *s) +{ + MIDIOUTCAPS caps; + + midiOutGetDevCaps(num, &caps, sizeof(caps)); + strcpy(s, caps.szPname); +} + + +void +plat_midi_play_msg(uint8_t *msg) +{ + if (!pm) + return; + + midiOutShortMsg(pm->midi_out_device, *(uint32_t *) msg); +} + + +void +plat_midi_play_sysex(uint8_t *sysex, unsigned int len) +{ + MMRESULT result; + + if (!pm) + return; + + if (WaitForSingleObject(pm->m_event, 2000) == WAIT_TIMEOUT) + return; + + midiOutUnprepareHeader(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); + + pm->m_hdr.lpData = (char *) sysex; + pm->m_hdr.dwBufferLength = len; + pm->m_hdr.dwBytesRecorded = len; + pm->m_hdr.dwUser = 0; + + result = midiOutPrepareHeader(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); + + if (result != MMSYSERR_NOERROR) + return; + ResetEvent(pm->m_event); + result = midiOutLongMsg(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); + if (result != MMSYSERR_NOERROR) { + SetEvent(pm->m_event); + return; + } +} + + +int +plat_midi_write(uint8_t val) +{ + return 0; +} + +void CALLBACK +plat_midi_in_callback(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + uint8_t msg[4] = {((dwParam1&0xff)),(((dwParam1&0xff00)>>8)), + (((dwParam1&0xff0000)>>16)),MIDI_evt_len[((dwParam1&0xff))]}; + uint8_t *sysex; + uint32_t len; + int cnt; + MIDIHDR *hdr; + switch (wMsg) { + case MM_MIM_DATA: /* 0x3C3 - midi message */ + input_msg(midi_in_p, msg); + break; + case MM_MIM_OPEN: /* 0x3C1 */ + break; + case MM_MIM_CLOSE: /* 0x3C2 */ + break; + case MM_MIM_LONGDATA: /* 0x3C4 - sysex */ + hdr = (MIDIHDR *)dwParam1; + sysex = (uint8_t *)hdr->lpData; + len = (uint32_t)hdr->dwBytesRecorded; + cnt = 5; + while (cnt) { /*abort if timed out*/ + int ret = input_sysex(midi_in_p, sysex, len, 0); + if (!ret) { + len = 0; + break; + } + if (len==ret) + cnt--; + else + cnt = 5; + sysex += len-ret; + len = ret; + Sleep(5);/*msec*/ + } + if (len) + input_sysex(midi_in_p, sysex, 0, 0); + + midiInUnprepareHeader(hMidiIn, hdr, sizeof(*hdr)); + hdr->dwBytesRecorded = 0; + midiInPrepareHeader(hMidiIn, hdr, sizeof(*hdr)); + break; + case MM_MIM_ERROR: + case MM_MIM_LONGERROR: + break; + default: + break; + } +} + +void +plat_midi_input_init(void) +{ + MMRESULT hr; + + pm_in = (plat_midi_t *) malloc(sizeof(plat_midi_t)); + memset(pm_in, 0, sizeof(plat_midi_t)); + + pm_in->midi_input_id = config_get_int(MIDI_INPUT_NAME, "midi_input", 0); + + hr = MMSYSERR_NOERROR; + + hr = midiInOpen(&pm_in->midi_in_device, pm_in->midi_input_id, + (uintptr_t) plat_midi_in_callback, 0, CALLBACK_FUNCTION); + if (hr != MMSYSERR_NOERROR) { + printf("midiInOpen error - %08X\n", hr); + pm_in->midi_input_id = 0; + hr = midiInOpen(&pm_in->midi_in_device, pm_in->midi_input_id, + (uintptr_t) plat_midi_in_callback, 0, CALLBACK_FUNCTION); + if (hr != MMSYSERR_NOERROR) { + printf("midiInOpen error - %08X\n", hr); + return; + } + } + + pm_in->m_hdr.lpData = (char*)&MIDI_InSysexBuf[0]; + pm_in->m_hdr.dwBufferLength = SYSEX_SIZE; + pm_in->m_hdr.dwBytesRecorded = 0; + pm_in->m_hdr.dwUser = 0; + midiInPrepareHeader(pm_in->midi_in_device,&pm_in->m_hdr,sizeof(pm_in->m_hdr)); + midiInStart(pm_in->midi_in_device); +} + +void +plat_midi_input_close(void) +{ + if (pm_in) { + if (pm_in->midi_in_device != NULL) { + midiInStop(pm_in->midi_in_device); + midiInClose(pm_in->midi_in_device); + } + + free(pm_in); + pm_in = NULL; + } +} + +int +plat_midi_in_get_num_devs(void) +{ + return midiInGetNumDevs(); +} + + +void +plat_midi_in_get_dev_name(int num, char *s) +{ + MIDIINCAPS caps; + + midiInGetDevCaps(num, &caps, sizeof(caps)); + strcpy(s, caps.szPname); +} \ No newline at end of file diff --git a/src/win/win_mouse.c b/src/win/win_mouse.c new file mode 100644 index 000000000..2ca004e9f --- /dev/null +++ b/src/win/win_mouse.c @@ -0,0 +1,161 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * RawInput mouse interface. + * + * Version: @(#)win_mouse_rawinput.cpp 1.0.0 2019/3/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * GH Cao, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + * Copyright 2019 GH Cao. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mouse.h" +#include "../plat.h" +#include "win.h" + +int mouse_capture; + +typedef struct { + int buttons; + int dx; + int dy; + int dwheel; +} MOUSESTATE; + +MOUSESTATE mousestate; + +void +win_mouse_init(void) +{ + atexit(win_mouse_close); + + mouse_capture = 0; + + /* Initialize the RawInput (mouse) module. */ + RAWINPUTDEVICE ridev; + ridev.dwFlags = 0; + ridev.hwndTarget = NULL; + ridev.usUsagePage = 0x01; + ridev.usUsage = 0x02; + if (! RegisterRawInputDevices(&ridev, 1, sizeof(ridev))) + fatal("plat_mouse_init: RegisterRawInputDevices failed\n"); + + memset(&mousestate, 0, sizeof(MOUSESTATE)); +} + +void +win_mouse_handle(LPARAM lParam, int infocus) +{ + uint32_t ri_size = 0; + UINT size; + RAWINPUT *raw; + RAWMOUSE state; + static int x, y; + + if (! infocus) return; + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, + &size, sizeof(RAWINPUTHEADER)); + + raw = (RAWINPUT*)malloc(size); + if (raw == NULL) return; + + /* Here we read the raw input data for the mouse */ + ri_size = GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, + raw, &size, sizeof(RAWINPUTHEADER)); + if (ri_size != size) goto err; + + /* If the input is not a mouse, we ignore it */ + if (raw->header.dwType != RIM_TYPEMOUSE) goto err; + + state = raw->data.mouse; + + /* read mouse buttons and wheel */ + if (state.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) + mousestate.buttons |= 1; + else if (state.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) + mousestate.buttons &= ~1; + + if (state.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) + mousestate.buttons |= 4; + else if (state.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) + mousestate.buttons &= ~4; + + if (state.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) + mousestate.buttons |= 2; + else if (state.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) + mousestate.buttons &= ~2; + + if (state.usButtonFlags & RI_MOUSE_WHEEL) { + mousestate.dwheel += (SHORT)state.usButtonData / 120; + } + + + if (state.usFlags & MOUSE_MOVE_ABSOLUTE) { + /* absolute mouse, i.e. RDP or VNC + * seems to work fine for RDP on Windows 10 + * Not sure about other environments. + */ + x=state.lLastX, y=state.lLastY; + mousestate.dx += (state.lLastX - x)/100; + mousestate.dy += (state.lLastY - y)/100; + x=state.lLastX; + y=state.lLastY; + } else { + /* relative mouse, i.e. regular mouse */ + mousestate.dx += state.lLastX; + mousestate.dy += state.lLastY; + } + + err: + free(raw); +} + +void +win_mouse_close(void) +{ + RAWINPUTDEVICE ridev; + ridev.dwFlags = RIDEV_REMOVE; + ridev.hwndTarget = NULL; + ridev.usUsagePage = 0x01; + ridev.usUsage = 0x02; + RegisterRawInputDevices(&ridev, 1, sizeof(ridev)); +} + +void +mouse_poll(void) +{ + static int b = 0; + if (mouse_capture || video_fullscreen) { + if (mousestate.dx != 0 || mousestate.dy != 0 || mousestate.dwheel != 0) { + mouse_x += mousestate.dx; + mouse_y += mousestate.dy; + mouse_z = mousestate.dwheel; + + mousestate.dx=0; + mousestate.dy=0; + mousestate.dwheel=0; + + //pclog("dx=%d, dy=%d, dwheel=%d\n", mouse_x, mouse_y, mouse_z); + } + + if (b != mousestate.buttons) { + mouse_buttons = mousestate.buttons; + b = mousestate.buttons; + } + } +} diff --git a/src/win/win_mouse.cpp b/src/win/win_mouse.cpp deleted file mode 100644 index 5fab0ad9f..000000000 --- a/src/win/win_mouse.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Mouse interface to host device. - * - * Version: @(#)win_mouse.cpp 1.0.6 2017/11/25 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. - */ -#define DIRECTINPUT_VERSION 0x0800 -#include -#include -#include -#include "../86Box.h" -#include "../mouse.h" -#include "../plat.h" -#include "win.h" - - -int mouse_capture; - - -static LPDIRECTINPUT8 lpdi; -static LPDIRECTINPUTDEVICE8 lpdi_mouse = NULL; -static DIMOUSESTATE mousestate; - - -void -win_mouse_init(void) -{ - atexit(win_mouse_close); - - mouse_capture = 0; - - if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, - IID_IDirectInput8A, (void **) &lpdi, NULL))) - fatal("plat_mouse_init: DirectInputCreate failed\n"); - - if (FAILED(lpdi->CreateDevice(GUID_SysMouse, &lpdi_mouse, NULL))) - fatal("plat_mouse_init: CreateDevice failed\n"); - - if (FAILED(lpdi_mouse->SetCooperativeLevel(hwndMain, - DISCL_FOREGROUND | (video_fullscreen ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE)))) - fatal("plat_mouse_init: SetCooperativeLevel failed\n"); - - if (FAILED(lpdi_mouse->SetDataFormat(&c_dfDIMouse))) - fatal("plat_mouse_init: SetDataFormat failed\n"); -} - - -void -win_mouse_close(void) -{ - if (lpdi_mouse != NULL) { - lpdi_mouse->Release(); - lpdi_mouse = NULL; - } -} - - -void -mouse_poll(void) -{ - static int buttons = 0; - static int x = 0, y = 0, z = 0; - int b; - - if (FAILED(lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), - (LPVOID)&mousestate))) { - lpdi_mouse->Acquire(); - lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate); - } - - if (mouse_capture || video_fullscreen) { - if (x != mousestate.lX || y != mousestate.lY || z != mousestate.lZ) { - mouse_x += mousestate.lX; - mouse_y += mousestate.lY; - mouse_z += mousestate.lZ/120; - - x = mousestate.lX; - y = mousestate.lY; - z = mousestate.lZ/120; - } - - b = 0; - if (mousestate.rgbButtons[0] & 0x80) b |= 1; - if (mousestate.rgbButtons[1] & 0x80) b |= 2; - if (mousestate.rgbButtons[2] & 0x80) b |= 4; - if (buttons != b) { - mouse_buttons = b; - buttons = b; - } - } -} diff --git a/src/win/win_new_floppy.c b/src/win/win_new_floppy.c index a7954672b..0dff080c9 100644 --- a/src/win/win_new_floppy.c +++ b/src/win/win_new_floppy.c @@ -8,11 +8,11 @@ * * Handle the New Floppy Image dialog. * - * Version: @(#)win_new_floppy.c 1.0.8 2018/05/25 + * Version: @(#)win_new_floppy.c 1.0.13 2019/11/19 * * Authors: Miran Grca, * - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. */ #define UNICODE #define BITMAP WINDOWS_BITMAP @@ -29,7 +29,7 @@ #include "../plat.h" #include "../random.h" #include "../ui.h" -#include "../scsi/scsi.h" +#include "../scsi/scsi_device.h" #include "../disk/zip.h" #include "win.h" @@ -75,7 +75,7 @@ create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) FILE *f; uint32_t magic = 0x46423638; - uint16_t version = 0x020B; + uint16_t version = 0x020C; uint16_t dflags = 0; uint16_t tflags = 0; uint32_t index_hole_pos = 0; @@ -267,9 +267,7 @@ create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) empty[0x38] = 'T'; empty[0x39] = '1'; empty[0x3A] = '2'; - empty[0x3B] = ' '; - empty[0x3C] = ' '; - empty[0x3D] = ' '; + memset(&(empty[0x3B]), 0x20, 0x0003); empty[0x1FE] = 0x55; empty[0x1FF] = 0xAA; @@ -304,6 +302,7 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, uint16_t base = 0x1000; uint32_t pbar_max = 0; uint32_t i; + MSG msg; f = plat_fopen(file_name, L"wb"); if (!f) @@ -371,40 +370,28 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, if (total_sectors == ZIP_SECTORS) { /* ZIP 100 */ /* MBR */ - *(uint64_t *) &(empty[0x0000]) = 0x0000030000025245LL; - *(uint64_t *) &(empty[0x0008]) = 0x0000000000000000LL; - *(uint64_t *) &(empty[0x0010]) = 0x0900E90300000100LL; - *(uint64_t *) &(empty[0x0018]) = 0x726F70726F430100LL; + *(uint64_t *) &(empty[0x0000]) = 0x2054524150492EEBLL; + *(uint64_t *) &(empty[0x0008]) = 0x3930302065646F63LL; + *(uint64_t *) &(empty[0x0010]) = 0x67656D6F49202D20LL; + *(uint64_t *) &(empty[0x0018]) = 0x726F70726F432061LL; *(uint64_t *) &(empty[0x0020]) = 0x202D206E6F697461LL; *(uint64_t *) &(empty[0x0028]) = 0x30392F33322F3131LL; - *(uint64_t *) &(empty[0x01AE]) = 0x0116010100E905E2LL; - *(uint64_t *) &(empty[0x01B6]) = 0x226BEDCE014E0135LL; - *(uint64_t *) &(empty[0x01BE]) = 0x5E203F0600010180LL; - *(uint64_t *) &(empty[0x01C6]) = 0x0002FE6000000020LL; + *(uint64_t *) &(empty[0x01AE]) = 0x0116010100E90644LL; + *(uint64_t *) &(empty[0x01B6]) = 0xED08BBE5014E0135LL; + *(uint64_t *) &(empty[0x01BE]) = 0xFFFFFE06FFFFFE80LL; + *(uint64_t *) &(empty[0x01C6]) = 0x0002FFE000000020LL; *(uint16_t *) &(empty[0x01FE]) = 0xAA55; - /* 4 sectors filled with 0xFA */ - memset(&(empty[0x0200]), 0xFA, 0x0800); - - /* Iomega_Reserved sector */ - *(uint64_t *) &(empty[0x0A00]) = 0x0500000000004D50LL; - *(uint64_t *) &(empty[0x0A08]) = 0xAFF9010051060100LL; - - *(uint64_t *) &(empty[0x0A30]) = 0x525F6167656D6F49LL; - *(uint64_t *) &(empty[0x0A38]) = 0x0064657672657365LL; - - *(uint64_t *) &(empty[0x0A54]) = 0x03000000AFF90100LL; - - /* 26 sectors filled with 0x48 */ - memset(&(empty[0x0C00]), 0x48, 0x3400); + /* 31 sectors filled with 0x48 */ + memset(&(empty[0x0200]), 0x48, 0x3E00); /* Boot sector */ *(uint64_t *) &(empty[0x4000]) = 0x584F4236389058EBLL; - *(uint64_t *) &(empty[0x4008]) = 0x0001040200302E35LL; + *(uint64_t *) &(empty[0x4008]) = 0x0008040200302E35LL; *(uint64_t *) &(empty[0x4010]) = 0x00C0F80000020002LL; - *(uint64_t *) &(empty[0x4018]) = 0x0000002000400020LL; + *(uint64_t *) &(empty[0x4018]) = 0x0000002000FF003FLL; *(uint32_t *) &(empty[0x4020]) = 0x0002FFE0; *(uint16_t *) &(empty[0x4024]) = 0x0080; @@ -422,17 +409,18 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, empty[0x4038] = 'T'; empty[0x4039] = '1'; empty[0x403A] = '6'; + memset(&(empty[0x403B]), 0x20, 0x0003); empty[0x41FE] = 0x55; empty[0x41FF] = 0xAA; - empty[0x4200] = empty[0x1C200] = empty[0x4015]; - empty[0x4201] = empty[0x1C201] = 0xFF; - empty[0x4202] = empty[0x1C202] = 0xFF; - empty[0x4203] = empty[0x1C203] = 0xFF; + empty[0x5000] = empty[0x1D000] = empty[0x4015]; + empty[0x5001] = empty[0x1D001] = 0xFF; + empty[0x5002] = empty[0x1D002] = 0xFF; + empty[0x5003] = empty[0x1D003] = 0xFF; - /* Root directory = 0x34200 - Data = 0x38200 */ + /* Root directory = 0x35000 + Data = 0x39000 */ } else { /* ZIP 250 */ /* MBR */ @@ -492,6 +480,7 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, empty[0x4038] = 'T'; empty[0x4039] = '1'; empty[0x403A] = '6'; + memset(&(empty[0x403B]), 0x20, 0x0003); empty[0x41FE] = 0x55; empty[0x41FF] = 0xAA; @@ -508,6 +497,11 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, for (i = 0; i < pbar_max; i++) { fwrite(&empty[i << 11], 1, 2048, f); SendMessage(h, PBM_SETPOS, (WPARAM) i + 2, (LPARAM) 0); + + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } } free(empty); @@ -542,7 +536,7 @@ new_floppy_msgbox(HWND hwnd, int type, void *arg) } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index 8fafd7e54..762f4c5db 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -12,13 +12,13 @@ * we will not use that, but, instead, use a new window which * coverrs the entire desktop. * - * Version: @(#)win_sdl.c 1.0.0 2018/05/26 + * Version: @(#)win_sdl.c 1.0.10 2019/12/06 * * Authors: Fred N. van Kempen, * Michael Drüing, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2018 Michael Drüing. + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2018,2019 Michael Drüing. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -55,26 +55,27 @@ #include #include -#define PNG_DEBUG 0 -#include - #include #include #include #include +/* This #undef is needed because a SDL include header redefines HAVE_STDARG_H. */ +#undef HAVE_STDARG_H +#define HAVE_STDARG_H #include "../86box.h" #include "../device.h" #include "../plat.h" #include "../plat_dynld.h" #include "../video/video.h" +#include "../ui.h" #include "win.h" #include "win_sdl.h" -#define PATH_SDL_DLL "sdl2.dll" +#define RENDERER_FULL_SCREEN 1 +#define RENDERER_HARDWARE 2 -static void *sdl_handle = NULL; /* handle to libSDL2 DLL */ static SDL_Window *sdl_win = NULL; static SDL_Renderer *sdl_render = NULL; static SDL_Texture *sdl_tex = NULL; @@ -83,76 +84,17 @@ static HWND sdl_hwnd = NULL; static int sdl_w, sdl_h; static int sdl_fs; static int cur_w, cur_h; - -static png_structp png_ptr; -static png_infop info_ptr; - - -/* Pointers to the real functions. */ -static void (*sdl_GetVersion)(SDL_version *ver); -static char *const (*sdl_GetError)(void); -static int (*sdl_Init)(Uint32 flags); -static void (*sdl_Quit)(void); -static SDL_Window *(*sdl_CreateWindowFrom)(const void *data); -static void (*sdl_DestroyWindow)(SDL_Window *window); -static SDL_Renderer *(*sdl_CreateRenderer)(SDL_Window *window, - int index, Uint32 flags); -static void (*sdl_DestroyRenderer)(SDL_Renderer *renderer); -static SDL_Texture *(*sdl_CreateTexture)(SDL_Renderer *renderer, - Uint32 format, int access, - int w, int h); -static void (*sdl_DestroyTexture)(SDL_Texture *texture); -static int (*sdl_LockTexture)(SDL_Texture *texture, - const SDL_Rect *rect, - void **pixels, int *pitch); -static void (*sdl_UnlockTexture)(SDL_Texture *texture); -static int (*sdl_RenderCopy)(SDL_Renderer *renderer, - SDL_Texture *texture, - const SDL_Rect *srcrect, - const SDL_Rect *dstrect); -static void (*sdl_RenderPresent)(SDL_Renderer *renderer); -static void (*sdl_GetWindowSize)(SDL_Window* window, - int* w, - int* h); -static int (*sdl_RenderReadPixels)(SDL_Renderer* renderer, - const SDL_Rect* rect, - Uint32 format, - void* pixels, - int pitch); -static SDL_bool (*sdl_SetHint)(const char* name, - const char* value); - -static dllimp_t sdl_imports[] = { - { "SDL_GetVersion", &sdl_GetVersion }, - { "SDL_GetError", &sdl_GetError }, - { "SDL_Init", &sdl_Init }, - { "SDL_Quit", &sdl_Quit }, - { "SDL_CreateWindowFrom", &sdl_CreateWindowFrom }, - { "SDL_DestroyWindow", &sdl_DestroyWindow }, - { "SDL_CreateRenderer", &sdl_CreateRenderer }, - { "SDL_DestroyRenderer", &sdl_DestroyRenderer }, - { "SDL_CreateTexture", &sdl_CreateTexture }, - { "SDL_DestroyTexture", &sdl_DestroyTexture }, - { "SDL_LockTexture", &sdl_LockTexture }, - { "SDL_UnlockTexture", &sdl_UnlockTexture }, - { "SDL_RenderCopy", &sdl_RenderCopy }, - { "SDL_RenderPresent", &sdl_RenderPresent }, - { "SDL_GetWindowSize", &sdl_GetWindowSize }, - { "SDL_RenderReadPixels", &sdl_RenderReadPixels }, - { "SDL_SetHint", &sdl_SetHint }, - { NULL, NULL } -}; +static volatile int sdl_enabled = 0; +static SDL_mutex* sdl_mutex = NULL; #ifdef ENABLE_SDL_LOG int sdl_do_log = ENABLE_SDL_LOG; -#endif static void sdl_log(const char *fmt, ...) { -#ifdef ENABLE_SDL_LOG va_list ap; if (sdl_do_log) { @@ -160,8 +102,10 @@ sdl_log(const char *fmt, ...) pclog_ex(fmt, ap); va_end(ap); } -#endif } +#else +#define sdl_log(fmt, ...) +#endif static void @@ -177,33 +121,31 @@ sdl_stretch(int *w, int *h, int *x, int *y) *y = 0; break; case FULLSCR_SCALE_43: + case FULLSCR_SCALE_KEEPRATIO: dw = (double) sdl_w; dh = (double) sdl_h; - temp = (dh / 3.0) * 4.0; - dx = (dw - temp) / 2.0; - dw = temp; - *w = (int) dw; - *h = (int) dh; - *x = (int) dx; - *y = 0; - break; - case FULLSCR_SCALE_SQ: - dw = (double) sdl_w; - dh = (double) sdl_h; - temp = ((double) *w); - temp2 = ((double) *h); - dx = (dw / 2.0) - ((dh * temp) / (temp2 * 2.0)); - dy = 0.0; - if (dx < 0.0) { - dx = 0.0; - dy = (dw / 2.0) - ((dh * temp2) / (temp * 2.0)); + hsr = dw / dh; + if (video_fullscreen_scale == FULLSCR_SCALE_43) + gsr = 4.0 / 3.0; + else + gsr = ((double) *w) / ((double) *h); + if (gsr <= hsr) { + temp = dh * gsr; + dx = (dw - temp) / 2.0; + dw = temp; + *w = (int) dw; + *h = (int) dh; + *x = (int) dx; + *y = 0; + } else { + temp = dw / gsr; + dy = (dh - temp) / 2.0; + dh = temp; + *w = (int) dw; + *h = (int) dh; + *x = 0; + *y = (int) dy; } - dw -= (dx * 2.0); - dh -= (dy * 2.0); - *w = (int) dw; - *h = (int) dh; - *x = (int) dx; - *y = (int) dy; break; case FULLSCR_SCALE_INT: dw = (double) sdl_w; @@ -223,29 +165,6 @@ sdl_stretch(int *w, int *h, int *x, int *y) *x = (int) dx; *y = (int) dy; break; - case FULLSCR_SCALE_KEEPRATIO: - dw = (double) sdl_w; - dh = (double) sdl_h; - hsr = dw / dh; - gsr = ((double) *w) / ((double) *h); - if (gsr <= hsr) { - temp = dh * gsr; - dx = (dw - temp) / 2.0; - dw = temp; - *w = (int) dw; - *h = (int) dh; - *x = (int) dx; - *y = 0; - } else { - temp = dw / gsr; - dy = (dh - temp) / 2.0; - dh = temp; - *w = (int) dw; - *h = (int) dh; - *x = 0; - *y = (int) dy; - } - break; } } @@ -258,41 +177,44 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) int pitch; int yy, ret; - if (y1 == y2) { + if (!sdl_enabled) { video_blit_complete(); return; } - if (buffer32 == NULL) { + if ((y1 == y2) || (h <= 0)) { video_blit_complete(); return; } + if (render_buffer == NULL) { + video_blit_complete(); + return; + } + + SDL_LockMutex(sdl_mutex); + /* * TODO: * SDL_UpdateTexture() might be better here, as it is * (reportedly) slightly faster. */ - sdl_LockTexture(sdl_tex, 0, &pixeldata, &pitch); + SDL_LockTexture(sdl_tex, 0, &pixeldata, &pitch); for (yy = y1; yy < y2; yy++) { - if ((y + yy) >= 0 && (y + yy) < buffer32->h) { - if (video_grayscale || invert_display) - video_transform_copy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w); - else - memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); - } + if ((y + yy) >= 0 && (y + yy) < render_buffer->h) + memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(render_buffer->line[y + yy][x]), w * 4); } video_blit_complete(); - sdl_UnlockTexture(sdl_tex); + SDL_UnlockTexture(sdl_tex); if (sdl_fs) { - pclog("sdl_blit(%i, %i, %i, %i, %i, %i) (%i, %i)\n", x, y, y1, y2, w, h, unscaled_size_x, efscrnsz_y); + sdl_log("sdl_blit(%i, %i, %i, %i, %i, %i) (%i, %i)\n", x, y, y1, y2, w, h, unscaled_size_x, efscrnsz_y); if (w == unscaled_size_x) sdl_resize(w, h); - pclog("(%08X, %08X, %08X)\n", sdl_win, sdl_render, sdl_tex); + sdl_log("(%08X, %08X, %08X)\n", sdl_win, sdl_render, sdl_tex); } r_src.x = 0; @@ -300,11 +222,13 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) r_src.w = w; r_src.h = h; - ret = sdl_RenderCopy(sdl_render, sdl_tex, &r_src, 0); + ret = SDL_RenderCopy(sdl_render, sdl_tex, &r_src, 0); if (ret) sdl_log("SDL: unable to copy texture to renderer (%s)\n", sdl_GetError()); - sdl_RenderPresent(sdl_render); + SDL_RenderPresent(sdl_render); + + SDL_UnlockMutex(sdl_mutex); } @@ -314,18 +238,26 @@ sdl_close(void) /* Unregister our renderer! */ video_setblit(NULL); + if (sdl_enabled) + sdl_enabled = 0; + + if (sdl_mutex != NULL) { + SDL_DestroyMutex(sdl_mutex); + sdl_mutex = NULL; + } + if (sdl_tex != NULL) { - sdl_DestroyTexture(sdl_tex); + SDL_DestroyTexture(sdl_tex); sdl_tex = NULL; } if (sdl_render != NULL) { - sdl_DestroyRenderer(sdl_render); + SDL_DestroyRenderer(sdl_render); sdl_render = NULL; } if (sdl_win != NULL) { - sdl_DestroyWindow(sdl_win); + SDL_DestroyWindow(sdl_win); sdl_win = NULL; } @@ -336,7 +268,8 @@ sdl_close(void) SetFocus(hwndMain); - DestroyWindow(sdl_hwnd); + if (sdl_fs) + DestroyWindow(sdl_hwnd); sdl_hwnd = NULL; } @@ -345,49 +278,55 @@ sdl_close(void) sdl_parent_hwnd = NULL; } - /* Quit and unload the DLL if possible. */ - if (sdl_handle != NULL) { - sdl_Quit(); - - dynld_close(sdl_handle); - sdl_handle = NULL; - } + /* Quit. */ + SDL_Quit(); } static int old_capture = 0; +static void +sdl_select_best_hw_driver(void) +{ + int i; + SDL_RendererInfo renderInfo; + + for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) + { + SDL_GetRenderDriverInfo(i, &renderInfo); + if (renderInfo.flags & SDL_RENDERER_ACCELERATED) { + SDL_SetHint(SDL_HINT_RENDER_DRIVER, renderInfo.name); + return; + } + } +} + + static int -sdl_init_common(int fs) +sdl_init_common(int flags) { wchar_t temp[128]; SDL_version ver; - int w, h, x, y; + int w = 0, h = 0, x = 0, y = 0; RECT rect; sdl_log("SDL: init (fs=%d)\n", fs); - cgapal_rebuild(); - - /* Try loading the DLL. */ - sdl_handle = dynld_module(PATH_SDL_DLL, sdl_imports); - if (sdl_handle == NULL) { - sdl_log("SDL: unable to load '%s', SDL not available.\n", PATH_SDL_DLL); - return(0); - } - /* Get and log the version of the DLL we are using. */ - sdl_GetVersion(&ver); + SDL_GetVersion(&ver); sdl_log("SDL: version %d.%d.%d\n", ver.major, ver.minor, ver.patch); /* Initialize the SDL system. */ - if (sdl_Init(SDL_INIT_VIDEO) < 0) { + if (SDL_Init(SDL_INIT_VIDEO) < 0) { sdl_log("SDL: initialization failed (%s)\n", sdl_GetError()); return(0); } - if (fs) { + if (flags & RENDERER_HARDWARE) + sdl_select_best_hw_driver(); + + if (flags & RENDERER_FULL_SCREEN) { /* Get the size of the (current) desktop. */ sdl_w = GetSystemMetrics(SM_CXSCREEN); sdl_h = GetSystemMetrics(SM_CYSCREEN); @@ -431,7 +370,7 @@ sdl_init_common(int fs) x, y, w, h, SWP_SHOWWINDOW); /* Now create the SDL window from that. */ - sdl_win = sdl_CreateWindowFrom((void *)sdl_hwnd); + sdl_win = SDL_CreateWindowFrom((void *)sdl_hwnd); old_capture = mouse_capture; @@ -442,7 +381,7 @@ sdl_init_common(int fs) mouse_capture = 1; } else { /* Create the SDL window from the render window. */ - sdl_win = sdl_CreateWindowFrom((void *)hwndRender); + sdl_win = SDL_CreateWindowFrom((void *)hwndRender); mouse_capture = old_capture; @@ -453,7 +392,7 @@ sdl_init_common(int fs) } } if (sdl_win == NULL) { - sdl_log("SDL: unable to CreateWindowFrom (%s)\n", sdl_GetError()); + sdl_log("SDL: unable to CreateWindowFrom (%s)\n", SDL_GetError()); sdl_close(); return(0); } @@ -465,9 +404,14 @@ sdl_init_common(int fs) * trying to switch to fullscreen even though the window is * not a fullscreen window?) */ - sdl_render = sdl_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + if (flags & RENDERER_HARDWARE) { + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); + } else + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + if (sdl_render == NULL) { - sdl_log("SDL: unable to create renderer (%s)\n", sdl_GetError()); + sdl_log("SDL: unable to create renderer (%s)\n", SDL_GetError()); sdl_close(); return(0); } @@ -478,10 +422,10 @@ sdl_init_common(int fs) * channel seems to be set to 255 everywhere, so ARGB8888 works * just as well. */ - sdl_tex = sdl_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 2048, 2048); if (sdl_tex == NULL) { - sdl_log("SDL: unable to create texture (%s)\n", sdl_GetError()); + sdl_log("SDL: unable to create texture (%s)\n", SDL_GetError()); sdl_close(); return(0); } @@ -492,109 +436,41 @@ sdl_init_common(int fs) /* Register our renderer! */ video_setblit(sdl_blit); - sdl_fs = fs; + sdl_fs = !!(flags & RENDERER_FULL_SCREEN); + + sdl_enabled = 1; + + sdl_mutex = SDL_CreateMutex(); return(1); } int -sdl_init(HWND h) +sdl_inits(HWND h) { return sdl_init_common(0); } int -sdl_init_fs(HWND h) +sdl_inith(HWND h) { - return sdl_init_common(1); + return sdl_init_common(RENDERER_HARDWARE); } -void -sdl_take_screenshot(const wchar_t *fn) +int +sdl_inits_fs(HWND h) { - int i, res, x, y, width = 0, height = 0; - unsigned char* rgba = NULL; - png_bytep *b_rgb = NULL; - FILE *fp = NULL; + return sdl_init_common(RENDERER_FULL_SCREEN); +} - sdl_GetWindowSize(sdl_win, &width, &height); - /* create file */ - fp = plat_fopen((wchar_t *) fn, (wchar_t *) L"wb"); - if (!fp) { - sdl_log("[sdl_take_screenshot] File %ls could not be opened for writing", fn); - return; - } - - /* initialize stuff */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!png_ptr) { - sdl_log("[sdl_take_screenshot] png_create_write_struct failed"); - fclose(fp); - return; - } - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - sdl_log("[sdl_take_screenshot] png_create_info_struct failed"); - fclose(fp); - return; - } - - png_init_io(png_ptr, fp); - - png_set_IHDR(png_ptr, info_ptr, width, height, - 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - if ((rgba = (unsigned char *)malloc(width * height * 4)) == NULL) { - sdl_log("[sdl_take_screenshot] Unable to Allocate RGBA Bitmap Memory"); - fclose(fp); - return; - } - - res = sdl_RenderReadPixels(sdl_render, NULL, SDL_PIXELFORMAT_ABGR8888, rgba, width * 4); - if (res) { - sdl_log("[sdl_take_screenshot] Error reading render pixels\n"); - fclose(fp); - return; - } - - if ((b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * height)) == NULL) { - sdl_log("[sdl_take_screenshot] Unable to Allocate RGB Bitmap Memory"); - free(rgba); - fclose(fp); - return; - } - - for (y = 0; y < height; ++y) { - b_rgb[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); - for (x = 0; x < width; ++x) { - b_rgb[y][(x) * 3 + 0] = rgba[(y * width + x) * 4 + 0]; - b_rgb[y][(x) * 3 + 1] = rgba[(y * width + x) * 4 + 1]; - b_rgb[y][(x) * 3 + 2] = rgba[(y * width + x) * 4 + 2]; - } - } - - png_write_info(png_ptr, info_ptr); - - png_write_image(png_ptr, b_rgb); - - png_write_end(png_ptr, NULL); - - /* cleanup heap allocation */ - for (i = 0; i < height; i++) - if (b_rgb[i]) free(b_rgb[i]); - - if (b_rgb) free(b_rgb); - - if (rgba) free(rgba); - - if (fp) fclose(fp); +int +sdl_inith_fs(HWND h) +{ + return sdl_init_common(RENDERER_FULL_SCREEN | RENDERER_HARDWARE); } @@ -608,18 +484,26 @@ sdl_pause(void) void sdl_resize(int x, int y) { - int ww, wh, wx, wy; + int ww = 0, wh = 0, wx = 0, wy = 0; if ((x == cur_w) && (y == cur_h)) return; - pclog("sdl_resize(%i, %i)\n", x, y); ww = x; wh = y; - sdl_stretch(&ww, &wh, &wx, &wy); - MoveWindow(sdl_hwnd, wx, wy, ww, wh, TRUE); + if (sdl_fs) { + sdl_stretch(&ww, &wh, &wx, &wy); + MoveWindow(sdl_hwnd, wx, wy, ww, wh, TRUE); + } cur_w = x; cur_h = y; } + + +void +sdl_enable(int enable) +{ + sdl_enabled = enable; +} diff --git a/src/win/win_sdl.h b/src/win/win_sdl.h index 23ba344be..896b3b8ef 100644 --- a/src/win/win_sdl.h +++ b/src/win/win_sdl.h @@ -8,13 +8,13 @@ * * Definitions for the libSDL2 rendering module. * - * Version: @(#)win_sdl.h 1.0.0 2018/05/26 + * Version: @(#)win_sdl.h 1.0.2 2019/12/05 * * Authors: Fred N. van Kempen, * Michael Drüing, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2018 Michael Drüing. + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2018,2019 Michael Drüing. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -51,12 +51,13 @@ extern void sdl_close(void); -extern int sdl_init(HWND h); -extern int sdl_init_fs(HWND h); +extern int sdl_inits(HWND h); +extern int sdl_inith(HWND h); +extern int sdl_inits_fs(HWND h); +extern int sdl_inith_fs(HWND h); extern int sdl_pause(void); extern void sdl_resize(int x, int y); - -extern void sdl_take_screenshot(const wchar_t *fn); +extern void sdl_enable(int enable); #endif /*WIN_SDL_H*/ diff --git a/src/win/win_serial.c b/src/win/win_serial.c deleted file mode 100644 index 21dc7443d..000000000 --- a/src/win/win_serial.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of host serial port services for Win32. - * - * This code is based on a universal serial port driver for - * Windows and UNIX systems, with support for FTDI and Prolific - * USB ports. Support for these has been removed. - * - * Version: @(#)win_serial.c 1.0.6 2017/10/16 - * - * Author: Fred N. van Kempen, - * - * Copyright 2017 Fred N. van Kempen. - */ -#include -#include -#include -#include -#define PLAT_SERIAL_C -#include "../86box.h" -#include "../plat.h" -#include "../plat_serial.h" - - -/* Handle the receiving of data from the host port. */ -static void -bhtty_reader(void *arg) -{ - BHTTY *pp = (BHTTY *)arg; - unsigned char b; - DWORD n; - - pclog("%s: thread started\n", pp->name); - - /* As long as the channel is open.. */ - while (pp->tid != NULL) { - /* Post a READ on the device. */ - n = 0; - if (ReadFile(pp->handle, &b, (DWORD)1, &n, &pp->rov) == FALSE) { - n = GetLastError(); - if (n != ERROR_IO_PENDING) { - /* Not good, we got an error. */ - pclog("%s: I/O error %d in read!\n", pp->name, n); - break; - } - - /* The read is pending, wait for it.. */ - if (GetOverlappedResult(pp->handle, &pp->rov, &n, TRUE) == FALSE) { - n = GetLastError(); - pclog("%s: I/O error %d in read!\n", pp->name, n); - break; - } - } - -pclog("%s: got %d bytes of data\n", pp->name, n); - if (n == 1) { - /* We got data, update stuff. */ - if (pp->icnt < sizeof(pp->buff)) { -pclog("%s: queued byte %02x (%d)\n", pp->name, b, pp->icnt+1); - pp->buff[pp->ihead++] = b; - pp->ihead &= (sizeof(pp->buff)-1); - pp->icnt++; - - /* Do a callback to let them know. */ - if (pp->rd_done != NULL) - pp->rd_done(pp->rd_arg, n); - } else { - pclog("%s: RX buffer overrun!\n", pp->name); - } - } - } - - /* Error or done, clean up. */ - pp->tid = NULL; - pclog("%s: thread stopped.\n", pp->name); -} - - -/* Set the state of a port. */ -int -bhtty_sstate(BHTTY *pp, void *arg) -{ - /* Make sure we can do this. */ - if (arg == NULL) { - pclog("%s: invalid argument\n", pp->name); - return(-1); - } - - if (SetCommState(pp->handle, (DCB *)arg) == FALSE) { - /* Mark an error. */ - pclog("%s: set state: %d\n", pp->name, GetLastError()); - return(-1); - } - - return(0); -} - - -/* Fetch the state of a port. */ -int -bhtty_gstate(BHTTY *pp, void *arg) -{ - /* Make sure we can do this. */ - if (arg == NULL) { - pclog("%s: invalid argument\n", pp->name); - return(-1); - } - - if (GetCommState(pp->handle, (DCB *)arg) == FALSE) { - /* Mark an error. */ - pclog("%s: get state: %d\n", pp->name, GetLastError()); - return(-1); - } - - return(0); -} - - -/* Enable or disable RTS/CTS mode (hardware handshaking.) */ -int -bhtty_crtscts(BHTTY *pp, char yesno) -{ - /* Get the current mode. */ - if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); - - switch(yesno) { - case 0: /* disable CRTSCTS */ - pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ - pp->dcb.fDsrSensitivity = 0; - - pp->dcb.fOutxCtsFlow = 0; /* disable RTS/CTS mode */ - - pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ - pp->dcb.fOutX = 0; - pp->dcb.fInX = 0; - break; - - case 1: /* enable CRTSCTS */ - pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ - pp->dcb.fDsrSensitivity = 0; - - pp->dcb.fOutxCtsFlow = 1; /* enable RTS/CTS mode */ - - pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ - pp->dcb.fOutX = 0; - pp->dcb.fInX = 0; - break; - - default: - pclog("%s: invalid parameter '%d'!\n", pp->name, yesno); - return(-1); - } - - /* Set new mode. */ - if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); - - return(0); -} - - -/* Set the port parameters. */ -int -bhtty_params(BHTTY *pp, char dbit, char par, char sbit) -{ - /* Get the current mode. */ - if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); - - /* Set the desired word length. */ - switch((int)dbit) { - case -1: /* no change */ - break; - - case 5: /* FTDI doesnt like these */ - case 6: - case 9: - break; - - case 7: - case 8: - pp->dcb.ByteSize = dbit; - break; - - default: - pclog("%s: invalid parameter '%d'!\n", pp->name, dbit); - return(-1); - } - - /* Set the type of parity encoding. */ - switch((int)par) { - case -1: /* no change */ - case ' ': - break; - - case 0: - case 'N': - pp->dcb.fParity = FALSE; - pp->dcb.Parity = NOPARITY; - break; - - case 1: - case 'O': - pp->dcb.fParity = TRUE; - pp->dcb.Parity = ODDPARITY; - break; - - case 2: - case 'E': - pp->dcb.fParity = TRUE; - pp->dcb.Parity = EVENPARITY; - break; - - case 3: - case 'M': - case 4: - case 'S': - break; - - default: - pclog("%s: invalid parameter '%c'!\n", pp->name, par); - return(-1); - } - - /* Set the number of stop bits. */ - switch((int)sbit) { - case -1: /* no change */ - break; - - case 1: - pp->dcb.StopBits = ONESTOPBIT; - break; - - case 2: - pp->dcb.StopBits = TWOSTOPBITS; - break; - - default: - pclog("%s: invalid parameter '%d'!\n", pp->name, sbit); - return(-1); - } - - /* Set new mode. */ - if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); - - return(0); -} - - -/* Put a port in transparent ("raw") state. */ -void -bhtty_raw(BHTTY *pp, void *arg) -{ - DCB *dcb = (DCB *)arg; - - /* Make sure we can do this. */ - if (arg == NULL) { - pclog("%s: invalid parameter\n", pp->name); - return; - } - - /* Enable BINARY transparent mode. */ - dcb->fBinary = 1; - dcb->fErrorChar = 0; /* disable Error Replacement */ - dcb->fNull = 0; /* disable NUL stripping */ - - /* Disable the DTR and RTS lines. */ - dcb->fDtrControl = DTR_CONTROL_DISABLE; /* DTR line */ - dcb->fRtsControl = RTS_CONTROL_DISABLE; /* RTS line */ - - /* Disable DSR/DCD handshaking. */ - dcb->fOutxDsrFlow = 0; /* DSR handshaking */ - dcb->fDsrSensitivity = 0; /* DSR Sensitivity */ - - /* Disable RTS/CTS handshaking. */ - dcb->fOutxCtsFlow = 0; /* CTS handshaking */ - - /* Disable XON/XOFF handshaking. */ - dcb->fTXContinueOnXoff = 0; /* continue TX after Xoff */ - dcb->fOutX = 0; /* enable output X-ON/X-OFF */ - dcb->fInX = 0; /* enable input X-ON/X-OFF */ - dcb->XonChar = 0x11; /* ASCII XON */ - dcb->XoffChar = 0x13; /* ASCII XOFF */ - dcb->XonLim = 100; - dcb->XoffLim = 100; - - dcb->fParity = FALSE; - dcb->Parity = NOPARITY; - dcb->StopBits = ONESTOPBIT; - dcb->BaudRate = CBR_1200; -} - - -/* Set the port speed. */ -int -bhtty_speed(BHTTY *pp, long speed) -{ - /* Get the current mode and speed. */ - if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); - - /* - * Set speed. - * - * This is not entirely correct, we should use a table - * with DCB_xxx speed values here, but we removed that - * and just hardcode the speed value into DCB. --FvK - */ - pp->dcb.BaudRate = speed; - - /* Set new speed. */ - if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); - - return(0); -} - - -/* Clean up and flush. */ -int -bhtty_flush(BHTTY *pp) -{ - DWORD dwErrs; - COMSTAT cst; - - /* First, clear any errors. */ - (void)ClearCommError(pp->handle, &dwErrs, &cst); - - /* Now flush all buffers. */ - if (PurgeComm(pp->handle, - (PURGE_RXABORT | PURGE_TXABORT | \ - PURGE_RXCLEAR | PURGE_TXCLEAR)) == FALSE) { - pclog("%s: flush: %d\n", pp->name, GetLastError()); - return(-1); - } - - /* Re-clear any errors. */ - if (ClearCommError(pp->handle, &dwErrs, &cst) == FALSE) { - pclog("%s: clear errors: %d\n", pp->name, GetLastError()); - return(-1); - } - - return(0); -} - - -/* Close an open serial port. */ -void -bhtty_close(BHTTY *pp) -{ - /* If the polling thread is running, stop it. */ - (void)bhtty_active(pp, 0); - - /* Close the event handles. */ - if (pp->rov.hEvent != INVALID_HANDLE_VALUE) - CloseHandle(pp->rov.hEvent); - if (pp->wov.hEvent != INVALID_HANDLE_VALUE) - CloseHandle(pp->wov.hEvent); - - if (pp->handle != INVALID_HANDLE_VALUE) { - pclog("%s: closing host port\n", pp->name); - - /* Restore the previous port state, if any. */ - (void)bhtty_sstate(pp, &pp->odcb); - - /* Close the port. */ - CloseHandle(pp->handle); - pp->handle = INVALID_HANDLE_VALUE; - } - - /* Release the control block. */ - free(pp); -} - - -/* Open a host serial port for I/O. */ -BHTTY * -bhtty_open(char *port, int tmo) -{ - char temp[84]; - COMMTIMEOUTS to; - COMMCONFIG conf; - BHTTY *pp; - DWORD d; - - /* First things first... create a control block. */ - if ((pp = (BHTTY *)malloc(sizeof(BHTTY))) == NULL) { - pclog("%s: out of memory!\n", port); - return(NULL); - } - memset(pp, 0x00, sizeof(BHTTY)); - strncpy(pp->name, port, sizeof(pp->name)-1); - - /* Try a regular Win32 serial port. */ - sprintf(temp, "\\\\.\\%s", pp->name); - if ((pp->handle = CreateFile(temp, - (GENERIC_READ|GENERIC_WRITE), - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, - 0)) == INVALID_HANDLE_VALUE) { - pclog("%s: open port: %d\n", pp->name, GetLastError()); - free(pp); - return(NULL); - } - - /* Create event handles. */ - pp->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - pp->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - /* Set up buffer size of the port. */ - if (SetupComm(pp->handle, 32768L, 32768L) == FALSE) { - /* This fails on FTDI-based devices. */ - pclog("%s: set buffers: %d\n", pp->name, GetLastError()); -#if 0 - CloseHandle(pp->handle); - free(pp); - return(NULL); -#endif - } - - /* Grab default config for the driver and set it. */ - d = sizeof(COMMCONFIG); - memset(&conf, 0x00, d); - conf.dwSize = d; - if (GetDefaultCommConfig(temp, &conf, &d) == TRUE) { - /* Change config here... */ - - /* Set new configuration. */ - if (SetCommConfig(pp->handle, &conf, d) == FALSE) { - /* This fails on FTDI-based devices. */ - pclog("%s: set configuration: %d\n", pp->name, GetLastError()); -#if 0 - CloseHandle(pp->handle); - free(pp); - return(NULL); -#endif - } - } - pclog("%s: host port '%s' open\n", pp->name, temp); - - /* - * We now have an open port. To allow for clean exit - * of the application, we first retrieve the port's - * current settings, and save these for later. - */ - if (bhtty_gstate(pp, &pp->odcb) < 0) { - (void)bhtty_close(pp); - return(NULL); - } - memcpy(&pp->dcb, &pp->odcb, sizeof(DCB)); - - /* Force the port to BINARY mode. */ - bhtty_raw(pp, &pp->dcb); - - /* Set new state of this port. */ - if (bhtty_sstate(pp, &pp->dcb) < 0) { - (void)bhtty_close(pp); - return(NULL); - } - - /* Just to make sure.. disable RTS/CTS mode. */ - (void)bhtty_crtscts(pp, 0); - - /* Set new timeout values. */ - if (GetCommTimeouts(pp->handle, &to) == FALSE) { - pclog("%s: error %d while getting current TO\n", - pp->name, GetLastError()); - (void)bhtty_close(pp); - return(NULL); - } - if (tmo < 0) { - /* No timeout, immediate return. */ - to.ReadIntervalTimeout = MAXDWORD; - to.ReadTotalTimeoutMultiplier = 0; - to.ReadTotalTimeoutConstant = 0; - } else if (tmo == 0) { - /* No timeout, wait for data. */ - memset(&to, 0x00, sizeof(to)); - } else { - /* Timeout specified. */ - to.ReadIntervalTimeout = MAXDWORD; - to.ReadTotalTimeoutMultiplier = MAXDWORD; - to.ReadTotalTimeoutConstant = tmo; - } - if (SetCommTimeouts(pp->handle, &to) == FALSE) { - pclog("%s: error %d while setting TO\n", pp->name, GetLastError()); - (void)bhtty_close(pp); - return(NULL); - } - - /* Clear all errors and flush all buffers. */ - if (bhtty_flush(pp) < 0) { - (void)bhtty_close(pp); - return(NULL); - } - - return(pp); -} - - -/* Activate the I/O for this port. */ -int -bhtty_active(BHTTY *pp, int flg) -{ - if (flg) { - pclog("%s: starting thread..\n", pp->name); - pp->tid = thread_create(bhtty_reader, pp); - } else { - if (pp->tid != NULL) { - pclog("%s: stopping thread..\n", pp->name); - thread_kill(pp->tid); - pp->tid = NULL; - } - } - - return(0); -} - - -/* Try to write data to an open port. */ -int -bhtty_write(BHTTY *pp, unsigned char val) -{ - DWORD n = 0; - -pclog("%s: writing byte %02x\n", pp->name, val); - if (WriteFile(pp->handle, &val, 1, &n, &pp->wov) == FALSE) { - n = GetLastError(); - if (n != ERROR_IO_PENDING) { - /* Not good, we got an error. */ - pclog("%s: I/O error %d in write!\n", pp->name, n); - return(-1); - } - - /* The write is pending, wait for it.. */ - if (GetOverlappedResult(pp->handle, &pp->wov, &n, TRUE) == FALSE) { - n = GetLastError(); - pclog("%s: I/O error %d in write!\n", pp->name, n); - return(-1); - } - } - - return((int)n); -} - - -/* - * Try to read data from an open port. - * - * For now, we will use one byte per call. Eventually, - * we should go back to loading a buffer full of data, - * just to speed things up a bit. --FvK - */ -int -bhtty_read(BHTTY *pp, unsigned char *bufp, int max) -{ - if (pp->icnt == 0) return(0); - - while (max-- > 0) { - *bufp++ = pp->buff[pp->itail++]; -pclog("%s: dequeued byte %02x (%d)\n", pp->name, *(bufp-1), pp->icnt); - pp->itail &= (sizeof(pp->buff)-1); - if (--pp->icnt == 0) break; - } - - return(max); -} diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 16d8ea151..f47f4f4b1 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -8,17 +8,22 @@ * * Windows 86Box Settings dialog handler. * - * Version: @(#)win_settings.c 1.0.51 2018/05/25 + * Version: @(#)win_settings.c 1.0.63 2019/12/21 * - * Author: Miran Grca, + * Authors: Miran Grca, + * David HrdliÄka, * - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 David HrdliÄka. */ #define UNICODE #define BITMAP WINDOWS_BITMAP #include #include #undef BITMAP +#ifdef ENABLE_SETTINGS_LOG +#include +#endif #include #include #include @@ -31,12 +36,16 @@ #include "../mem.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "../nvr.h" #include "../machine/machine.h" #include "../game/gameport.h" +#include "../isamem.h" +#include "../isartc.h" #include "../lpt.h" #include "../mouse.h" #include "../scsi/scsi.h" +#include "../scsi/scsi_device.h" #include "../cdrom/cdrom.h" #include "../disk/hdd.h" #include "../disk/hdc.h" @@ -46,8 +55,8 @@ #include "../network/network.h" #include "../sound/sound.h" #include "../sound/midi.h" -#include "../sound/snd_dbopl.h" #include "../sound/snd_mpu401.h" +#include "../sound/snd_gus.h" #include "../video/video.h" #include "../video/vid_voodoo.h" #include "../plat.h" @@ -56,21 +65,12 @@ #include "win.h" -#define SETTINGS_PAGE_MACHINE 0 -#define SETTINGS_PAGE_VIDEO 1 -#define SETTINGS_PAGE_INPUT 2 -#define SETTINGS_PAGE_SOUND 3 -#define SETTINGS_PAGE_NETWORK 4 -#define SETTINGS_PAGE_PORTS 5 -#define SETTINGS_PAGE_PERIPHERALS 6 -#define SETTINGS_PAGE_HARD_DISKS 7 -#define SETTINGS_PAGE_FLOPPY_DRIVES 8 -#define SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES 9 - /* Icon, Bus, File, C, H, S, Size */ #define C_COLUMNS_HARD_DISKS 6 +static int first_cat = 0; + /* Machine category */ static int temp_machine, temp_cpu_m, temp_cpu, temp_wait_states, temp_fpu, temp_sync; static uint32_t temp_mem_size; @@ -85,22 +85,22 @@ static int temp_gfxcard, temp_voodoo; static int temp_mouse, temp_joystick; /* Sound category */ -static int temp_sound_card, temp_midi_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS, temp_opl_type; +static int temp_sound_card, temp_midi_device, temp_midi_input_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS; static int temp_float; /* Network category */ static int temp_net_type, temp_net_card; -static char temp_pcap_dev[520]; +static char temp_pcap_dev[522]; /* Ports category */ -static char temp_lpt_device_names[3][16]; -static int temp_serial[2], temp_lpt; +static int temp_lpt_devices[3]; +static int temp_serial[2], temp_lpt[3]; /* Other peripherals category */ -static int temp_scsi_card, temp_ide_ter, temp_ide_qua; -static char temp_hdc_name[32]; -static char *hdc_names[32]; +static int temp_hdc, temp_scsi_card, temp_ide_ter, temp_ide_qua; static int temp_bugger; +static int temp_isartc; +static int temp_isamem[ISAMEM_MAX]; static uint8_t temp_deviceconfig; @@ -113,7 +113,7 @@ static int temp_fdd_turbo[FDD_NUM]; static int temp_fdd_check_bpb[FDD_NUM]; /* Other removable devices category */ -static cdrom_drive_t temp_cdrom_drives[CDROM_NUM]; +static cdrom_t temp_cdrom[CDROM_NUM]; static zip_drive_t temp_zip_drives[ZIP_NUM]; static HWND hwndParentDialog, hwndChildDialog; @@ -121,9 +121,10 @@ static HWND hwndParentDialog, hwndChildDialog; static uint32_t displayed_category = 0; extern int is486; -static int romstolist[ROM_MAX], listtomachine[ROM_MAX], romstomachine[ROM_MAX], machinetolist[ROM_MAX]; -static int settings_device_to_list[20], settings_list_to_device[20]; +static int listtomachine[256], machinetolist[256]; +static int settings_device_to_list[2][20], settings_list_to_device[2][20]; static int settings_midi_to_list[20], settings_list_to_midi[20]; +static int settings_midi_in_to_list[20], settings_list_to_midi_in[20]; static int max_spt = 63, max_hpc = 255, max_tracks = 266305; static uint64_t mfm_tracking, esdi_tracking, xta_tracking, ide_tracking, scsi_tracking[2]; @@ -155,7 +156,11 @@ image_list_init(HWND hwndList, const uint8_t *icon_ids) if (icon_ids[i] == 0) break; +#if defined(__amd64__) || defined(__aarch64__) + hiconItem = LoadIcon(hinstance, (LPCWSTR) ((uint64_t) icon_ids[i])); +#else hiconItem = LoadIcon(hinstance, (LPCWSTR) ((uint32_t) icon_ids[i])); +#endif ImageList_AddIcon(hSmall, hiconItem); DestroyIcon(hiconItem); @@ -202,7 +207,7 @@ win_settings_init(void) temp_dynarec = cpu_use_dynarec; #endif temp_fpu = enable_external_fpu; - temp_sync = enable_sync; + temp_sync = time_sync; /* Video category */ temp_gfxcard = gfxcard; @@ -215,33 +220,42 @@ win_settings_init(void) /* Sound category */ temp_sound_card = sound_card_current; temp_midi_device = midi_device_current; + temp_midi_input_device = midi_input_device_current; temp_mpu401 = mpu401_standalone_enable; temp_SSI2001 = SSI2001; temp_GAMEBLASTER = GAMEBLASTER; temp_GUS = GUS; - temp_opl_type = opl_type; temp_float = sound_is_float; /* Network category */ temp_net_type = network_type; memset(temp_pcap_dev, 0, sizeof(temp_pcap_dev)); - strcpy(temp_pcap_dev, network_host); +#ifdef ENABLE_SETTINGS_LOG + assert(sizeof(temp_pcap_dev) == sizeof(network_host)); +#endif + memcpy(temp_pcap_dev, network_host, sizeof(network_host)); temp_net_card = network_card; /* Ports category */ - for (i = 0; i < 3; i++) - strncpy(temp_lpt_device_names[i], lpt_device_names[i], sizeof(temp_lpt_device_names[i]) - 1); - temp_serial[0] = serial_enabled[0]; - temp_serial[1] = serial_enabled[1]; - temp_lpt = lpt_enabled; + for (i = 0; i < 3; i++) { + temp_lpt_devices[i] = lpt_ports[i].device; + temp_lpt[i] = lpt_ports[i].enabled; + } + for (i = 0; i < 2; i++) + temp_serial[i] = serial_enabled[i]; /* Other peripherals category */ temp_scsi_card = scsi_card_current; - strncpy(temp_hdc_name, hdc_name, sizeof(temp_hdc_name) - 1); + temp_hdc = hdc_current; temp_ide_ter = ide_ter_enabled; temp_ide_qua = ide_qua_enabled; temp_bugger = bugger_enabled; - + temp_isartc = isartc_type; + + /* ISA memory boards. */ + for (i = 0; i < ISAMEM_MAX; i++) + temp_isamem[i] = isamem_type[i]; + mfm_tracking = xta_tracking = esdi_tracking = ide_tracking = 0; for (i = 0; i < 2; i++) scsi_tracking[i] = 0; @@ -259,8 +273,8 @@ win_settings_init(void) ide_tracking |= (1 << (hdd[i].ide_channel << 3)); else if (hdd[i].bus == HDD_BUS_SCSI) scsi_tracking[hdd[i].scsi_id >> 3] |= (1 << ((hdd[i].scsi_id & 0x07) << 3)); - } - + } + /* Floppy drives category */ for (i = 0; i < FDD_NUM; i++) { temp_fdd_types[i] = fdd_get_type(i); @@ -269,12 +283,12 @@ win_settings_init(void) } /* Other removable devices category */ - memcpy(temp_cdrom_drives, cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + memcpy(temp_cdrom, cdrom, CDROM_NUM * sizeof(cdrom_t)); for (i = 0; i < CDROM_NUM; i++) { - if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) - ide_tracking |= (2 << (cdrom_drives[i].ide_channel << 3)); - else if (cdrom_drives[i].bus_type == CDROM_BUS_SCSI) - scsi_tracking[cdrom_drives[i].scsi_device_id >> 3] |= (1 << ((cdrom_drives[i].scsi_device_id & 0x07) << 3)); + if (cdrom[i].bus_type == CDROM_BUS_ATAPI) + ide_tracking |= (2 << (cdrom[i].ide_channel << 3)); + else if (cdrom[i].bus_type == CDROM_BUS_SCSI) + scsi_tracking[cdrom[i].scsi_device_id >> 3] |= (1 << ((cdrom[i].scsi_device_id & 0x07) << 3)); } memcpy(temp_zip_drives, zip_drives, ZIP_NUM * sizeof(zip_drive_t)); for (i = 0; i < ZIP_NUM; i++) { @@ -305,7 +319,7 @@ win_settings_changed(void) i = i || (temp_dynarec != cpu_use_dynarec); #endif i = i || (temp_fpu != enable_external_fpu); - i = i || (temp_sync != enable_sync); + i = i || (temp_sync != time_sync); /* Video category */ i = i || (gfxcard != temp_gfxcard); @@ -318,11 +332,11 @@ win_settings_changed(void) /* Sound category */ i = i || (sound_card_current != temp_sound_card); i = i || (midi_device_current != temp_midi_device); + i = i || (midi_input_device_current != temp_midi_input_device); i = i || (mpu401_standalone_enable != temp_mpu401); i = i || (SSI2001 != temp_SSI2001); i = i || (GAMEBLASTER != temp_GAMEBLASTER); i = i || (GUS != temp_GUS); - i = i || (opl_type != temp_opl_type); i = i || (sound_is_float != temp_float); /* Network category */ @@ -331,19 +345,25 @@ win_settings_changed(void) i = i || (network_card != temp_net_card); /* Ports category */ - for (j = 0; j < 3; j++) - i = i || strncmp(temp_lpt_device_names[j], lpt_device_names[j], sizeof(temp_lpt_device_names[j]) - 1); - i = i || (temp_serial[0] != serial_enabled[0]); - i = i || (temp_serial[1] != serial_enabled[1]); - i = i || (temp_lpt != lpt_enabled); + for (j = 0; j < 3; j++) { + i = i || (temp_lpt_devices[j] != lpt_ports[j].device); + i = i || (temp_lpt[j] != lpt_ports[j].enabled); + } + for (j = 0; j < 2; j++) + i = i || (temp_serial[j] != serial_enabled[j]); /* Peripherals category */ i = i || (scsi_card_current != temp_scsi_card); - i = i || strncmp(temp_hdc_name, hdc_name, sizeof(temp_hdc_name) - 1); + i = i || (hdc_current != temp_hdc); i = i || (temp_ide_ter != ide_ter_enabled); i = i || (temp_ide_qua != ide_qua_enabled); i = i || (temp_bugger != bugger_enabled); + i = i || (temp_isartc != isartc_type); + /* ISA memory boards. */ + for (j = 0; j < ISAMEM_MAX; j++) + i = i || (temp_isamem[j] != isamem_type[j]); + /* Hard disks category */ i = i || memcmp(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); @@ -355,7 +375,7 @@ win_settings_changed(void) } /* Other removable devices category */ - i = i || memcmp(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + i = i || memcmp(cdrom, temp_cdrom, CDROM_NUM * sizeof(cdrom_t)); i = i || memcmp(zip_drives, temp_zip_drives, ZIP_NUM * sizeof(zip_drive_t)); i = i || !!temp_deviceconfig; @@ -394,7 +414,6 @@ win_settings_save(void) /* Machine category */ machine = temp_machine; - romset = machine_getromset(); cpu_manufacturer = temp_cpu_m; cpu_waitstates = temp_wait_states; cpu = temp_cpu; @@ -403,7 +422,7 @@ win_settings_save(void) cpu_use_dynarec = temp_dynarec; #endif enable_external_fpu = temp_fpu; - enable_sync = temp_sync; + time_sync = temp_sync; /* Video category */ gfxcard = temp_gfxcard; @@ -416,11 +435,11 @@ win_settings_save(void) /* Sound category */ sound_card_current = temp_sound_card; midi_device_current = temp_midi_device; + midi_input_device_current = temp_midi_input_device; mpu401_standalone_enable = temp_mpu401; SSI2001 = temp_SSI2001; GAMEBLASTER = temp_GAMEBLASTER; GUS = temp_GUS; - opl_type = temp_opl_type; sound_is_float = temp_float; /* Network category */ @@ -430,27 +449,29 @@ win_settings_save(void) network_card = temp_net_card; /* Ports category */ - for (i = 0; i < 3; i++) - strncpy(lpt_device_names[i], temp_lpt_device_names[i], sizeof(temp_lpt_device_names[i]) - 1); - serial_enabled[0] = temp_serial[0]; - serial_enabled[1] = temp_serial[1]; - lpt_enabled = temp_lpt; + for (i = 0; i < 3; i++) { + lpt_ports[i].device = temp_lpt_devices[i]; + lpt_ports[i].enabled = temp_lpt[i]; + } + for (i = 0; i < 2; i++) + serial_enabled[i] = temp_serial[i]; /* Peripherals category */ scsi_card_current = temp_scsi_card; - if (hdc_name) { - free(hdc_name); - hdc_name = NULL; - } - hdc_name = (char *) malloc(sizeof(temp_hdc_name)); - strncpy(hdc_name, temp_hdc_name, sizeof(temp_hdc_name) - 1); - hdc_init(hdc_name); + hdc_current = temp_hdc; ide_ter_enabled = temp_ide_ter; ide_qua_enabled = temp_ide_qua; bugger_enabled = temp_bugger; + isartc_type = temp_isartc; + /* ISA memory boards. */ + for (i = 0; i < ISAMEM_MAX; i++) + isamem_type[i] = temp_isamem[i]; + /* Hard disks category */ memcpy(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); + for (i = 0; i < HDD_NUM; i++) + hdd[i].priv = NULL; /* Floppy drives category */ for (i = 0; i < FDD_NUM; i++) { @@ -460,8 +481,22 @@ win_settings_save(void) } /* Removable devices category */ - memcpy(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + memcpy(cdrom, temp_cdrom, CDROM_NUM * sizeof(cdrom_t)); + for (i = 0; i < CDROM_NUM; i++) { + cdrom[i].img_fp = NULL; + cdrom[i].priv = NULL; + cdrom[i].ops = NULL; + cdrom[i].image = NULL; + cdrom[i].insert = NULL; + cdrom[i].close = NULL; + cdrom[i].get_volume = NULL; + cdrom[i].get_channel = NULL; + } memcpy(zip_drives, temp_zip_drives, ZIP_NUM * sizeof(zip_drive_t)); + for (i = 0; i < ZIP_NUM; i++) { + zip_drives[i].f = NULL; + zip_drives[i].priv = NULL; + } /* Mark configuration as changed. */ config_changed = 1; @@ -474,15 +509,13 @@ static void win_settings_machine_recalc_cpu(HWND hdlg) { HWND h; - int cpu_type, temp_romset; + int cpu_type; #ifdef USE_DYNAREC int cpu_flags; #endif - temp_romset = machine_getromset_ex(temp_machine); - h = GetDlgItem(hdlg, IDC_COMBO_WS); - cpu_type = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + cpu_type = machines[temp_machine].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; if ((cpu_type >= CPU_286) && (cpu_type <= CPU_386DX)) EnableWindow(h, TRUE); else @@ -490,7 +523,7 @@ win_settings_machine_recalc_cpu(HWND hdlg) #ifdef USE_DYNAREC h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); - cpu_flags = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + cpu_flags = machines[temp_machine].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) && (cpu_flags & CPU_REQUIRES_DYNAREC)) fatal("Attempting to select a CPU that requires the recompiler and does not support it at the same time\n"); if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) { @@ -505,8 +538,9 @@ win_settings_machine_recalc_cpu(HWND hdlg) #endif h = GetDlgItem(hdlg, IDC_CHECK_FPU); - cpu_type = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; - if ((cpu_type < CPU_i486DX) && (cpu_type >= CPU_286)) + cpu_type = machines[temp_machine].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + // if ((cpu_type < CPU_i486DX) && (cpu_type >= CPU_286)) + if (cpu_type < CPU_i486DX) EnableWindow(h, TRUE); else if (cpu_type < CPU_286) { temp_fpu = 0; @@ -523,18 +557,17 @@ static void win_settings_machine_recalc_cpu_m(HWND hdlg) { HWND h; - int c, temp_romset; + int c; LPTSTR lptsTemp; char *stransi; - temp_romset = machine_getromset_ex(temp_machine); - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_CPU); SendMessage(h, CB_RESETCONTENT, 0, 0); c = 0; - while (machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[c].cpu_type != -1) { - stransi = (char *) machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[c].name; + while (machines[temp_machine].cpu[temp_cpu_m].cpus[c].cpu_type != -1) { + stransi = (char *) machines[temp_machine].cpu[temp_cpu_m].cpus[c].name; mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); c++; @@ -554,16 +587,17 @@ static void win_settings_machine_recalc_machine(HWND hdlg) { HWND h; - int c, temp_romset; + int c; LPTSTR lptsTemp; const char *stransi; UDACCEL accel; + device_t *d; - temp_romset = machine_getromset_ex(temp_machine); - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_CONFIGURE_MACHINE); - if (machine_getdevice(temp_machine)) + d = (device_t *) machine_getdevice(temp_machine); + if (d && d->config) EnableWindow(h, TRUE); else EnableWindow(h, FALSE); @@ -571,8 +605,8 @@ win_settings_machine_recalc_machine(HWND hdlg) h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); SendMessage(h, CB_RESETCONTENT, 0, 0); c = 0; - while (machines[romstomachine[temp_romset]].cpu[c].cpus != NULL && c < 4) { - stransi = machines[romstomachine[temp_romset]].cpu[c].name; + while (machines[temp_machine].cpu[c].cpus != NULL && c < 4) { + stransi = machines[temp_machine].cpu[c].name; mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); c++; @@ -586,11 +620,11 @@ win_settings_machine_recalc_machine(HWND hdlg) win_settings_machine_recalc_cpu_m(hdlg); h = GetDlgItem(hdlg, IDC_MEMSPIN); - SendMessage(h, UDM_SETRANGE, 0, (machines[romstomachine[temp_romset]].min_ram << 16) | machines[romstomachine[temp_romset]].max_ram); + SendMessage(h, UDM_SETRANGE, 0, (machines[temp_machine].min_ram << 16) | machines[temp_machine].max_ram); accel.nSec = 0; - accel.nInc = machines[romstomachine[temp_romset]].ram_granularity; + accel.nInc = machines[temp_machine].ram_granularity; SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); - if (!(machines[romstomachine[temp_romset]].flags & MACHINE_AT) || (machines[romstomachine[temp_romset]].ram_granularity >= 128)) { + if (!(machines[temp_machine].flags & MACHINE_AT) || (machines[temp_machine].ram_granularity >= 128)) { SendMessage(h, UDM_SETPOS, 0, temp_mem_size); h = GetDlgItem(hdlg, IDC_TEXT_MB); SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2094)); @@ -604,7 +638,7 @@ win_settings_machine_recalc_machine(HWND hdlg) } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -618,21 +652,17 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); - for (c = 0; c < ROM_MAX; c++) - romstolist[c] = 0; c = d = 0; - while (machines[c].id != -1) { - if (romspresent[machines[c].id]) { + while (machine_get_internal_name_ex(c) != NULL) { + if (machine_available(c)) { stransi = (char *)machines[c].name; mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); machinetolist[c] = d; listtomachine[d] = c; - romstolist[machines[c].id] = d; - romstomachine[machines[c].id] = c; d++; } c++; @@ -658,8 +688,24 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h2 = GetDlgItem(hdlg, IDC_MEMTEXT); SendMessage(h, UDM_SETBUDDY, (WPARAM)h2, 0); - h=GetDlgItem(hdlg, IDC_CHECK_SYNC); - SendMessage(h, BM_SETCHECK, temp_sync, 0); + if (temp_sync & TIME_SYNC_ENABLED) + { + if (temp_sync & TIME_SYNC_UTC) + { + h=GetDlgItem(hdlg, IDC_RADIO_TS_UTC); + SendMessage(h, BM_SETCHECK, BST_CHECKED, 0); + } + else + { + h=GetDlgItem(hdlg, IDC_RADIO_TS_LOCAL); + SendMessage(h, BM_SETCHECK, BST_CHECKED, 0); + } + } + else + { + h=GetDlgItem(hdlg, IDC_RADIO_TS_DISABLED); + SendMessage(h, BM_SETCHECK, BST_CHECKED, 0); + } win_settings_machine_recalc_machine(hdlg); @@ -705,7 +751,7 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return FALSE; case WM_SAVESETTINGS: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); stransi = (char *)malloc(512); #ifdef USE_DYNAREC @@ -713,8 +759,17 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); #endif - h=GetDlgItem(hdlg, IDC_CHECK_SYNC); - temp_sync = SendMessage(h, BM_GETCHECK, 0, 0); + h=GetDlgItem(hdlg, IDC_RADIO_TS_DISABLED); + if(SendMessage(h, BM_GETCHECK, 0, 0)) + temp_sync = TIME_SYNC_DISABLED; + + h=GetDlgItem(hdlg, IDC_RADIO_TS_LOCAL); + if(SendMessage(h, BM_GETCHECK, 0, 0)) + temp_sync = TIME_SYNC_ENABLED; + + h=GetDlgItem(hdlg, IDC_RADIO_TS_UTC); + if(SendMessage(h, BM_GETCHECK, 0, 0)) + temp_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC; h=GetDlgItem(hdlg, IDC_CHECK_FPU); temp_fpu = SendMessage(h, BM_GETCHECK, 0, 0); @@ -767,11 +822,11 @@ recalc_vid_list(HWND hdlg) if (!s[0]) break; - if (video_card_available(c) && gfx_present[video_new_to_old(c)] && + if (video_card_available(c) && device_is_valid(video_card_getdevice(c), machines[temp_machine].flags)) { mbstowcs(szText, s, strlen(s) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); - if (video_new_to_old(c) == temp_gfxcard) { + if (c == temp_gfxcard) { SendMessage(h, CB_SETCURSEL, d, 0); found_card = 1; } @@ -783,7 +838,7 @@ recalc_vid_list(HWND hdlg) } if (!found_card) SendMessage(h, CB_SETCURSEL, 0, 0); - EnableWindow(h, machines[temp_machine].fixed_gfxcard ? FALSE : TRUE); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_VIDEO_FIXED) ? FALSE : TRUE); h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); EnableWindow(h, (machines[temp_machine].flags & MACHINE_PCI) ? TRUE : FALSE); @@ -793,7 +848,7 @@ recalc_vid_list(HWND hdlg) } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -803,11 +858,10 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) HWND h; LPTSTR lptsTemp; char *stransi; - int gfx; switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); stransi = (char *) malloc(512); recalc_vid_list(hdlg); @@ -818,10 +872,9 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); wcstombs(stransi, lptsTemp, 512); - gfx = video_card_getid(stransi); h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); - if (video_card_has_config(gfx)) + if (video_card_has_config(temp_gfxcard)) EnableWindow(h, TRUE); else EnableWindow(h, FALSE); @@ -834,17 +887,16 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_COMBO_VIDEO: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); stransi = (char *) malloc(512); h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); wcstombs(stransi, lptsTemp, 512); - gfx = video_card_getid(stransi); - temp_gfxcard = video_new_to_old(gfx); + temp_gfxcard = video_card_getid(stransi); h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); - if (video_card_has_config(gfx)) + if (video_card_has_config(temp_gfxcard)) EnableWindow(h, TRUE); else EnableWindow(h, FALSE); @@ -866,7 +918,7 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; case IDC_CONFIGURE_VID: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); stransi = (char *) malloc(512); h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); @@ -881,13 +933,13 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return FALSE; case WM_SAVESETTINGS: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); stransi = (char *) malloc(512); h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); wcstombs(stransi, lptsTemp, 512); - temp_gfxcard = video_new_to_old(video_card_getid(stransi)); + temp_gfxcard = video_card_getid(stransi); h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); @@ -915,7 +967,7 @@ mouse_valid(int num, int m) } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -931,18 +983,18 @@ win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); c = d = 0; for (c = 0; c < mouse_get_ndev(); c++) { - settings_device_to_list[c] = d; + settings_device_to_list[0][c] = d; if (mouse_valid(c, temp_machine)) { mbstowcs(str, mouse_get_name(c), sizeof_w(str)); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)str); - settings_list_to_device[d] = c; + settings_list_to_device[0][d] = c; d++; } } - SendMessage(h, CB_SETCURSEL, settings_device_to_list[temp_mouse], 0); + SendMessage(h, CB_SETCURSEL, settings_device_to_list[0][temp_mouse], 0); h = GetDlgItem(hdlg, IDC_CONFIGURE_MOUSE); if (mouse_has_config(temp_mouse)) @@ -974,7 +1026,7 @@ win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (LOWORD(wParam)) { case IDC_COMBO_MOUSE: h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); - temp_mouse = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_mouse = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; h = GetDlgItem(hdlg, IDC_CONFIGURE_MOUSE); if (mouse_has_config(temp_mouse)) @@ -985,7 +1037,7 @@ win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case IDC_CONFIGURE_MOUSE: h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); - temp_mouse = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_mouse = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)mouse_get_device(temp_mouse)); break; @@ -1031,7 +1083,7 @@ win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_SAVESETTINGS: h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); - temp_mouse = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_mouse = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); @@ -1046,14 +1098,6 @@ win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) static int mpu401_present(void) { - char *n; - - n = sound_card_get_internal_name(temp_sound_card); - if (n != NULL) { - if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) - return 1; - } - return temp_mpu401 ? 1 : 0; } @@ -1061,25 +1105,20 @@ mpu401_present(void) int mpu401_standalone_allow(void) { - char *n, *md; + char *md, *mdin; - n = sound_card_get_internal_name(temp_sound_card); md = midi_device_get_internal_name(temp_midi_device); - if (n != NULL) { - if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) - return 0; - } + mdin = midi_in_device_get_internal_name(temp_midi_input_device); if (md != NULL) { - if (!strcmp(md, "none")) + if (!strcmp(md, "none") && !strcmp(mdin, "none")) return 0; } return 1; } - -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -1094,7 +1133,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_SOUND); c = d = 0; @@ -1104,7 +1143,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (!s[0]) break; - settings_device_to_list[c] = d; + settings_device_to_list[0][c] = d; if (sound_card_available(c)) { sound_dev = sound_card_getdevice(c); @@ -1116,14 +1155,14 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) mbstowcs(lptsTemp, s, strlen(s) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); } - settings_list_to_device[d] = c; + settings_list_to_device[0][d] = c; d++; } } c++; } - SendMessage(h, CB_SETCURSEL, settings_device_to_list[temp_sound_card], 0); + SendMessage(h, CB_SETCURSEL, settings_device_to_list[0][temp_sound_card], 0); EnableWindow(h, d ? TRUE : FALSE); @@ -1161,25 +1200,58 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) else EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); + c = d = 0; + while (1) { + s = midi_in_device_getname(c); + + if (!s[0]) + break; + + settings_midi_in_to_list[c] = d; + + if (midi_in_device_available(c)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_midi_in[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_midi_in_to_list[temp_midi_input_device], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI_IN); + if (midi_in_device_has_config(temp_midi_input_device)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); SendMessage(h, BM_SETCHECK, temp_mpu401, 0); EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + h=GetDlgItem(hdlg, IDC_CHECK_CMS); SendMessage(h, BM_SETCHECK, temp_GAMEBLASTER, 0); h=GetDlgItem(hdlg, IDC_CHECK_GUS); SendMessage(h, BM_SETCHECK, temp_GUS, 0); - + + h = GetDlgItem(hdlg, IDC_CONFIGURE_GUS); + EnableWindow(h, (temp_GUS) ? TRUE : FALSE); + h=GetDlgItem(hdlg, IDC_CHECK_SSI); SendMessage(h, BM_SETCHECK, temp_SSI2001, 0); - h=GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); - SendMessage(h, BM_SETCHECK, temp_opl_type, 0); - h=GetDlgItem(hdlg, IDC_CHECK_FLOAT); SendMessage(h, BM_SETCHECK, temp_float, 0); @@ -1191,7 +1263,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (LOWORD(wParam)) { case IDC_COMBO_SOUND: h = GetDlgItem(hdlg, IDC_COMBO_SOUND); - temp_sound_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_sound_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; h = GetDlgItem(hdlg, IDC_CONFIGURE_SND); if (sound_card_has_config(temp_sound_card)) @@ -1209,7 +1281,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case IDC_CONFIGURE_SND: h = GetDlgItem(hdlg, IDC_COMBO_SOUND); - temp_sound_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_sound_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card)); break; @@ -1239,6 +1311,31 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) temp_deviceconfig |= deviceconfig_open(hdlg, (void *)midi_device_getdevice(temp_midi_device)); break; + case IDC_COMBO_MIDI_IN: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); + temp_midi_input_device = settings_list_to_midi_in[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI_IN); + if (midi_in_device_has_config(temp_midi_input_device)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_MIDI_IN: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); + temp_midi_input_device = settings_list_to_midi_in[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)midi_in_device_getdevice(temp_midi_input_device)); + break; + case IDC_CHECK_MPU401: h = GetDlgItem(hdlg, IDC_CHECK_MPU401); temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); @@ -1248,18 +1345,34 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; case IDC_CONFIGURE_MPU401: - temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&mpu401_device); + temp_deviceconfig |= deviceconfig_open(hdlg, (machines[temp_machine].flags & MACHINE_MCA) ? + (void *)&mpu401_mca_device : (void *)&mpu401_device); + break; + + case IDC_CHECK_GUS: + h = GetDlgItem(hdlg, IDC_CHECK_GUS); + temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_GUS); + EnableWindow(h, temp_GUS ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_GUS: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&gus_device); break; } return FALSE; case WM_SAVESETTINGS: h = GetDlgItem(hdlg, IDC_COMBO_SOUND); - temp_sound_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_sound_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; h = GetDlgItem(hdlg, IDC_COMBO_MIDI); temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); + temp_midi_input_device = settings_list_to_midi_in[SendMessage(h, CB_GETCURSEL, 0, 0)]; + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); @@ -1272,9 +1385,6 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_CHECK_SSI); temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); - temp_opl_type = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_CHECK_FLOAT); temp_float = SendMessage(h, BM_GETCHECK, 0, 0); @@ -1285,7 +1395,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -1293,17 +1403,17 @@ static BOOL CALLBACK win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h; - int c, d, i; + int c, i; char *s; LPTSTR lptsTemp; switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); for (i = 0; i < 3; i++) { h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); - c = d = 0; + c = 0; while (1) { s = lpt_device_get_name(c); @@ -1317,22 +1427,18 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); } - if (!strcmp(temp_lpt_device_names[i], lpt_device_get_internal_name(c))) - d = c; - c++; } - SendMessage(h, CB_SETCURSEL, d, 0); + SendMessage(h, CB_SETCURSEL, temp_lpt_devices[i], 0); + + h=GetDlgItem(hdlg, IDC_CHECK_PARALLEL1 + i); + SendMessage(h, BM_SETCHECK, temp_lpt[i], 0); } - h=GetDlgItem(hdlg, IDC_CHECK_SERIAL1); - SendMessage(h, BM_SETCHECK, temp_serial[0], 0); - - h=GetDlgItem(hdlg, IDC_CHECK_SERIAL2); - SendMessage(h, BM_SETCHECK, temp_serial[1], 0); - - h=GetDlgItem(hdlg, IDC_CHECK_PARALLEL); - SendMessage(h, BM_SETCHECK, temp_lpt, 0); + for (i = 0; i < 2; i++) { + h=GetDlgItem(hdlg, IDC_CHECK_SERIAL1 + i); + SendMessage(h, BM_SETCHECK, temp_serial[i], 0); + } free(lptsTemp); @@ -1341,18 +1447,16 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_SAVESETTINGS: for (i = 0; i < 3; i++) { h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); - c = SendMessage(h, CB_GETCURSEL, 0, 0); - strcpy(temp_lpt_device_names[i], lpt_device_get_internal_name(c)); + temp_lpt_devices[i] = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_PARALLEL1 + i); + temp_lpt[i] = SendMessage(h, BM_GETCHECK, 0, 0); } - h = GetDlgItem(hdlg, IDC_CHECK_SERIAL1); - temp_serial[0] = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_SERIAL2); - temp_serial[1] = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_PARALLEL); - temp_lpt = SendMessage(h, BM_GETCHECK, 0, 0); + for (i = 0; i < 2; i++) { + h = GetDlgItem(hdlg, IDC_CHECK_SERIAL1 + i); + temp_serial[i] = SendMessage(h, BM_GETCHECK, 0, 0); + } default: return FALSE; @@ -1362,67 +1466,48 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) static void -recalc_hdc_list(HWND hdlg, int machine, int use_selected_hdc) +recalc_hdc_list(HWND hdlg) { - HWND h; - char *s, old_name[32]; - int valid, c, d; - - LPTSTR lptsTemp; - - lptsTemp = (LPTSTR) malloc(512); - - h = GetDlgItem(hdlg, IDC_COMBO_HDC); - - valid = 0; - - if (use_selected_hdc) { - c = SendMessage(h, CB_GETCURSEL, 0, 0); - - if (c != -1 && hdc_names[c]) - strncpy(old_name, hdc_names[c], sizeof(old_name) - 1); - else - strcpy(old_name, "none"); - } else - strncpy(old_name, temp_hdc_name, sizeof(old_name) - 1); + HWND h = GetDlgItem(hdlg, IDC_COMBO_HDC); + int c = 0, d = 0; + int found_card = 0; + WCHAR szText[512]; SendMessage(h, CB_RESETCONTENT, 0, 0); - c = d = 0; + SendMessage(h, CB_SETCURSEL, 0, 0); + while (1) { - s = hdc_get_name(c); - if (s[0] == 0) + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && !(machines[temp_machine].flags & MACHINE_HDC)) { + c++; + continue; + } + + char *s = hdc_get_name(c); + + if (!s[0]) break; - if (c==1 && !(machines[temp_machine].flags&MACHINE_HDC)) { - /* Skip "Internal" if machine doesn't have one. */ - c++; - continue; - } - if (!hdc_available(c) || !device_is_valid(hdc_get_device(c), machines[temp_machine].flags)) { - c++; - continue; - } - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - hdc_names[d] = hdc_get_internal_name(c); - if (!strcmp(old_name, hdc_names[d])) { - SendMessage(h, CB_SETCURSEL, d, 0); - valid = 1; + if (hdc_available(c) && + device_is_valid(hdc_get_device(c), machines[temp_machine].flags)) { + mbstowcs(szText, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if (c == temp_hdc) { + SendMessage(h, CB_SETCURSEL, d, 0); + found_card = 1; + } + + d++; } + c++; - d++; } - - if (!valid) + if (!found_card) SendMessage(h, CB_SETCURSEL, 0, 0); - - EnableWindow(h, d ? TRUE : FALSE); - - free(lptsTemp); } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -1430,13 +1515,27 @@ static BOOL CALLBACK win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h; - int c, d, temp_hdc_type; + int c, d; + int e; LPTSTR lptsTemp; + char *stransi; const device_t *scsi_dev; + const device_t *dev; + char *s; switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); + + /*HD controller config*/ + recalc_hdc_list(hdlg); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + if (hdc_has_config(temp_hdc)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); /*SCSI config*/ h = GetDlgItem(hdlg, IDC_COMBO_SCSI); @@ -1447,7 +1546,7 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa if (!s[0]) break; - settings_device_to_list[c] = d; + settings_device_to_list[0][c] = d; if (scsi_card_available(c)) { scsi_dev = scsi_card_getdevice(c); @@ -1459,25 +1558,20 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa mbstowcs(lptsTemp, s, strlen(s) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); } - settings_list_to_device[d] = c; + settings_list_to_device[0][d] = c; d++; } } c++; } - SendMessage(h, CB_SETCURSEL, settings_device_to_list[temp_scsi_card], 0); + SendMessage(h, CB_SETCURSEL, settings_device_to_list[0][temp_scsi_card], 0); EnableWindow(h, d ? TRUE : FALSE); h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); EnableWindow(h, scsi_card_has_config(temp_scsi_card) ? TRUE : FALSE); - recalc_hdc_list(hdlg, temp_machine, 0); - - h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); - EnableWindow(h, hdc_has_config(hdc_get_from_internal_name(temp_hdc_name)) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); EnableWindow(h, (machines[temp_machine].flags & MACHINE_AT) ? TRUE : FALSE); @@ -1499,37 +1593,109 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa h=GetDlgItem(hdlg, IDC_CHECK_BUGGER); SendMessage(h, BM_SETCHECK, temp_bugger, 0); + /* Populate the ISA RTC card dropdown. */ + e = 0; + h = GetDlgItem(hdlg, IDC_COMBO_ISARTC); + for (d = 0; ; d++) { + s = isartc_get_name(d); + if (!s[0]) + break; + + settings_device_to_list[1][d] = e; + + if (d == 0) { + /* Translate "None". */ + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + } else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + settings_list_to_device[1][e] = d; + e++; + } + SendMessage(h, CB_SETCURSEL, temp_isartc, 0); + h = GetDlgItem(hdlg, IDC_CONFIGURE_ISARTC); + if (temp_isartc != 0) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + /* Populate the ISA memory card dropdowns. */ + for (c = 0; c < ISAMEM_MAX; c++) { + h = GetDlgItem(hdlg, IDC_COMBO_ISAMEM_1 + c); + for (d = 0; ; d++) { + s = (char *) isamem_get_internal_name(d); + if (s == NULL) + break; + + if (d == 0) { + /* Translate "None". */ + SendMessage(h, CB_ADDSTRING, 0, + (LPARAM)win_get_string(IDS_2112)); + } else { + s = (char *) isamem_get_name(d); + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)lptsTemp); + } + } + SendMessage(h, CB_SETCURSEL, temp_isamem[c], 0); + h = GetDlgItem(hdlg, IDC_CONFIGURE_ISAMEM_1 + c); + if (temp_isamem[c] != 0) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + } + + free(stransi); free(lptsTemp); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { - case IDC_COMBO_HDC: - h = GetDlgItem(hdlg, IDC_COMBO_HDC); - temp_hdc_type = hdc_get_from_internal_name(hdc_names[SendMessage(h, CB_GETCURSEL, 0, 0)]); + case IDC_CONFIGURE_HDC: + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); - h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); - EnableWindow(h, hdc_has_config(temp_hdc_type) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)hdc_get_device(hdc_get_id(stransi))); + + free(stransi); + free(lptsTemp); break; - case IDC_CONFIGURE_HDC: - h = GetDlgItem(hdlg, IDC_COMBO_HDC); - temp_hdc_type = hdc_get_from_internal_name(hdc_names[SendMessage(h, CB_GETCURSEL, 0, 0)]); + case IDC_COMBO_HDC: + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); - temp_deviceconfig |= deviceconfig_open(hdlg, (void *)hdc_get_device(temp_hdc_type)); + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_hdc = hdc_get_id(stransi); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + if (hdc_has_config(temp_hdc)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + free(stransi); + free(lptsTemp); break; case IDC_CONFIGURE_SCSI: h = GetDlgItem(hdlg, IDC_COMBO_SCSI); - temp_scsi_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_scsi_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)scsi_card_getdevice(temp_scsi_card)); break; case IDC_COMBO_SCSI: h = GetDlgItem(hdlg, IDC_COMBO_SCSI); - temp_scsi_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_scsi_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); if (scsi_card_has_config(temp_scsi_card)) @@ -1538,6 +1704,48 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa EnableWindow(h, FALSE); break; + case IDC_CONFIGURE_ISARTC: + h = GetDlgItem(hdlg, IDC_COMBO_ISARTC); + temp_isartc = settings_list_to_device[1][SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)isartc_get_device(temp_isartc)); + break; + + case IDC_COMBO_ISARTC: + h = GetDlgItem(hdlg, IDC_COMBO_ISARTC); + temp_isartc = settings_list_to_device[1][SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_ISARTC); + if (temp_isartc != 0) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_COMBO_ISAMEM_1: + case IDC_COMBO_ISAMEM_2: + case IDC_COMBO_ISAMEM_3: + case IDC_COMBO_ISAMEM_4: + c = LOWORD(wParam) - IDC_COMBO_ISAMEM_1; + h = GetDlgItem(hdlg, LOWORD(wParam)); + temp_isamem[c] = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_ISAMEM_1 + c); + if (temp_isamem[c] != 0) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGURE_ISAMEM_1: + case IDC_CONFIGURE_ISAMEM_2: + case IDC_CONFIGURE_ISAMEM_3: + case IDC_CONFIGURE_ISAMEM_4: + c = LOWORD(wParam) - IDC_CONFIGURE_ISAMEM_1; + dev = isamem_get_device(temp_isamem[c]); + temp_deviceconfig |= deviceconfig_inst_open(hdlg, (void *)dev, c + 1); + break; + case IDC_CHECK_IDE_TER: h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); @@ -1565,15 +1773,19 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa return FALSE; case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); + h = GetDlgItem(hdlg, IDC_COMBO_HDC); - c = SendMessage(h, CB_GETCURSEL, 0, 0); - if (hdc_names[c]) - strncpy(temp_hdc_name, hdc_names[c], sizeof(temp_hdc_name) - 1); - else - strcpy(temp_hdc_name, "none"); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_hdc = hdc_get_id(stransi); h = GetDlgItem(hdlg, IDC_COMBO_SCSI); - temp_scsi_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_scsi_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_ISARTC); + temp_isartc = settings_list_to_device[1][SendMessage(h, CB_GETCURSEL, 0, 0)]; h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); @@ -1584,6 +1796,9 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa h = GetDlgItem(hdlg, IDC_CHECK_BUGGER); temp_bugger = SendMessage(h, BM_GETCHECK, 0, 0); + free(stransi); + free(lptsTemp); + default: return FALSE; } @@ -1624,7 +1839,7 @@ static void network_recalc_combos(HWND hdlg) } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -1638,7 +1853,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"None"); @@ -1668,7 +1883,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (s[0] == '\0') break; - settings_device_to_list[c] = d; + settings_device_to_list[0][c] = d; if (network_card_available(c) && device_is_valid(network_card_getdevice(c), machines[temp_machine].flags)) { if (c == 0) @@ -1677,14 +1892,14 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) mbstowcs(lptsTemp, s, strlen(s) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); } - settings_list_to_device[d] = c; + settings_list_to_device[0][d] = c; d++; } c++; } - SendMessage(h, CB_SETCURSEL, settings_device_to_list[temp_net_card], 0); + SendMessage(h, CB_SETCURSEL, settings_device_to_list[0][temp_net_card], 0); EnableWindow(h, d ? TRUE : FALSE); network_recalc_combos(hdlg); free(lptsTemp); @@ -1719,7 +1934,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return FALSE; h = GetDlgItem(hdlg, IDC_COMBO_NET); - temp_net_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_net_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; network_recalc_combos(hdlg); break; @@ -1729,7 +1944,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return FALSE; h = GetDlgItem(hdlg, IDC_COMBO_NET); - temp_net_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_net_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; temp_deviceconfig |= deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_net_card)); break; @@ -1745,7 +1960,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); h = GetDlgItem(hdlg, IDC_COMBO_NET); - temp_net_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_net_card = settings_list_to_device[0][SendMessage(h, CB_GETCURSEL, 0, 0)]; default: return FALSE; @@ -1803,7 +2018,7 @@ add_locations(HWND hdlg) HWND h; int i = 0; - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); for (i = 0; i < 5; i++) @@ -1964,7 +2179,7 @@ recalc_location_controls(HWND hdlg, int is_add_dlg, int assign_id) EnableWindow(h, TRUE); if (assign_id) - next_free_scsi_id((uint8_t *) is_add_dlg ? &new_hdd.scsi_id : &temp_hdd[lv1_current_sel].scsi_id); + next_free_scsi_id((uint8_t *) (is_add_dlg ? &(new_hdd.scsi_id) : &(temp_hdd[lv1_current_sel].scsi_id))); h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); ShowWindow(h, SW_SHOW); @@ -2352,7 +2567,7 @@ recalc_selection(HWND hdlg) } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -2371,6 +2586,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM uint8_t id = 0; wchar_t *twcs; vhd_footer_t *vft = NULL; + MSG msg; switch (message) { case WM_INITDIALOG: @@ -2528,7 +2744,8 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM fwrite(&zero, 1, 4, f); /* 00000004: [Translation] Heads per cylinder */ } - memset(buf, 0, 512); + big_buf = (char *) malloc(1048576); + memset(big_buf, 0, 1048576); temp_size = size; @@ -2559,19 +2776,23 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM ShowWindow(h, SW_SHOW); } + h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); + if (size) { - fwrite(buf, 1, size, f); + fwrite(big_buf, 1, size, f); SendMessage(h, PBM_SETPOS, (WPARAM) 1, (LPARAM) 0); } if (r) { - big_buf = (char *) malloc(1048576); - memset(big_buf, 0, 1048576); for (i = 0; i < r; i++) { fwrite(big_buf, 1, 1048576, f); SendMessage(h, PBM_SETPOS, (WPARAM) (size + 1), (LPARAM) 0); + + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } } - free(big_buf); } if (image_is_vhd(hd_file_name, 0)) { @@ -2583,14 +2804,14 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM vft->geom.heads = hpc; vft->geom.spt = spt; generate_vhd_checksum(vft); - memset(buf, 0, 512); - vhd_footer_to_bytes((uint8_t *) buf, vft); - fwrite(buf, 1, 512, f); - memset(buf, 0, 512); + vhd_footer_to_bytes((uint8_t *) big_buf, vft); + fwrite(big_buf, 1, 512, f); free(vft); vft = NULL; } + free(big_buf); + fclose(f); settings_msgbox(MBX_INFO, (wchar_t *)IDS_4113); } @@ -2726,15 +2947,15 @@ hdd_add_file_open_error: get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &temp); if (tracks != (int64_t) temp) { tracks = temp; - size = (tracks * hpc * spt) << 9LL; + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (tracks > max_tracks) { tracks = max_tracks; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, (uint32_t) tracks); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -2750,15 +2971,15 @@ hdd_add_file_open_error: get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &temp); if (hpc != (int64_t) temp) { hpc = temp; - size = (tracks * hpc * spt) << 9LL; + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (hpc > max_hpc) { hpc = max_hpc; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, (uint32_t) hpc); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -2774,14 +2995,14 @@ hdd_add_file_open_error: get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &temp); if (spt != (int64_t) temp) { spt = temp; - size = (tracks * hpc * spt) << 9LL; + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (spt > max_spt) { spt = max_spt; - size = (tracks * hpc * spt) << 9LL; + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); @@ -2800,32 +3021,32 @@ hdd_add_file_open_error: size = ((uint64_t) temp) << 20LL; /* This is needed to ensure VHD standard compliance. */ hdd_image_calc_chs((uint32_t *) &tracks, (uint32_t *) &hpc, (uint32_t *) &spt, temp); - set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); - set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, (uint32_t) tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, (uint32_t) hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, (uint32_t) spt); recalc_selection(hdlg); } if (tracks > max_tracks) { tracks = max_tracks; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, (uint32_t) tracks); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (hpc > max_hpc) { hpc = max_hpc; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, (uint32_t) hpc); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (spt > max_spt) { spt = max_spt; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, (uint32_t) spt); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -2844,10 +3065,10 @@ hdd_add_file_open_error: tracks = hdd_table[selection][0]; hpc = hdd_table[selection][1]; spt = hdd_table[selection][2]; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); - set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, (uint32_t) tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, (uint32_t) hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, (uint32_t) spt); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); } else if ((temp != selection) && (temp == 127)) selection = temp; @@ -2855,32 +3076,32 @@ hdd_add_file_open_error: selection = temp; hpc = 16; spt = 63; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, (uint32_t) hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, (uint32_t) spt); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); } if (spt > max_spt) { spt = max_spt; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, (uint32_t) spt); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (hpc > max_hpc) { hpc = max_hpc; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, (uint32_t) hpc); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (tracks > max_tracks) { tracks = max_tracks; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, (uint32_t) tracks); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -2907,16 +3128,20 @@ hdd_add_file_open_error: max_spt = max_hpc = max_tracks = 0; break; case HDD_BUS_MFM: - max_spt = 17; + max_spt = 26; /* 17 for MFM, 26 for RLL. */ max_hpc = 15; max_tracks = 1023; break; - case HDD_BUS_ESDI: case HDD_BUS_XTA: max_spt = 63; max_hpc = 16; max_tracks = 1023; break; + case HDD_BUS_ESDI: + max_spt = 99; /* ESDI drives usually had 32 to 43 sectors per track. */ + max_hpc = 16; + max_tracks = 266305; + break; case HDD_BUS_IDE: max_spt = 63; max_hpc = 255; @@ -2944,24 +3169,24 @@ hdd_add_file_open_error: if (spt > max_spt) { spt = max_spt; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, (uint32_t) spt); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (hpc > max_hpc) { hpc = max_hpc; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, (uint32_t) hpc); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (tracks > max_tracks) { tracks = max_tracks; - size = (tracks * hpc * spt) << 9LL; - set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + size = ((uint64_t) tracks * (uint64_t) hpc * (uint64_t) spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, (uint32_t) tracks); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -3050,14 +3275,14 @@ hard_disk_track_all(void) } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK #endif win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; + HWND h = NULL; int old_sel = 0, b = 0, assign = 0; const uint8_t hd_icons[2] = { 64, 0 }; @@ -3195,7 +3420,7 @@ hd_bus_skip: return FALSE; case IDC_BUTTON_HDD_REMOVE: - memcpy(temp_hdd[lv1_current_sel].fn, L"", 4); + memcpy(temp_hdd[lv1_current_sel].fn, L"", sizeof(L"")); hard_disk_untrack(lv1_current_sel); temp_hdd[lv1_current_sel].bus = HDD_BUS_DISABLED; /* Only set the bus to zero, the list normalize code below will take care of turning this entire entry to a complete zero. */ normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. */ @@ -3294,22 +3519,22 @@ win_settings_cdrom_drives_recalc_list(HWND hwndList) lvI.stateMask = lvI.iSubItem = lvI.state = 0; for (i = 0; i < 4; i++) { - fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + fsid = combo_id_to_format_string_id(temp_cdrom[i].bus_type); lvI.iSubItem = 0; - switch (temp_cdrom_drives[i].bus_type) { + switch (temp_cdrom[i].bus_type) { case CDROM_BUS_DISABLED: default: lvI.pszText = plat_get_string(fsid); lvI.iImage = 0; break; case CDROM_BUS_ATAPI: - wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].ide_channel >> 1, temp_cdrom[i].ide_channel & 1); lvI.pszText = szText; lvI.iImage = 1; break; case CDROM_BUS_SCSI: - wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].scsi_device_id); + wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].scsi_device_id); lvI.pszText = szText; lvI.iImage = 1; break; @@ -3321,10 +3546,10 @@ win_settings_cdrom_drives_recalc_list(HWND hwndList) return FALSE; lvI.iSubItem = 1; - if (temp_cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) + if (temp_cdrom[i].bus_type == CDROM_BUS_DISABLED) lvI.pszText = plat_get_string(IDS_2112); else { - wsprintf(szText, L"%ix", temp_cdrom_drives[i].speed); + wsprintf(szText, L"%ix", temp_cdrom[i].speed); lvI.pszText = szText; } lvI.iItem = i; @@ -3557,21 +3782,21 @@ win_settings_cdrom_drives_update_item(HWND hwndList, int i) lvI.iSubItem = 0; lvI.iItem = i; - fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + fsid = combo_id_to_format_string_id(temp_cdrom[i].bus_type); - switch (temp_cdrom_drives[i].bus_type) { + switch (temp_cdrom[i].bus_type) { case CDROM_BUS_DISABLED: default: lvI.pszText = plat_get_string(fsid); lvI.iImage = 0; break; case CDROM_BUS_ATAPI: - wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].ide_channel >> 1, temp_cdrom[i].ide_channel & 1); lvI.pszText = szText; lvI.iImage = 1; break; case CDROM_BUS_SCSI: - wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].scsi_device_id); + wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].scsi_device_id); lvI.pszText = szText; lvI.iImage = 1; break; @@ -3581,10 +3806,10 @@ win_settings_cdrom_drives_update_item(HWND hwndList, int i) return; lvI.iSubItem = 1; - if (temp_cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) + if (temp_cdrom[i].bus_type == CDROM_BUS_DISABLED) lvI.pszText = plat_get_string(IDS_2112); else { - wsprintf(szText, L"%ix", temp_cdrom_drives[i].speed); + wsprintf(szText, L"%ix", temp_cdrom[i].speed); lvI.pszText = szText; } lvI.iItem = i; @@ -3648,7 +3873,7 @@ cdrom_add_locations(HWND hdlg) HWND h; int i = 0; - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); for (i = CDROM_BUS_DISABLED; i <= CDROM_BUS_SCSI; i++) { @@ -3683,7 +3908,7 @@ static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) int i = 0; HWND h; - int bus = temp_cdrom_drives[lv1_current_sel].bus_type; + int bus = temp_cdrom[lv1_current_sel].bus_type; for (i = IDT_1741; i < (IDT_1742 + 1); i++) { h = GetDlgItem(hdlg, i); @@ -3706,7 +3931,7 @@ static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) } else { ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[lv1_current_sel].speed - 1, 0); + SendMessage(h, CB_SETCURSEL, temp_cdrom[lv1_current_sel].speed - 1, 0); } h = GetDlgItem(hdlg, IDT_1758); @@ -3725,12 +3950,12 @@ static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) EnableWindow(h, TRUE); if (assign_id) - temp_cdrom_drives[lv1_current_sel].ide_channel = next_free_ide_channel(); + temp_cdrom[lv1_current_sel].ide_channel = next_free_ide_channel(); h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[lv1_current_sel].ide_channel, 0); + SendMessage(h, CB_SETCURSEL, temp_cdrom[lv1_current_sel].ide_channel, 0); break; case CDROM_BUS_SCSI: /* SCSI */ h = GetDlgItem(hdlg, IDT_1741); @@ -3738,12 +3963,12 @@ static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) EnableWindow(h, TRUE); if (assign_id) - next_free_scsi_id((uint8_t *) &temp_cdrom_drives[lv1_current_sel].scsi_device_id); + next_free_scsi_id((uint8_t *) &temp_cdrom[lv1_current_sel].scsi_device_id); h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); - SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[lv1_current_sel].scsi_device_id, 0); + SendMessage(h, CB_SETCURSEL, temp_cdrom[lv1_current_sel].scsi_device_id, 0); break; } } @@ -3756,7 +3981,7 @@ zip_add_locations(HWND hdlg) HWND h; int i = 0; - lptsTemp = (LPTSTR) malloc(512); + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); for (i = ZIP_BUS_DISABLED; i <= ZIP_BUS_SCSI; i++) { @@ -3846,20 +4071,20 @@ zip_recalc_location_controls(HWND hdlg, int assign_id) static void cdrom_track(uint8_t id) { - if (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI) - ide_tracking |= (2 << (temp_cdrom_drives[id].ide_channel << 3)); - else if (temp_cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - scsi_tracking[temp_cdrom_drives[id].scsi_device_id >> 3] |= (1 << (temp_cdrom_drives[id].scsi_device_id & 0x07)); + if (temp_cdrom[id].bus_type == CDROM_BUS_ATAPI) + ide_tracking |= (2 << (temp_cdrom[id].ide_channel << 3)); + else if (temp_cdrom[id].bus_type == CDROM_BUS_SCSI) + scsi_tracking[temp_cdrom[id].scsi_device_id >> 3] |= (1 << (temp_cdrom[id].scsi_device_id & 0x07)); } static void cdrom_untrack(uint8_t id) { - if (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI) - ide_tracking &= ~(2 << (temp_cdrom_drives[id].ide_channel << 3)); - else if (temp_cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - scsi_tracking[temp_cdrom_drives[id].scsi_device_id >> 3] &= ~(1 << (temp_cdrom_drives[id].scsi_device_id & 0x07)); + if (temp_cdrom[id].bus_type == CDROM_BUS_ATAPI) + ide_tracking &= ~(2 << (temp_cdrom[id].ide_channel << 3)); + else if (temp_cdrom[id].bus_type == CDROM_BUS_SCSI) + scsi_tracking[temp_cdrom[id].scsi_device_id >> 3] &= ~(1 << (temp_cdrom[id].scsi_device_id & 0x07)); } @@ -3883,14 +4108,14 @@ zip_untrack(uint8_t id) } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK #endif win_settings_floppy_drives_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; + HWND h = NULL; int i = 0, old_sel = 0; WCHAR szText[256]; const uint8_t fd_icons[15] = { 248, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 0 }; @@ -3989,14 +4214,14 @@ win_settings_floppy_drives_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM l } -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK #endif win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; + HWND h = NULL; int old_sel = 0, b = 0, assign = 0; uint32_t b2 = 0; const uint8_t cd_icons[3] = { 249, 32, 0 }; @@ -4016,7 +4241,7 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); - switch (temp_cdrom_drives[lv1_current_sel].bus_type) { + switch (temp_cdrom[lv1_current_sel].bus_type) { case CDROM_BUS_DISABLED: default: b = 0; @@ -4083,7 +4308,7 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); - switch (temp_cdrom_drives[lv1_current_sel].bus_type) { + switch (temp_cdrom[lv1_current_sel].bus_type) { case CDROM_BUS_DISABLED: default: b = 0; @@ -4157,13 +4382,13 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam b2 = CDROM_BUS_SCSI; break; } - if (b2 == temp_cdrom_drives[lv1_current_sel].bus_type) + if (b2 == temp_cdrom[lv1_current_sel].bus_type) break; cdrom_untrack(lv1_current_sel); - assign = (temp_cdrom_drives[lv1_current_sel].bus_type == b2) ? 0 : 1; - if (temp_cdrom_drives[lv1_current_sel].bus_type == CDROM_BUS_DISABLED) - temp_cdrom_drives[lv1_current_sel].speed = 8; - temp_cdrom_drives[lv1_current_sel].bus_type = b2; + assign = (temp_cdrom[lv1_current_sel].bus_type == b2) ? 0 : 1; + if (temp_cdrom[lv1_current_sel].bus_type == CDROM_BUS_DISABLED) + temp_cdrom[lv1_current_sel].speed = 8; + temp_cdrom[lv1_current_sel].bus_type = b2; cdrom_recalc_location_controls(hdlg, assign); cdrom_track(lv1_current_sel); h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); @@ -4173,7 +4398,7 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam case IDC_COMBO_CD_ID: h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); cdrom_untrack(lv1_current_sel); - temp_cdrom_drives[lv1_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_cdrom[lv1_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); cdrom_track(lv1_current_sel); h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); win_settings_cdrom_drives_update_item(h, lv1_current_sel); @@ -4182,7 +4407,7 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam case IDC_COMBO_CD_CHANNEL_IDE: h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); cdrom_untrack(lv1_current_sel); - temp_cdrom_drives[lv1_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_cdrom[lv1_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); cdrom_track(lv1_current_sel); h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); win_settings_cdrom_drives_update_item(h, lv1_current_sel); @@ -4190,7 +4415,7 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam case IDC_COMBO_CD_SPEED: h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); - temp_cdrom_drives[lv1_current_sel].speed = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + temp_cdrom[lv1_current_sel].speed = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); win_settings_cdrom_drives_update_item(h, lv1_current_sel); break; @@ -4328,14 +4553,40 @@ win_settings_main_insert_categories(HWND hwndList) } -#ifdef __amd64__ + +#if defined(__amd64__) || defined(__aarch64__) +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_confirm(HWND hdlg, int button) +{ + int i; + + SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); + i = settings_msgbox_reset(); + if (i > 0) { + if (i == 2) + win_settings_save(); + + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + win_notify_dlg_closed(); + + return button ? TRUE : FALSE; + } else + return button ? FALSE : TRUE; +} + + +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK #endif win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; + HWND h = NULL; int category, i = 0, j = 0; const uint8_t cat_icons[11] = { 240, 241, 242, 243, 80, 244, 245, 64, 246, 247, 0 }; @@ -4343,13 +4594,12 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - plat_pause(1); win_settings_init(); displayed_category = -1; h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); image_list_init(h, (const uint8_t *) cat_icons); win_settings_main_insert_categories(h); - ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + ListView_SetItemState(h, first_cat, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); return TRUE; case WM_NOTIFY: if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_SETTINGSCATLIST)) { @@ -4364,25 +4614,16 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) win_settings_show_child(hdlg, category); } break; + case WM_CLOSE: + return win_settings_confirm(hdlg, 0); case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: - SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); - i = settings_msgbox_reset(); - if (i > 0) { - if (i == 2) - win_settings_save(); - - DestroyWindow(hwndChildDialog); - EndDialog(hdlg, 0); - plat_pause(0); - return TRUE; - } else - return FALSE; + return win_settings_confirm(hdlg, 1); case IDCANCEL: DestroyWindow(hwndChildDialog); EndDialog(hdlg, 0); - plat_pause(0); + win_notify_dlg_closed(); return TRUE; } break; @@ -4395,7 +4636,17 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) void -win_settings_open(HWND hwnd) +win_settings_open_ex(HWND hwnd, int category) { + win_notify_dlg_open(); + + first_cat = category; DialogBox(hinstance, (LPCWSTR)DLG_CONFIG, hwnd, win_settings_main_proc); } + + +void +win_settings_open(HWND hwnd) +{ + win_settings_open_ex(hwnd, SETTINGS_PAGE_MACHINE); +} diff --git a/src/win/win_snd_gain.c b/src/win/win_snd_gain.c index 6580fec7e..0dc4e5dcc 100644 --- a/src/win/win_snd_gain.c +++ b/src/win/win_snd_gain.c @@ -35,7 +35,7 @@ static uint8_t old_gain; -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index 750b8837d..ede2cb271 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -8,13 +8,13 @@ * * Implement the application's Status Bar. * - * Version: @(#)win_stbar.c 1.0.18 2018/05/25 + * Version: @(#)win_stbar.c 1.0.27 2019/12/06 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #define UNICODE #define BITMAP WINDOWS_BITMAP @@ -33,14 +33,16 @@ #include "../cpu/cpu.h" #include "../device.h" #include "../machine/machine.h" +#include "../timer.h" #include "../disk/hdd.h" #include "../disk/hdc.h" #include "../floppy/fdd.h" +#include "../floppy/fdd_86f.h" #include "../scsi/scsi.h" +#include "../scsi/scsi_device.h" #include "../cdrom/cdrom.h" #include "../disk/zip.h" #include "../cdrom/cdrom_image.h" -#include "../cdrom/cdrom_null.h" #include "../scsi/scsi_disk.h" #include "../network/network.h" #include "../video/video.h" @@ -152,13 +154,13 @@ StatusBarCreateCdromSubmenu(HMENU m, int id) AppendMenu(m, MF_STRING, IDM_CDROM_IMAGE | id, plat_get_string(IDS_2089)); - if (! cdrom_drives[id].sound_on) + if (! cdrom[id].sound_on) CheckMenuItem(m, IDM_CDROM_MUTE | id, MF_CHECKED); - if (cdrom_drives[id].host_drive == 200) + if (cdrom[id].host_drive == 200) CheckMenuItem(m, IDM_CDROM_IMAGE | id, MF_CHECKED); else { - cdrom_drives[id].host_drive = 0; + cdrom[id].host_drive = 0; CheckMenuItem(m, IDM_CDROM_EMPTY | id, MF_CHECKED); } } @@ -190,6 +192,19 @@ StatusBarCreateZIPSubmenu(HMENU m, int id) } +void +ui_sb_timer_callback(int pane) +{ + sb_part_icons[pane] &= ~1; + + if (sb_part_icons && sb_part_icons[pane]) { + SendMessage(hwndSBAR, SB_SETICON, pane, + (LPARAM)hIcon[sb_part_icons[pane]]); + } +} + + + /* API */ /* API: update one of the icons after activity. */ void @@ -197,19 +212,20 @@ ui_sb_update_icon(int tag, int active) { uint8_t found = 0xff; - if (!update_icons) + if (!update_icons || !sb_ready) return; - if (((tag & 0xf0) >= SB_TEXT) || !sb_ready) + if (((tag & 0xf0) >= SB_TEXT)) return; found = sb_map[tag]; - if (found != 0xff) { - sb_part_icons[found] &= ~1; - sb_part_icons[found] |= (uint8_t) active; + if ((found != 0xff) && ((sb_part_icons[found] ^ active) & 1) && active) { + sb_part_icons[found] |= 1; SendMessage(hwndSBAR, SB_SETICON, found, (LPARAM)hIcon[sb_part_icons[found]]); + + SetTimer(hwndMain, 0x8000 | found, 75, NULL); } } @@ -220,7 +236,7 @@ ui_sb_update_icon_state(int tag, int state) { uint8_t found = 0xff; - if (((tag & 0xf0) >= SB_HDD) || !sb_ready) + if (!sb_ready || ((tag & 0xf0) >= SB_HDD)) return; found = sb_map[tag]; @@ -268,16 +284,16 @@ StatusBarCreateCdromTip(int part) WCHAR *szText; int id; int drive = sb_part_meanings[part] & 0xf; - int bus = cdrom_drives[drive].bus_type; + int bus = cdrom[drive].bus_type; id = IDS_5377 + (bus - 1); szText = plat_get_string(id); - if (cdrom_drives[drive].host_drive == 200) { - if (wcslen(cdrom_image[drive].image_path) == 0) + if (cdrom[drive].host_drive == 200) { + if (wcslen(cdrom[drive].image_path) == 0) _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); else - _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, cdrom_image[drive].image_path); + _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, cdrom[drive].image_path); } else _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); @@ -285,7 +301,7 @@ StatusBarCreateCdromTip(int part) free(sbTips[part]); sbTips[part] = NULL; } - sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 4); wcscpy(sbTips[part], tempTip); } @@ -374,7 +390,8 @@ ui_sb_update_tip(int meaning) { uint8_t part = 0xff; - if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) return; + if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) + return; part = sb_map[meaning]; @@ -467,6 +484,14 @@ StatusBarCreatePopupMenu(int part) } +/* API: mark the status bar as not ready. */ +void +ui_sb_set_ready(int ready) +{ + sb_ready = ready; +} + + /* API: update the status bar panes. */ void ui_sb_update_panes(void) @@ -476,8 +501,14 @@ ui_sb_update_panes(void) int c_mfm, c_esdi, c_xta; int c_ide, c_scsi; int do_net; + char *hdc_name; - sb_ready = 0; + if (!config_changed) + return; + + if (sb_ready) { + sb_ready = 0; + } hdint = (machines[machine].flags & MACHINE_HDC) ? 1 : 0; c_mfm = hdd_count(HDD_BUS_MFM); @@ -515,16 +546,17 @@ ui_sb_update_panes(void) if (fdd_get_type(i) != 0) sb_parts++; } + hdc_name = hdc_get_internal_name(hdc_current); for (i=0; ihandler->exit(id); - cdrom_close_handler(id); - memset(cdrom_image[id].image_path, 0, 2048); - image_open(id, temp_path); + wcscpy(cdrom[id].prev_image_path, cdrom[id].image_path); + if (cdrom[id].ops && cdrom[id].ops->exit) + cdrom[id].ops->exit(&(cdrom[id])); + cdrom[id].ops = NULL; + memset(cdrom[id].image_path, 0, sizeof(cdrom[id].image_path)); + cdrom_image_open(&(cdrom[id]), temp_path); /* Signal media change to the emulated machine. */ - cdrom_insert(cdrom[id]); - CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); - cdrom_drives[id].host_drive = (wcslen(cdrom_image[id].image_path) == 0) ? 0 : 200; - if (cdrom_drives[id].host_drive == 200) { + if (cdrom[id].insert) + cdrom[id].insert(cdrom[id].priv); + cdrom[id].host_drive = (wcslen(cdrom[id].image_path) == 0) ? 0 : 200; + if (cdrom[id].host_drive == 200) { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_CHECKED); ui_sb_update_icon_state(SB_CDROM | id, 0); } else { CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_UNCHECKED); - CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_CHECKED); ui_sb_update_icon_state(SB_CDROM | id, 1); } EnableMenuItem(sb_menu_handles[part], IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); @@ -1061,6 +1110,9 @@ ui_sb_check_menu_item(int tag, int id, int chk) { uint8_t part; + if (!sb_ready) + return; + part = sb_map[tag]; if ((part == 0xff) || (sb_menu_handles == NULL)) return; @@ -1075,6 +1127,9 @@ ui_sb_enable_menu_item(int tag, int id, int flg) { uint8_t part; + if (!sb_ready) + return; + part = sb_map[tag]; if ((part == 0xff) || (sb_menu_handles == NULL)) return; diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 735baa0a5..4e99eebb4 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -8,15 +8,16 @@ * * user Interface module for WinAPI on Windows. * - * Version: @(#)win_ui.c 1.0.29 2018/07/19 + * Version: @(#)win_ui.c 1.0.45 2019/12/05 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2019 GH Cao. */ #define UNICODE #include @@ -38,7 +39,9 @@ #include "../plat_midi.h" #include "../ui.h" #include "win.h" -#include "win_d3d.h" +#ifdef USE_DISCORD +# include "win_discord.h" +#endif #define TIMER_1SEC 1 /* ID of the one-second timer */ @@ -50,8 +53,11 @@ HWND hwndMain, /* application main window */ HMENU menuMain; /* application main menu */ HICON hIcon[256]; /* icon data loaded from resources */ RECT oldclip; /* mouse rect */ +int sbar_height = 23; /* statusbar height */ +int minimized = 0; int infocus = 1; int rctrl_is_lalt = 0; +int user_resize = 0; char openfilestring[260]; WCHAR wopenfilestring[260]; @@ -60,8 +66,8 @@ WCHAR wopenfilestring[260]; /* Local data. */ static wchar_t wTitle[512]; static HHOOK hKeyboardHook; -static int hook_enabled = 0; -static int save_window_pos = 0; +static int hook_enabled = 0, manager_wm = 0; +static int save_window_pos = 0, pause_state = 0; static int vis = -1; @@ -113,6 +119,12 @@ ResetAllMenus(void) EnableMenuItem(menuMain, IDM_CONFIG_SAVE, MF_DISABLED); #endif +#ifdef USE_D2D + /* Disable Direct2D menu option on NT5 */ + if(LOBYTE(LOWORD(GetVersion())) < 6) + EnableMenuItem(menuMain, IDM_VID_D2D, MF_GRAYED); +#endif + CheckMenuItem(menuMain, IDM_ACTION_RCTRL_IS_LALT, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_UPDATE_ICONS, MF_UNCHECKED); @@ -146,11 +158,13 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_INVERT, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_RESIZE, MF_UNCHECKED); - CheckMenuItem(menuMain, IDM_VID_DDRAW+0, MF_UNCHECKED); - CheckMenuItem(menuMain, IDM_VID_DDRAW+1, MF_UNCHECKED); - CheckMenuItem(menuMain, IDM_VID_DDRAW+2, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SDL_SW, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SDL_HW, MF_UNCHECKED); +#ifdef USE_D2D + CheckMenuItem(menuMain, IDM_VID_D2D, MF_UNCHECKED); +#endif #ifdef USE_VNC - CheckMenuItem(menuMain, IDM_VID_DDRAW+3, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_VNC, MF_UNCHECKED); #endif CheckMenuItem(menuMain, IDM_VID_FS_FULL+0, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_FS_FULL+1, MF_UNCHECKED); @@ -207,7 +221,7 @@ ResetAllMenus(void) if (vid_resize) CheckMenuItem(menuMain, IDM_VID_RESIZE, MF_CHECKED); - CheckMenuItem(menuMain, IDM_VID_DDRAW+vid_api, MF_CHECKED); + CheckMenuItem(menuMain, IDM_VID_SDL_SW+vid_api, MF_CHECKED); CheckMenuItem(menuMain, IDM_VID_FS_FULL+video_fullscreen_scale, MF_CHECKED); CheckMenuItem(menuMain, IDM_VID_REMEMBER, window_remember?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SCALE_1X+scale, MF_CHECKED); @@ -215,6 +229,13 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_CGACON, vid_cga_contrast?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_GRAYCT_601+video_graytype, MF_CHECKED); CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+video_grayscale, MF_CHECKED); + +#ifdef USE_DISCORD + if (discord_loaded) + CheckMenuItem(menuMain, IDM_DISCORD, enable_discord ? MF_CHECKED : MF_UNCHECKED); + else + EnableMenuItem(menuMain, IDM_DISCORD, MF_DISABLED); +#endif } @@ -251,12 +272,33 @@ LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) } +void +win_notify_dlg_open(void) +{ + manager_wm = 1; + pause_state = dopause; + plat_pause(1); + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDDLGSTATUS, (WPARAM) 1, (LPARAM) hwndMain); +} + + +void +win_notify_dlg_closed(void) +{ + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDDLGSTATUS, (WPARAM) 0, (LPARAM) hwndMain); + plat_pause(pause_state); + manager_wm = 0; +} + + static LRESULT CALLBACK MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HMENU hmenu; - int sb_borders[3]; + int i, sb_borders[3]; RECT rect; int temp_x, temp_y; @@ -278,7 +320,11 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_ACTION_HRESET: - pc_reset(1); + win_notify_dlg_open(); + i = ui_msgbox(MBX_QUESTION_YN, (wchar_t *)IDS_2121); + if (i == 0) + pc_reset(1); + win_notify_dlg_closed(); break; case IDM_ACTION_RESET_CAD: @@ -286,7 +332,14 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_ACTION_EXIT: - PostQuitMessage(0); + win_notify_dlg_open(); + i = ui_msgbox(MBX_QUESTION_YN, (wchar_t *)IDS_2122); + if (i == 0) { + UnhookWindowsHookEx(hKeyboardHook); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage(0); + } + win_notify_dlg_closed(); break; case IDM_ACTION_CTRL_ALT_ESC: @@ -321,7 +374,6 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_VID_RESIZE: vid_resize = !vid_resize; CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)? MF_CHECKED : MF_UNCHECKED); - GetWindowRect(hwnd, &rect); if (vid_resize) SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW) | WS_VISIBLE); @@ -330,11 +382,24 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); + GetWindowRect(hwnd, &rect); + /* Main Window. */ - MoveWindow(hwnd, rect.left, rect.top, - unscaled_size_x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), - unscaled_size_y + (GetSystemMetrics(SM_CYEDGE) * 2) + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 17 + sb_borders[1] + 1, - TRUE); + if (GetSystemMetrics(SM_CXPADDEDBORDER) == 0) { + /* For platforms that subsystem version < 6.0 (default on mingw/msys2) */ + /* In this case, border sizes are different between resizable and non-resizable window */ + MoveWindow(hwnd, rect.left, rect.top, + unscaled_size_x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), + unscaled_size_y + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, + TRUE); + } else { + /* For platforms that subsystem version >= 6.0 (default on llvm-mingw, mainly for Windows/ARM) */ + /* In this case, border sizes are the same between resizable and non-resizable window */ + MoveWindow(hwnd, rect.left, rect.top, + unscaled_size_x + ((GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2), + unscaled_size_y + ((GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, + TRUE); + } /* Render window. */ MoveWindow(hwndRender, 0, 0, unscaled_size_x, unscaled_size_y, TRUE); @@ -377,16 +442,17 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) config_save(); break; - case IDM_VID_DDRAW: + case IDM_VID_SDL_SW: + case IDM_VID_SDL_HW: +#ifdef USE_D2D case IDM_VID_D2D: - case IDM_VID_D3D: - case IDM_VID_SDL: +#endif #ifdef USE_VNC case IDM_VID_VNC: #endif - CheckMenuItem(hmenu, IDM_VID_DDRAW+vid_api, MF_UNCHECKED); - plat_setvid(LOWORD(wParam) - IDM_VID_DDRAW); - CheckMenuItem(hmenu, IDM_VID_DDRAW+vid_api, MF_CHECKED); + CheckMenuItem(hmenu, IDM_VID_SDL_SW + vid_api, MF_UNCHECKED); + plat_setvid(LOWORD(wParam) - IDM_VID_SDL_SW); + CheckMenuItem(hmenu, IDM_VID_SDL_SW + vid_api, MF_CHECKED); config_save(); break; @@ -397,9 +463,8 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_VID_FS_FULL: case IDM_VID_FS_43: - case IDM_VID_FS_SQ: + case IDM_VID_FS_KEEPRATIO: case IDM_VID_FS_INT: - case IDM_VID_FS_KEEPRATIO: 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); @@ -463,6 +528,19 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) config_save(); break; +#ifdef USE_DISCORD + case IDM_DISCORD: + if (! discord_loaded) break; + enable_discord ^= 1; + CheckMenuItem(hmenu, IDM_DISCORD, enable_discord ? MF_CHECKED : MF_UNCHECKED); + if(enable_discord) { + discord_init(); + discord_update_activity(dopause); + } else + discord_close(); + break; +#endif + #ifdef ENABLE_LOG_TOGGLES # ifdef ENABLE_BUSLOGIC_LOG case IDM_LOG_BUSLOGIC: @@ -532,10 +610,24 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_SIZE: + if (user_resize && !vid_resize) + break; + SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); temp_x = (lParam & 0xFFFF); - temp_y = (lParam >> 16) - (21 + sb_borders[1]); + temp_y = (lParam >> 16); + + if ((temp_x <= 0) || (temp_y <= 0)) { + minimized = 1; + break; + } else if (minimized == 1) { + minimized = 0; + video_force_resize_set(1); + } + + plat_vidapi_enable(0); + temp_y -= sbar_height; if (temp_x < 1) temp_x = 1; if (temp_y < 1) @@ -572,16 +664,12 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) window_h = rect.bottom - rect.top; save_window_pos = 1; } + plat_vidapi_enable(1); config_save(); break; case WM_MOVE: - /* If window is not resizable, then tell the main thread to - resize it, as sometimes, moves can mess up the window size. */ - if (!vid_resize) - doresize = 1; - if (window_remember) { GetWindowRect(hwnd, &rect); window_x = rect.left; @@ -593,20 +681,12 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_TIMER: - if (wParam == TIMER_1SEC) { + if (wParam == TIMER_1SEC) pc_onesec(); - } + else if ((wParam >= 0x8000) && (wParam <= 0x80ff)) + ui_sb_timer_callback(wParam & 0xff); break; - case WM_RESETD3D: - startblit(); - if (video_fullscreen) - d3d_reset_fs(); - else - d3d_reset(); - endblit(); - break; - case WM_LEAVEFULLSCREEN: plat_setfullscreen(0); config_save(); @@ -618,6 +698,17 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_SYSKEYUP: return(0); + case WM_CLOSE: + win_notify_dlg_open(); + i = ui_msgbox(MBX_QUESTION_YN, (wchar_t *)IDS_2122); + if (i == 0) { + UnhookWindowsHookEx(hKeyboardHook); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage(0); + } + win_notify_dlg_closed(); + break; + case WM_DESTROY: UnhookWindowsHookEx(hKeyboardHook); KillTimer(hwnd, TIMER_1SEC); @@ -625,12 +716,51 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_SHOWSETTINGS: + if (manager_wm) + break; + manager_wm = 1; win_settings_open(hwnd); + manager_wm = 0; break; case WM_PAUSE: + if (manager_wm) + break; + manager_wm = 1; plat_pause(dopause ^ 1); CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); + manager_wm = 0; + break; + + case WM_HARDRESET: + if (manager_wm) + break; + win_notify_dlg_open(); + i = ui_msgbox(MBX_QUESTION_YN, (wchar_t *)IDS_2121); + if (i == 0) + pc_reset(1); + win_notify_dlg_closed(); + break; + + case WM_SHUTDOWN: + if (manager_wm) + break; + win_notify_dlg_open(); + i = ui_msgbox(MBX_QUESTION_YN, (wchar_t *)IDS_2122); + if (i == 0) { + UnhookWindowsHookEx(hKeyboardHook); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage(0); + } + win_notify_dlg_closed(); + break; + + case WM_CTRLALTDEL: + if (manager_wm) + break; + manager_wm = 1; + pc_reset(0); + manager_wm = 0; break; case WM_SYSCOMMAND: @@ -665,6 +795,19 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) hook_enabled = 0; } break; + + case WM_ENTERSIZEMOVE: + user_resize = 1; + break; + + case WM_EXITSIZEMOVE: + user_resize = 0; + + /* If window is not resizable, then tell the main thread to + resize it, as sometimes, moves can mess up the window size. */ + if (!vid_resize) + doresize = 1; + break; } return(0); @@ -685,8 +828,9 @@ ui_init(int nCmdShow) WNDCLASSEX wincl; /* buffer for main window's class */ RAWINPUTDEVICE ridev; /* RawInput device */ MSG messages; /* received-messages buffer */ - HWND hwnd; /* handle for our window */ + HWND hwnd = NULL; /* handle for our window */ HACCEL haccel; /* handle to accelerator table */ + RECT sbar_rect; /* RECT of the status bar */ int bRet; if (settings_only) { @@ -703,6 +847,18 @@ ui_init(int nCmdShow) return(0); } +#ifdef USE_DISCORD + if(! discord_load()) { + enable_discord = 0; + } else if (enable_discord) { + /* Initialize the Discord API */ + discord_init(); + + /* Update Discord status */ + discord_update_activity(dopause); + } +#endif + /* Create our main window's class and register it. */ wincl.hInstance = hinstance; wincl.lpszClassName = CLASS_NAME; @@ -797,6 +953,12 @@ ui_init(int nCmdShow) /* Create the status bar window. */ StatusBarCreate(hwndMain, IDC_STATUS, hinstance); + /* Get the actual height of the statusbar, + * since that is not something we can change. + */ + GetWindowRect(hwndSBAR, &sbar_rect); + sbar_height = sbar_rect.bottom - sbar_rect.top; + /* * Before we can create the Render window, we first have * to prepare some other things that it depends on. @@ -835,7 +997,7 @@ ui_init(int nCmdShow) plat_resize(scrnsz_x, scrnsz_y); /* Fire up the machine. */ - pc_reset_hard(); + pc_reset_hard_init(); /* Set the PAUSE mode depending on the renderer. */ plat_pause(0); @@ -845,7 +1007,7 @@ ui_init(int nCmdShow) * the hWnd and unique ID the application has given * us. */ if (source_hwnd) - SendMessage((HWND) (uintptr_t) source_hwnd, WM_SENDHWND, (WPARAM) unique_id, (LPARAM) hwndMain); + PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDHWND, (WPARAM) unique_id, (LPARAM) hwndMain); /* * Everything has been configured, and all seems to work, @@ -883,6 +1045,12 @@ ui_init(int nCmdShow) /* Signal "exit fullscreen mode". */ plat_setfullscreen(0); } + +#ifdef USE_DISCORD + /* Run Discord API callbacks */ + if (enable_discord) + discord_run_callbacks(); +#endif } timeEndPeriod(1); @@ -898,6 +1066,11 @@ ui_init(int nCmdShow) win_mouse_close(); +#ifdef USE_DISCORD + /* Shut down the Discord integration */ + discord_close(); +#endif + return(messages.wParam); } @@ -933,7 +1106,13 @@ plat_pause(int p) p = get_vidpause(); /* If already so, done. */ - if (dopause == p) return; + if (dopause == p) { + /* Send the WM to a manager if needed. */ + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDSTATUS, (WPARAM) !!dopause, (LPARAM) hwndMain); + + return; + } if (p) { wcscpy(oldtitle, ui_window_title(NULL)); @@ -949,6 +1128,16 @@ plat_pause(int p) /* Update the actual menu. */ CheckMenuItem(menuMain, IDM_ACTION_PAUSE, (dopause) ? MF_CHECKED : MF_UNCHECKED); + +#if USE_DISCORD + /* Update Discord status */ + if(enable_discord) + discord_update_activity(dopause); +#endif + + /* Send the WM to a manager if needed. */ + if (source_hwnd) + PostMessage((HWND) (uintptr_t) source_hwnd, WM_SENDSTATUS, (WPARAM) !!dopause, (LPARAM) hwndMain); } @@ -962,14 +1151,26 @@ plat_resize(int x, int y) /* First, see if we should resize the UI window. */ if (!vid_resize) { video_wait_for_blit(); + SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); GetWindowRect(hwndMain, &r); - MoveWindow(hwndMain, r.left, r.top, - x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), - y + (GetSystemMetrics(SM_CYEDGE) * 2) + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 17 + sb_borders[1] + 1, - TRUE); - GetWindowRect(hwndMain, &r); + + if (GetSystemMetrics(SM_CXPADDEDBORDER) == 0) { + /* For platforms that subsystem version < 6.0 (gcc on mingw/msys2) */ + /* In this case, border sizes are different between resizable and non-resizable window */ + MoveWindow(hwndMain, r.left, r.top, + x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), + y + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, + TRUE); + } else { + /* For platforms that subsystem version >= 6.0 (clang/llvm on llvm-mingw, mainly for Windows/ARM) */ + /* In this case, border sizes are the same between resizable and non-resizable window */ + MoveWindow(hwndMain, r.left, r.top, + x + ((GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2), + y + ((GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, + TRUE); + } MoveWindow(hwndRender, 0, 0, x, y, TRUE); GetWindowRect(hwndRender, &r); @@ -1014,7 +1215,7 @@ plat_mouse_capture(int on) /* Catch WM_INPUT messages for 'current focus' window. */ static LONG_PTR input_orig_proc; static HWND input_orig_hwnd = NULL; -#ifdef __amd64__ +#if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else static BOOL CALLBACK @@ -1024,6 +1225,9 @@ input_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INPUT: keyboard_handle(lParam, infocus); +#ifndef USE_DINPUT + win_mouse_handle(lParam, infocus); +#endif break; case WM_SETFOCUS: @@ -1071,12 +1275,12 @@ plat_set_input(HWND h) { /* If needed, rest the old one first. */ if (input_orig_hwnd != NULL) { - SetWindowLongPtr(input_orig_hwnd, GWL_WNDPROC, + SetWindowLongPtr(input_orig_hwnd, GWLP_WNDPROC, (LONG_PTR)input_orig_proc); } /* Redirect the window procedure so we can catch WM_INPUT. */ input_orig_proc = GetWindowLongPtr(h, GWLP_WNDPROC); input_orig_hwnd = h; - SetWindowLongPtr(h, GWL_WNDPROC, (LONG_PTR)&input_proc); + SetWindowLongPtr(h, GWLP_WNDPROC, (LONG_PTR)&input_proc); }