diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 11fc491ef..e301d68ce 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: Feature request about: Suggest an idea for this project title: '' -labels: enhancement +labels: feature request assignees: '' --- diff --git a/README.md b/README.md index 5f823de0e..7984a775f 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ to retro computing and, of course, 86Box. We look forward to hearing from you! [![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/myzwyfX) +[![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](https://discord.gg/QXK9XTv) Getting started --------------- @@ -30,35 +30,27 @@ 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. If you do not want to use the shortcut, launch it with `\mingw32.exe`. +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 -f win/makefile.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 https://tinyurl.com/rs20191022. -8. Enjoy using and testing the emulator! :) +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 -------------- @@ -78,7 +70,7 @@ Jenkins instance. 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 - with 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/src/86box.h b/src/86box.h index 477051461..ce915f8ae 100644 --- a/src/86box.h +++ b/src/86box.h @@ -133,7 +133,7 @@ extern int serial_do_log; extern int nic_do_log; #endif -extern wchar_t exe_path[1024]; /* path (dir) of executable */ +extern wchar_t exe_path[2048]; /* 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 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/cdrom/cdrom.c b/src/cdrom/cdrom.c index 1947b1573..6c19233a7 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -8,7 +8,7 @@ * * Generic CD-ROM drive core. * - * Version: @(#)cdrom.c 1.0.8 2019/09/26 + * Version: @(#)cdrom.c 1.0.9 2019/12/13 * * Author: Miran Grca, * @@ -332,7 +332,7 @@ cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf) /* 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)) { - pclog("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); + cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); cdrom_stop(dev); return 0; } diff --git a/src/cdrom/cdrom_dosbox.cpp b/src/cdrom/cdrom_dosbox.cpp deleted file mode 100644 index 95ee86e3d..000000000 --- a/src/cdrom/cdrom_dosbox.cpp +++ /dev/null @@ -1,884 +0,0 @@ -/* - * 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. - * - * CD-ROM image file handling module. - * - * Re-hacked to remove the dirname() function, and to have this - * code using stdio instead of C++ fstream - fstream cannot deal - * with Unicode pathnames, and we need those. --FvK - * - * **NOTE** This code will very soon be replaced with a C variant, so - * no more changes will be done. - * - * Version: @(#)cdrom_dosbox.cpp 1.0.12 2019/10/22 - * - * Authors: Fred N. van Kempen, - * Miran Grca, - * The DOSBox Team, - * - * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2019 Miran Grca. - * Copyright 2002-2019 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. - */ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -# include -#else -# include -#endif -#include -#include -#define HAVE_STDARG_H -#include "../86box.h" -#include "../plat.h" -#include "cdrom_dosbox.h" - -using namespace std; - - -#define MAX_LINE_LENGTH 512 -#define MAX_FILENAME_LENGTH 256 -#define CROSS_LEN 512 - - - -#ifdef ENABLE_CDROM_DOSBOX_LOG -int cdrom_dosbox_do_log = ENABLE_CDROM_DOSBOX_LOG; - - -void -cdrom_dosbox_log(const char *fmt, ...) -{ - va_list ap; - - if (cdrom_dosbox_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define cdrom_dosbox_log(fmt, ...) -#endif - - -CDROM_Interface_Image::BinaryFile::BinaryFile(const wchar_t *filename, bool &error) -{ - memset(fn, 0x00, sizeof(fn)); - wcscpy(fn, filename); - file = plat_fopen64(fn, L"rb"); - cdrom_dosbox_log("CDROM: binary_open(%ls) = %08lx\n", fn, file); - - if (file == NULL) - error = true; - else - error = false; -} - - -CDROM_Interface_Image::BinaryFile::~BinaryFile(void) -{ - if (file != NULL) { - fclose(file); - file = NULL; - } - memset(fn, 0x00, sizeof(fn)); -} - - -bool -CDROM_Interface_Image::BinaryFile::read(uint8_t *buffer, uint64_t seek, size_t count) -{ - cdrom_dosbox_log("CDROM: binary_read(%08lx, pos=%" PRIu64 " count=%lu\n", - file, seek, count); - if (file == NULL) return 0; - - fseeko64(file, seek, SEEK_SET); - if (fread(buffer, count, 1, file) != 1) { -#ifdef ENABLE_CDROM_DOSBOX_LOG - cdrom_dosbox_log("CDROM: binary_read failed!\n"); -#endif - return 0; - } - - return 1; -} - - -uint64_t -CDROM_Interface_Image::BinaryFile::getLength(void) -{ - off64_t len; - - cdrom_dosbox_log("CDROM: binary_length(%08lx)\n", file); - if (file == NULL) return 0; - - fseeko64(file, 0, SEEK_END); - len = ftello64(file); - cdrom_dosbox_log("CDROM: binary_length(%08lx) = %" PRIu64 "\n", file, len); - - return len; -} - - -CDROM_Interface_Image::CDROM_Interface_Image(void) -{ -} - - -CDROM_Interface_Image::~CDROM_Interface_Image(void) -{ - ClearTracks(); -} - - -void -CDROM_Interface_Image::InitNewMedia(void) -{ -} - - -bool -CDROM_Interface_Image::SetDevice(const wchar_t *path, int forceCD) -{ - (void)forceCD; - - if (CueLoadSheet(path)) return true; - - if (IsoLoadFile(path)) return true; - - return false; -} - - -bool -CDROM_Interface_Image::GetUPC(uint8_t& 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, uint8_t& 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::GetAudioTrackEndInfo(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 + tracks[track - 1].length + 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, uint8_t& attr, uint8_t& track, uint8_t& index, TMSF& relPos, TMSF& absPos) -{ - int cur_track = GetTrack(sector); - - if (cur_track < 1) return false; - - track = (uint8_t)cur_track; - attr = tracks[track - 1].attr; - index = 1; - - FRAMES_TO_MSF(sector + 150, &absPos.min, &absPos.sec, &absPos.fr); - - /* Absolute position should be adjusted by 150, not the relative ones. */ - 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, uint32_t sector, uint32_t num) -{ - int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; - uint8_t buflen = num * sectorSize; - uint8_t* buf = new uint8_t[buflen]; - bool success = true; /* reading 0 sectors is OK */ - uint32_t i; - - for (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(uint8_t *buffer, bool raw, uint32_t sector) -{ - size_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(uint8_t *buffer, uint32_t 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(uint32_t sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return 0; - - return tracks[track].sectorSize; -} - - -bool -CDROM_Interface_Image::IsMode2(uint32_t sector) -{ - int track = GetTrack(sector) - 1; - - if (track < 0) return false; - - if (tracks[track].mode2) - return true; - - return false; -} - - -int -CDROM_Interface_Image::GetMode2Form(uint32_t sector) -{ - int track = GetTrack(sector) - 1; - - if (track < 0) return false; - - return tracks[track].form; -} - - -bool -CDROM_Interface_Image::CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2) -{ - uint8_t 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); - -#if 0 - pvd[0] = descriptor type, pvd[1..5] = standard identifier, pvd[6] = iso version (+8 for High Sierra) -#endif - - 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)); -} - - -bool -CDROM_Interface_Image::IsoLoadFile(const wchar_t *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, 2336, true)) { - track.sectorSize = 2336; - track.mode2 = true; - } else if (CanReadPVD(track.file, 2324, true)) { - track.sectorSize = 2324; - track.form = 2; - 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::CueGetBuffer(char *str, char **line, bool 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 false; - } - 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 true; -} - - -/* Get a filename string from the input line. */ -bool -CDROM_Interface_Image::CueGetString(string &dest, char **line) -{ - char temp[1024]; - bool success; - - success = CueGetBuffer(temp, line, false); - if (success) - dest = temp; - - return success; -} - - -bool -CDROM_Interface_Image::CueGetKeyword(string &dest, char **line) -{ - char temp[1024]; - bool success; - - success = CueGetBuffer(temp, line, true); - if (success) - dest = temp; - - return success; -} - - -/* Get a string from the input line, handling quotes properly. */ -uint64_t -CDROM_Interface_Image::CueGetNumber(char **line) -{ - char temp[128]; - uint64_t num; - - if (! CueGetBuffer(temp, line, false)) - return 0; - - if (sscanf(temp, "%" PRIu64, &num) != 1) - return 0; - - return num; -} - - -bool -CDROM_Interface_Image::CueGetFrame(uint64_t &frames, char **line) -{ - char temp[128]; - int min, sec, fr; - bool success; - - success = CueGetBuffer(temp, line, false); - if (! success) return false; - - success = sscanf(temp, "%d:%d:%d", &min, &sec, &fr) == 3; - if (! success) return false; - - frames = MSF_TO_FRAMES(min, sec, fr); - - return true; -} - - -bool -CDROM_Interface_Image::CueLoadSheet(const wchar_t *cuefile) -{ - Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; - wchar_t pathname[MAX_FILENAME_LENGTH]; - uint64_t shift = 0; - uint64_t currPregap = 0; - uint64_t totalPregap = 0; - uint64_t prestart = 0; - int i; - bool canAddTrack = false; - bool success; - FILE *fp; - wstring name(L"r"); - - tracks.clear(); - - /* 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, (wchar_t *) name.c_str()); - if (fp == NULL) - return false; - - success = false; - - for (;;) { - char buf[MAX_LINE_LENGTH]; - char *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 */ - } - } - - string command; - success = CueGetKeyword(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; - - track.number = CueGetNumber(&line); - track.track_number = track.number; - string type; - success = CueGetKeyword(type, &line); - if (! success) break; - - 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 frame = 0ULL, index; - index = CueGetNumber(&line); - success = CueGetFrame(frame, &line); - - switch(index) { - case 0: - prestart = frame; - break; - - case 1: - track.start = frame; - break; - - default: - /* ignore other indices */ - break; - } - } else if (command == "FILE") { - if (canAddTrack) - success = AddTrack(track, shift, prestart, totalPregap, currPregap); - else - success = true; - canAddTrack = false; - - char ansi[MAX_FILENAME_LENGTH]; - wchar_t filename[MAX_FILENAME_LENGTH]; - string type; - memset(ansi, 0, MAX_FILENAME_LENGTH); - memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); - - success = CueGetBuffer(ansi, &line, false); - if (! success) break; - success = CueGetKeyword(type, &line); - if (! success) break; - - track.file = NULL; - bool error = true; - - if (type == "BINARY") { - wchar_t temp[MAX_FILENAME_LENGTH]; - memset(temp, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); - mbstowcs(temp, ansi, sizeof_w(temp)); - plat_append_filename(filename, pathname, temp); - track.file = new BinaryFile(filename, error); - } - if (error) { -#ifdef ENABLE_CDROM_DOSBOX_LOG - cdrom_dosbox_log("CUE: cannot open fille '%ls' in cue sheet!\n", - filename); -#endif - delete track.file; - track.file = NULL; - success = false; - } - } else if (command == "PREGAP") - success = CueGetFrame(currPregap, &line); - else if (command == "CATALOG") { - success = CueGetString(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 { -#ifdef ENABLE_CDROM_DOSBOX_LOG - cdrom_dosbox_log("CUE: unsupported command '%s' in cue sheet!\n", - command.c_str()); -#endif - success = false; - } - - if (! success) - break; - } - - fclose(fp); - 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.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; - - 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; -} - - -void -CDROM_Interface_Image::ClearTracks(void) -{ - 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 93b80340f..000000000 --- a/src/cdrom/cdrom_dosbox.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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 CD-ROM image file handling module. - * - * Version: @(#)cdrom_dosbox.h 1.0.3 2019/03/05 - * - * Authors: Fred N. van Kempen, - * Miran Grca, - * The DOSBox Team, - * - * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 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. - */ -#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 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) { \ - 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; - -typedef struct SCtrl { - uint8_t out[4]; // output channel - uint8_t vol[4]; // channel volume -} TCtrl; - - -class CDROM_Interface { -public: -// CDROM_Interface(void); - - virtual ~CDROM_Interface(void) {}; - - virtual bool SetDevice(const wchar_t *path, int forceCD) = 0; - - virtual bool GetUPC(uint8_t& attr, char* upc) = 0; - - virtual bool GetAudioTracks(int& stTrack, int& end, TMSF& leadOut) = 0; - virtual bool GetAudioTrackInfo(int track, int& number, TMSF& start, uint8_t& attr) = 0; - virtual bool GetAudioTrackEndInfo(int track, int& number, TMSF& start, unsigned char& attr) = 0; - virtual bool GetAudioSub(int sector, uint8_t& attr, uint8_t& track, uint8_t& index, TMSF& relPos, TMSF& absPos) = 0; - virtual bool GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; - - virtual bool ReadSectors(PhysPt buffer, bool raw, uint32_t sector, uint32_t 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(uint8_t *buffer, uint64_t seek, size_t count) = 0; - virtual uint64_t getLength() = 0; - virtual ~TrackFile() { }; - }; - - class BinaryFile : public TrackFile { - public: - BinaryFile(const wchar_t *filename, bool &error); - ~BinaryFile(); - bool read(uint8_t *buffer, uint64_t seek, size_t count); - uint64_t getLength(); - private: - BinaryFile(); - wchar_t fn[260]; - FILE *file; - }; - - struct Track { - int number; - int track_number; - int attr; - int form; - uint64_t start; - uint64_t length; - uint64_t skip; - int sectorSize; - bool mode2; - TrackFile *file; - }; - -public: - CDROM_Interface_Image(); - virtual ~CDROM_Interface_Image(void); - void InitNewMedia(void); - bool SetDevice(const wchar_t* path, int forceCD); - bool GetUPC(uint8_t& attr, char* upc); - bool GetAudioTracks(int& stTrack, int& end, TMSF& leadOut); - bool GetAudioTrackInfo(int track, int& number, TMSF& start, uint8_t& attr); - bool GetAudioTrackEndInfo(int track, int& number, TMSF& start, unsigned char& attr); - bool GetAudioSub(int sector, uint8_t& attr, uint8_t& track, uint8_t& index, TMSF& relPos, TMSF& absPos); - bool GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen); - bool ReadSectors(PhysPt buffer, bool raw, uint32_t sector, uint32_t num); - bool LoadUnloadMedia(bool unload); - bool ReadSector(uint8_t *buffer, bool raw, uint32_t sector); - bool ReadSectorSub(uint8_t *buffer, uint32_t sector); - int GetSectorSize(uint32_t sector); - bool IsMode2(uint32_t sector); - int GetMode2Form(uint32_t sector); - bool HasDataTrack(void); - bool HasAudioTracks(void); - - int GetTrack(unsigned int sector); - -private: - // player - static void CDAudioCallBack(unsigned int len); - - void ClearTracks(); - bool IsoLoadFile(const wchar_t *filename); - bool CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2); - - // cue sheet processing - bool CueGetBuffer(char *str, char **line, bool up); - bool CueGetString(std::string &str, char **line); - bool CueGetKeyword(std::string &keyword, char **line); - uint64_t CueGetNumber(char **line); - bool CueGetFrame(uint64_t &frames, char **line); - bool CueLoadSheet(const wchar_t *cuefile); - 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; -}; - - -extern int CDROM_GetMountType(char* path, int force); - -extern void cdrom_image_log(const char *format, ...); - - -#endif /* __CDROM_INTERFACE__ */ diff --git a/src/cdrom/cdrom_image.cc b/src/cdrom/cdrom_image.c similarity index 70% rename from src/cdrom/cdrom_image.cc rename to src/cdrom/cdrom_image.c index 4eb6c6499..84dff1f98 100644 --- a/src/cdrom/cdrom_image.cc +++ b/src/cdrom/cdrom_image.c @@ -8,7 +8,7 @@ * * CD-ROM image support. * - * Version: @(#)cdrom_image.cc 1.0.10 2019/03/06 + * Version: @(#)cdrom_image.c 1.0.11 2019/03/06 * * Author: RichardG867, * Miran Grca, @@ -21,6 +21,7 @@ #define __USE_LARGEFILE64 #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE +#include #include #include #include @@ -32,7 +33,7 @@ #include "../config.h" #include "../plat.h" #include "../scsi/scsi_device.h" -#include "cdrom_dosbox.h" +#include "cdrom_image_backend.h" #include "cdrom.h" #include "cdrom_image.h" @@ -60,29 +61,26 @@ cdrom_image_log(const char *fmt, ...) /* 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) +#define MSFtoLBA(m,s,f) ((((m * 60) + s) * 75) + f) static void image_get_tracks(cdrom_t *dev, int *first, int *last) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; TMSF tmsf; - img->GetAudioTracks(*first, *last, 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) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; TMSF tmsf; - if (end) - img->GetAudioTrackEndInfo(track, ti->number, tmsf, ti->attr); - else - img->GetAudioTrackInfo(track, ti->number, tmsf, ti->attr); + cdi_get_audio_track_info(img, end, track, &ti->number, &tmsf, &ti->attr); ti->m = tmsf.min; ti->s = tmsf.sec; @@ -93,11 +91,11 @@ image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) static void image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; TMSF rel_pos, abs_pos; - img->GetAudioSub(lba, subc->attr, subc->track, subc->index, - 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; @@ -112,22 +110,19 @@ image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) static int image_get_capacity(cdrom_t *dev) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + 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; + uint32_t address = 0, lb = 0; if (!img) return 0; - img->GetAudioTracks(first_track, last_track, tmsf); + cdi_get_audio_tracks_lba(img, &first_track, &last_track, &lb); for (c = 0; c <= last_track; c++) { - img->GetAudioTrackInfo(c+1, number, tmsf, attr); - address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */ + cdi_get_audio_track_info_lba(img, 0, c + 1, &number, &address, &attr); if (address > lb) lb = address; } @@ -139,11 +134,11 @@ image_get_capacity(cdrom_t *dev) static int image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; uint8_t attr; TMSF tmsf; int m, s, f; - int number; + int number, track; if (!img || (dev->cd_status == CD_STATUS_DATA_ONLY)) return 0; @@ -156,36 +151,40 @@ image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) } /* GetTrack requires LBA. */ - img->GetAudioTrackInfo(img->GetTrack(pos), number, tmsf, attr); - - return attr == AUDIO_TRACK; + track = cdi_get_track(img, pos); + if (track == -1) + return 0; + else { + 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) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; - return img->GetSectorSize(lba); + return cdi_get_sector_size(img, lba); } static int image_read_sector(struct cdrom *dev, int type, uint8_t *b, uint32_t lba) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; switch (type) { case CD_READ_DATA: - return img->ReadSector(b, false, lba); + return cdi_read_sector(img, b, 0, lba); case CD_READ_AUDIO: - return img->ReadSector(b, true, lba); + return cdi_read_sector(img, b, 1, lba); case CD_READ_RAW: - if (img->GetSectorSize(lba) == 2352) - return img->ReadSector(b, true, lba); + if (cdi_get_sector_size(img, lba) == 2352) + return cdi_read_sector(img, b, 1, lba); else - return img->ReadSectorSub(b, lba); + return cdi_read_sector_sub(img, b, lba); default: cdrom_image_log("CD-ROM %i: Unknown CD read type\n", dev->id); return 0; @@ -196,14 +195,14 @@ image_read_sector(struct cdrom *dev, int type, uint8_t *b, uint32_t lba) static int image_track_type(cdrom_t *dev, uint32_t lba) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + 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 (img->IsMode2(lba)) - return CD_TRACK_MODE2 | img->GetMode2Form(lba); + if (cdi_is_mode2(img, lba)) + return CD_TRACK_MODE2 | cdi_get_mode2_form(img, lba); } } @@ -214,13 +213,13 @@ image_track_type(cdrom_t *dev, uint32_t lba) static void image_exit(cdrom_t *dev) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + 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) { - delete img; + cdi_close(img); dev->image = NULL; } @@ -252,22 +251,23 @@ image_open_abort(cdrom_t *dev) int cdrom_image_open(cdrom_t *dev, const wchar_t *fn) { - CDROM_Interface_Image *img; + cd_img_t *img; wcscpy(dev->image_path, fn); /* Create new instance of the CDROM_Image class. */ - img = new CDROM_Interface_Image(); + 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 (! img->SetDevice(fn, false)) + if (!cdi_set_device(img, fn)) return image_open_abort(dev); /* All good, reset state. */ @@ -278,7 +278,7 @@ cdrom_image_open(cdrom_t *dev, const wchar_t *fn) 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); + cdrom_image_log("CD-ROM capacity: %i sectors (%" PRIi64 " bytes)\n", dev->cdrom_capacity, ((uint64_t) dev->cdrom_capacity) << 11ULL); /* Attach this handler to the drive. */ dev->ops = &cdrom_image_ops; diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c new file mode 100644 index 000000000..556c0e954 --- /dev/null +++ b/src/cdrom/cdrom_image_backend.c @@ -0,0 +1,1035 @@ +/* + * 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.5 2020/01/17 + * + * 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 + + +static char temp_keyword[1024]; + + +#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; + + if (fseeko64(tf->file, seek, SEEK_SET) == -1) { +#ifdef ENABLE_cdrom_image_backend_log + cdrom_image_backend_log("CDROM: binary_read failed during seek!\n"); +#endif + return 0; + } + + if (fread(buffer, count, 1, tf->file) != 1) { +#ifdef ENABLE_cdrom_image_backend_log + cdrom_image_backend_log("CDROM: binary_read failed during read!\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)); + + if (tf == NULL) { + *error = 1; + return NULL; + } + + memset(tf->fn, 0x00, sizeof(tf->fn)); + if (wcslen(filename) <= 260) + wcscpy(tf->fn, filename); + else + wcsncpy(tf->fn, filename, 260); + 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; + } else { + free(tf); + tf = NULL; + } + + 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; +} + + +int +cdi_get_audio_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *lead_out) +{ + *st_track = 1; + *end = cdi->tracks_num - 1; + *lead_out = cdi->tracks[*end].start; + + 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_audio_track_info_lba(cd_img_t *cdi, int end, int track, int *track_num, uint32_t *start, uint8_t *attr) +{ + track_t *trk = &cdi->tracks[track - 1]; + + if ((track < 1) || (track > cdi->tracks_num)) + return 0; + + *start = (uint32_t) trk->start; + + *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)); + + 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 != 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; + cdrom_image_backend_log("ISO: Data track: length = %" PRIu64 ", sector_size = %i\n", trk.length, 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) +{ + int success; + + success = cdi_cue_get_buffer(temp_keyword, line, 1); + if (success) + *dest = temp_keyword; + + 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]; + else if ((cdi->tracks == NULL) && (cdi->tracks_num != 0)) { + fatal("NULL cdi->tracks with non-zero cdi->tracks_num\n"); + return 0; + } + + /* 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; + if (!success) + break; + + 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; + if (!success) + break; + 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..69a59031c --- /dev/null +++ b/src/cdrom/cdrom_image_backend.h @@ -0,0 +1,95 @@ +/* + * 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.2 2020/01/17 + * + * 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. + */ +#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 { + uint16_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_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *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_audio_track_info_lba(cd_img_t *cdi, int end, int track, int *track_num, uint32_t *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/chipset/chipset.h b/src/chipset/chipset.h index bf2cda160..f61cdcd3e 100644 --- a/src/chipset/chipset.h +++ b/src/chipset/chipset.h @@ -8,11 +8,11 @@ * * Handling of the emulated chipsets. * - * Version: @(#)machine.h 1.0.0 2019/05/13 + * Version: @(#)machine.h 1.0.1 2020/01/14 * * Authors: Miran Grca, * - * Copyright 2019 Miran Grca. + * Copyright 2019,2020 Miran Grca. */ #ifndef EMU_CHIPSET_H # define EMU_CHIPSET_H @@ -61,6 +61,9 @@ extern const device_t sis_85c496_device; extern const device_t sis_85c50x_device; #endif +/* VIA */ +extern const device_t via_mvp3_device; + /* WD */ extern const device_t wd76c10_device; diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 4f2524db9..cc641c0d5 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -565,7 +565,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB7: val &= RB7_MASK; - *reg = (*reg & ~RB7_MASK) | val; + *reg = val; #if NEAT_DEBUG > 1 neat_log("NEAT: RB7=%02x(%02x)\n", val, *reg); #endif diff --git a/src/chipset/scat.c b/src/chipset/scat.c index 0c3223486..d5712a98c 100644 --- a/src/chipset/scat.c +++ b/src/chipset/scat.c @@ -1056,17 +1056,14 @@ scat_out(uint16_t port, uint8_t val, void *priv) break; case SCAT_EMS_CONTROL: + 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); + if (val & 0x40) { - if (val & 1) { + 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 { + 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; @@ -1338,13 +1335,24 @@ 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; + scat_t *dev; uint32_t oldaddr = addr, chkaddr; - addr = get_addr(dev, addr, page); - chkaddr = page ? addr : oldaddr; + if (page == NULL) + dev = NULL; + else + dev = (scat_t *)page->scat; + + if (dev == NULL) + chkaddr = oldaddr; + else { + addr = get_addr(dev, addr, page); + chkaddr = addr; + } + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { - if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + if ((dev == NULL) || (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15)))) + return; } if (addr < ((uint32_t)mem_size << 10)) @@ -1356,13 +1364,24 @@ 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; + scat_t *dev; uint32_t oldaddr = addr, chkaddr; - addr = get_addr(dev, addr, page); - chkaddr = page ? addr : oldaddr; + if (page == NULL) + dev = NULL; + else + dev = (scat_t *)page->scat; + + if (dev == NULL) + chkaddr = oldaddr; + else { + addr = get_addr(dev, addr, page); + chkaddr = addr; + } + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { - if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + if (dev != NULL && (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15)))) + return; } if (addr < ((uint32_t)mem_size << 10)) @@ -1374,14 +1393,26 @@ 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; + scat_t *dev; 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 (page == NULL) + dev = NULL; + else + dev = (scat_t *)page->scat; + + if (dev == NULL) + chkaddr = oldaddr; + else { + addr = get_addr(dev, addr, page); + chkaddr = addr; } + + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev != NULL && (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15)))) + return; + } + if (addr < ((uint32_t)mem_size << 10)) *(uint32_t *)&ram[addr] = val; } diff --git a/src/chipset/via_mvp3.c b/src/chipset/via_mvp3.c new file mode 100644 index 000000000..d9ffc01a6 --- /dev/null +++ b/src/chipset/via_mvp3.c @@ -0,0 +1,324 @@ +/* + * 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 VIA MVP3 chip. + * + * Version: @(#)via_mvp3.c 1.0.1 2019/10/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * Melissa Goad, + * + * Copyright 2020 Miran Grca, Melissa Goad. + */ +#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 via_mvp3_t +{ + uint8_t pci_conf[2][256]; +} via_mvp3_t; + + +static void +mvp3_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_EXTANY | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + + flushmmucache_nopc(); +} + + +static void +via_mvp3_setup(via_mvp3_t *dev) +{ + memset(dev, 0, sizeof(via_mvp3_t)); + + /* Host Bridge */ + dev->pci_conf[0][0x00] = 0x06; /*VIA*/ + dev->pci_conf[0][0x01] = 0x11; + dev->pci_conf[0][0x02] = 0x98; /*VT82C598MVP*/ + dev->pci_conf[0][0x03] = 0x05; + + dev->pci_conf[0][0x04] = 6; + dev->pci_conf[0][0x05] = 0; + + dev->pci_conf[0][0x06] = 0x90; + dev->pci_conf[0][0x07] = 0x02; + + dev->pci_conf[0][0x09] = 0; + dev->pci_conf[0][0x0a] = 0; + dev->pci_conf[0][0x0b] = 6; + dev->pci_conf[0][0x0c] = 0; + dev->pci_conf[0][0x0d] = 0; + dev->pci_conf[0][0x0e] = 0; + dev->pci_conf[0][0x0f] = 0; + dev->pci_conf[0][0x10] = 0x08; + dev->pci_conf[0][0x34] = 0xa0; + + dev->pci_conf[0][0x5a] = 0x01; + dev->pci_conf[0][0x5b] = 0x01; + dev->pci_conf[0][0x5c] = 0x01; + dev->pci_conf[0][0x5d] = 0x01; + dev->pci_conf[0][0x5e] = 0x01; + dev->pci_conf[0][0x5f] = 0x01; + + dev->pci_conf[0][0x64] = 0xec; + dev->pci_conf[0][0x65] = 0xec; + dev->pci_conf[0][0x66] = 0xec; + dev->pci_conf[0][0x6b] = 0x01; + + dev->pci_conf[0][0xa0] = 0x02; + dev->pci_conf[0][0xa2] = 0x10; + dev->pci_conf[0][0xa4] = 0x03; + dev->pci_conf[0][0xa5] = 0x02; + dev->pci_conf[0][0xa7] = 0x07; + + /* PCI-to-PCI Bridge */ + + dev->pci_conf[1][0x00] = 0x06; /*VIA*/ + dev->pci_conf[1][0x01] = 0x11; + dev->pci_conf[1][0x02] = 0x98; /*VT82C598MVP*/ + dev->pci_conf[1][0x03] = 0x85; + + dev->pci_conf[1][0x04] = 7; + dev->pci_conf[1][0x05] = 0; + + dev->pci_conf[1][0x06] = 0x20; + dev->pci_conf[1][0x07] = 0x02; + + dev->pci_conf[1][0x09] = 0; + dev->pci_conf[1][0x0a] = 4; + dev->pci_conf[1][0x0b] = 6; + dev->pci_conf[1][0x0c] = 0; + dev->pci_conf[1][0x0d] = 0; + dev->pci_conf[1][0x0e] = 1; + dev->pci_conf[1][0x0f] = 0; + + dev->pci_conf[1][0x1c] = 0xf0; + + dev->pci_conf[1][0x20] = 0xf0; + dev->pci_conf[1][0x21] = 0xff; + dev->pci_conf[1][0x24] = 0xf0; + dev->pci_conf[1][0x25] = 0xff; +} + + +static void +via_mvp3_host_bridge_write(int func, int addr, uint8_t val, void *priv) +{ + via_mvp3_t *dev = (via_mvp3_t *) priv; + + if (func) + return; + + /*Read-only addresses*/ + if ((addr < 4) || ((addr >= 5) && (addr < 7)) || ((addr >= 8) && (addr < 0xd)) || + ((addr >= 0xe) && (addr < 0x12)) || ((addr >= 0x14) && (addr < 0x50)) || + ((addr >= 0x79) && (addr < 0x7e)) || ((addr >= 0x85) && (addr < 0x88)) || + ((addr >= 0x8c) && (addr < 0xa8)) || ((addr >= 0xad) && (addr < 0xfd))) + return; + + switch(addr) { + case 0x04: + dev->pci_conf[0][0x04] = (dev->pci_conf[0][0x04] & ~0x40) | (val & 0x40); + break; + case 0x07: + dev->pci_conf[0][0x07] &= ~(val & 0xb0); + break; + + case 0x12: /* Graphics Aperture Base */ + dev->pci_conf[0][0x12] = (val & 0xf0); + break; + case 0x13: /* Graphics Aperture Base */ + dev->pci_conf[0][0x13] = val; + break; + + case 0x61: /* Shadow RAM Control 1 */ + if ((dev->pci_conf[0][0x61] ^ val) & 0x03) + mvp3_map(0xc0000, 0x04000, val & 0x03); + if ((dev->pci_conf[0][0x61] ^ val) & 0x0c) + mvp3_map(0xc4000, 0x04000, (val & 0x0c) >> 2); + if ((dev->pci_conf[0][0x61] ^ val) & 0x30) + mvp3_map(0xc8000, 0x04000, (val & 0x30) >> 4); + if ((dev->pci_conf[0][0x61] ^ val) & 0xc0) + mvp3_map(0xcc000, 0x04000, (val & 0xc0) >> 6); + dev->pci_conf[0][0x61] = val; + return; + case 0x62: /* Shadow RAM Control 2 */ + if ((dev->pci_conf[0][0x62] ^ val) & 0x03) + mvp3_map(0xd0000, 0x04000, val & 0x03); + if ((dev->pci_conf[0][0x62] ^ val) & 0x0c) + mvp3_map(0xd4000, 0x04000, (val & 0x0c) >> 2); + if ((dev->pci_conf[0][0x62] ^ val) & 0x30) + mvp3_map(0xd8000, 0x04000, (val & 0x30) >> 4); + if ((dev->pci_conf[0][0x62] ^ val) & 0xc0) + mvp3_map(0xdc000, 0x04000, (val & 0xc0) >> 6); + dev->pci_conf[0][0x62] = val; + return; + case 0x63: /* Shadow RAM Control 3 */ + if ((dev->pci_conf[0][0x63] ^ val) & 0x30) { + mvp3_map(0xf0000, 0x10000, (val & 0x30) >> 4); + shadowbios = (((val & 0x30) >> 4) & 0x02); + } + if ((dev->pci_conf[0][0x63] ^ val) & 0xc0) + mvp3_map(0xe0000, 0x10000, (val & 0xc0) >> 6); + dev->pci_conf[0][0x63] = val; + return; + + default: + dev->pci_conf[0][addr] = val; + break; + } +} + + +static void +via_mvp3_pci_bridge_write(int func, int addr, uint8_t val, void *priv) +{ + via_mvp3_t *dev = (via_mvp3_t *) priv; + + if (func != 1) + return; + + /*Read-only addresses*/ + + if ((addr < 4) || ((addr >= 5) && (addr < 7)) || + ((addr >= 8) && (addr < 0x18)) || (addr == 0x1b) || + ((addr >= 0x1e) && (addr < 0x20)) || ((addr >= 0x28) && (addr < 0x3e)) || + (addr >= 0x43)) + return; + + switch(addr) { + case 0x04: + dev->pci_conf[1][0x04] = (dev->pci_conf[1][0x04] & ~0x47) | (val & 0x47); + break; + case 0x07: + dev->pci_conf[1][0x07] &= ~(val & 0x30); + break; + + case 0x20: /* Memory Base */ + dev->pci_conf[1][0x20] = val & 0xf0; + break; + case 0x22: /* Memory Limit */ + dev->pci_conf[1][0x22] = val & 0xf0; + break; + case 0x24: /* Prefetchable Memory Base */ + dev->pci_conf[1][0x24] = val & 0xf0; + break; + case 0x26: /* Prefetchable Memory Limit */ + dev->pci_conf[1][0x26] = val & 0xf0; + break; + + default: + dev->pci_conf[1][addr] = val; + break; + } +} + + +static uint8_t +via_mvp3_read(int func, int addr, void *priv) +{ + via_mvp3_t *dev = (via_mvp3_t *) priv; + uint8_t ret = 0xff; + + switch(func) { + case 0: + ret = dev->pci_conf[0][addr]; + break; + case 1: + ret = dev->pci_conf[1][addr]; + break; + } + + return ret; +} + + +static void +via_mvp3_write(int func, int addr, uint8_t val, void *priv) +{ + switch(func) { + case 0: + via_mvp3_host_bridge_write(func, addr, val, priv); + break; + case 1: + via_mvp3_pci_bridge_write(func, addr, val, priv); + break; + } +} + + +static void +via_mvp3_reset(void *priv) +{ + via_mvp3_write(0, 0x63, via_mvp3_read(0, 0x63, priv) & 0xcf, priv); +} + + +static void * +via_mvp3_init(const device_t *info) +{ + via_mvp3_t *dev = (via_mvp3_t *) malloc(sizeof(via_mvp3_t)); + + pci_add_card(0, via_mvp3_read, via_mvp3_write, dev); + + via_mvp3_setup(dev); + + return dev; +} + + +static void +via_mvp3_close(void *priv) +{ + via_mvp3_t *dev = (via_mvp3_t *) priv; + + free(dev); +} + + +const device_t via_mvp3_device = +{ + "VIA MVP3", + DEVICE_PCI, + 0, + via_mvp3_init, + via_mvp3_close, + via_mvp3_reset, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/config.c b/src/config.c index 9b09e7a8f..f2b6076c1 100644 --- a/src/config.c +++ b/src/config.c @@ -8,7 +8,7 @@ * * Configuration file handler. * - * Version: @(#)config.c 1.0.65 2019/12/05 + * Version: @(#)config.c 1.0.66 2019/12/21 * * Authors: Sarah Walker, * Miran Grca, @@ -57,9 +57,7 @@ #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" @@ -83,7 +81,7 @@ typedef struct { list_t list; char name[128]; - char data[256]; + char data[512]; wchar_t wdata[512]; } entry_t; @@ -311,7 +309,7 @@ config_read(wchar_t *fn) /* Create a new section and insert it. */ ns = malloc(sizeof(section_t)); memset(ns, 0x00, sizeof(section_t)); - strncpy(ns->name, sname, sizeof(ns->name)); + strncpy(ns->name, sname, sizeof(ns->name) - 1); list_add(&ns->list, &config_head); /* New section is now the current one. */ @@ -341,7 +339,7 @@ config_read(wchar_t *fn) /* Allocate a new variable entry.. */ ne = malloc(sizeof(entry_t)); memset(ne, 0x00, sizeof(entry_t)); - strncpy(ne->name, ename, sizeof(ne->name)); + strncpy(ne->name, ename, sizeof(ne->name) - 1); wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata)-1); ne->wdata[sizeof_w(ne->wdata)-1] = L'\0'; wcstombs(ne->data, ne->wdata, sizeof(ne->data)); @@ -397,7 +395,7 @@ config_write(wchar_t *fn) ent = (entry_t *)sec->entry_head.next; while (ent != NULL) { if (ent->name[0] != '\0') { - mbstowcs(wtemp, ent->name, sizeof_w(wtemp)); + mbstowcs(wtemp, ent->name, 128); if (ent->wdata[0] == L'\0') fwprintf(f, L"%ls = \n", wtemp); else @@ -568,6 +566,7 @@ load_video(void) { char *cat = "Video"; char *p; + int free_p = 0; if (machines[machine].flags & MACHINE_VIDEO_FIXED) { config_delete_var(cat, "gfxcard"); @@ -582,8 +581,11 @@ load_video(void) p = (char *)malloc((strlen("none")+1)*sizeof(char)); strcpy(p, "none"); } + free_p = 1; } gfxcard = video_get_video_from_internal_name(p); + if (free_p) + free(p); } voodoo_enabled = !!config_get_int(cat, "voodoo", 0); @@ -605,7 +607,7 @@ load_input_devices(void) else mouse_type = 0; - joystick_type = config_get_int(cat, "joystick_type", 7); + joystick_type = config_get_int(cat, "joystick_type", JOYSTICK_TYPE_NONE); for (c=0; cdata, "%i", val); - mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); + mbstowcs(ent->wdata, ent->data, 512); } @@ -2159,7 +2170,7 @@ config_set_mac(char *head, char *name, int val) sprintf(ent->data, "%02x:%02x:%02x", (val>>16)&0xff, (val>>8)&0xff, val&0xff); - mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); + mbstowcs(ent->wdata, ent->data, 512); } diff --git a/src/cpu/386.c b/src/cpu/386.c index 7694a0be4..5c7273e04 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -73,8 +73,12 @@ extern int dontprint; #define OP_TABLE(name) ops_ ## name -#define CLOCK_CYCLES(c) cycles -= (c) -#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) +#define CLOCK_CYCLES(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) +#define CLOCK_CYCLES_ALWAYS(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) #include "x86_ops.h" diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index fab7e429c..91a9eeeeb 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -499,9 +499,223 @@ 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) +#define CLOCK_CYCLES(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) +#define CLOCK_CYCLES_ALWAYS(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) #include "386_ops.h" @@ -576,6 +790,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) @@ -726,6 +944,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(); @@ -796,7 +1017,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(); @@ -851,6 +1075,11 @@ inrecomp=0; } } + if (in_smm && smi_line && is_pentium) + { + enter_smm(); + } + if (trap) { flags_rebuild(); diff --git a/src/cpu/386_dynarec_ops.c b/src/cpu/386_dynarec_ops.c index aa4784ba8..ade318301 100644 --- a/src/cpu/386_dynarec_ops.c +++ b/src/cpu/386_dynarec_ops.c @@ -9,6 +9,7 @@ #endif #include "../86box.h" #include "cpu.h" +#include "../timer.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" @@ -63,7 +64,8 @@ static __inline void fetch_ea_16_long(uint32_t rmdat) #define PREFETCH_FLUSH() #define OP_TABLE(name) dynarec_ops_ ## name -#define CLOCK_CYCLES(c) -#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) - +#define CLOCK_CYCLES(c) +#define CLOCK_CYCLES_ALWAYS(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) #include "386_ops.h" diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index 55d7d72f3..c66b3d0b4 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -185,9 +185,6 @@ extern void x386_dynarec_log(const char *fmt, ...); #endif #include "x86seg.h" -#if defined(DEV_BRANCH) && defined(USE_AMD_K) -# include "x86_ops_amd.h" -#endif #include "x86_ops_arith.h" #include "x86_ops_atomic.h" #include "x86_ops_bcd.h" @@ -651,7 +648,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, @@ -673,7 +670,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, @@ -695,7 +692,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, @@ -717,7 +714,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, @@ -742,7 +739,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, @@ -764,7 +761,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, @@ -786,7 +783,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, @@ -808,7 +805,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, @@ -817,99 +814,6 @@ const OpFn OP_TABLE(pentiummmx_0f)[1024] = /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, }; -#if defined(DEV_BRANCH) && defined(USE_AMD_K) -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, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, -/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, - -/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, -/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, -/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, -/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, - - /*32-bit data, 16-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ -/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - -/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, -/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, - -/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, -/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, -/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, -/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, - -/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, -/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, -/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, -/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, - - /*16-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ -/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - -/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, -/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, - -/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, -/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, -/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, -/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, - -/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, -/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, -/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, -/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, - - /*32-bit data, 32-bit addr*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ -/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, - -/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, -/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, - -/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, -/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, -/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, -/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, - -/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, -/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, -/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, -/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, -}; -#endif - #if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) const OpFn OP_TABLE(c6x86mx_0f)[1024] = { @@ -927,7 +831,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, @@ -949,7 +853,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, @@ -971,7 +875,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, @@ -993,7 +897,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, @@ -1021,7 +925,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, @@ -1043,7 +947,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, @@ -1065,7 +969,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, @@ -1087,7 +991,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, @@ -1113,7 +1017,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, @@ -1135,7 +1039,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, @@ -1157,7 +1061,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, @@ -1179,7 +1083,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, @@ -1205,7 +1109,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, @@ -1227,7 +1131,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, @@ -1249,7 +1153,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, @@ -1271,7 +1175,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 9d4e318f6..929d08bb6 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -915,7 +915,10 @@ reset_common(int hard) cr0 = 1 << 30; else cr0 = 0; - cpu_cache_int_enabled = 0; + if (isibmcpu) + cpu_cache_int_enabled = 1; + else + cpu_cache_int_enabled = 0; cpu_update_waitstates(); cr4 = 0; cpu_state.eflags = 0; @@ -961,6 +964,8 @@ reset_common(int hard) prefetching = 1; takeint = 0; + + cpu_ven_reset(); } @@ -1212,7 +1217,7 @@ jcc(uint8_t opcode, int cond) wait(1, 0); cpu_data = pfq_fetchb(); wait(1, 0); - if ((!cond) == (opcode & 0x01)) + if ((!cond) == !!(opcode & 0x01)) jump_short(); } diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index dc068d62f..599c90e6e 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -122,6 +122,9 @@ 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; @@ -145,6 +148,7 @@ int is286, is386, is486, cpu_iscyrix, + isibmcpu, israpidcad, is_pentium; @@ -187,8 +191,7 @@ uint64_t ecx570_msr = 0; #if defined(DEV_BRANCH) && defined(USE_AMD_K) uint64_t ecx83_msr = 0; /* AMD K5 and K6 MSR's. */ -uint64_t star = 0; /* These are K6-only. */ -uint64_t sfmask = 0; +uint64_t amd_efer = 0, amd_whcr = 0; #endif int timing_rr; @@ -255,8 +258,9 @@ cpu_set(void) 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); + 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) @@ -265,11 +269,9 @@ cpu_set(void) 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_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) { - if (cpu_s->pci_speed) - cpu_busspeed = cpu_s->pci_speed; - else cpu_busspeed = cpu_s->rspeed / cpu_s->multi; } cpu_multi = cpu_s->multi; @@ -484,6 +486,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*/ @@ -546,6 +549,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*/ @@ -656,6 +733,7 @@ cpu_set(void) case CPU_iDX4: cpu_features = CPU_FEATURE_CR4 | CPU_FEATURE_VME; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; + /*FALLTHROUGH*/ case CPU_i486SX: case CPU_i486DX: #ifdef USE_DYNAREC @@ -1114,9 +1192,9 @@ cpu_set(void) case CPU_K5: case CPU_5K86: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); #else - x86_setopcodes(ops_386, ops_k6_0f); + x86_setopcodes(ops_386, ops_pentiummmx_0f); #endif timing_rr = 1; /*register dest - register src*/ timing_rm = 2; /*register dest - memory src*/ @@ -1135,9 +1213,9 @@ cpu_set(void) case CPU_K6: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); #else - x86_setopcodes(ops_386, ops_k6_0f); + x86_setopcodes(ops_386, ops_pentiummmx_0f); #endif timing_rr = 1; /*register dest - register src*/ timing_rm = 2; /*register dest - memory src*/ @@ -1722,6 +1800,20 @@ cpu_CPUID(void) } } +void cpu_ven_reset(void) +{ +#if defined(DEV_BRANCH) && defined(USE_AMD_K) + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_K5: + case CPU_5K86: + case CPU_K6: + amd_efer = amd_whcr = 0ULL; + break; + } +#endif +} + void cpu_RDMSR() { switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) @@ -1763,24 +1855,24 @@ void cpu_RDMSR() EAX = EDX = 0; switch (ECX) { - case 0x0e: + case 0x0000000e: EAX = msr.tr12; break; - case 0x10: + case 0x00000010: EAX = tsc & 0xffffffff; EDX = tsc >> 32; break; - case 0x83: + case 0x00000083: EAX = ecx83_msr & 0xffffffff; EDX = ecx83_msr >> 32; break; - case 0xC0000081: - EAX = star & 0xffffffff; - EDX = star >> 32; + case 0xC0000080: + EAX = amd_efer & 0xffffffff; + EDX = amd_efer >> 32; break; - case 0xC0000084: - EAX = sfmask & 0xffffffff; - EDX = sfmask >> 32; + case 0xC0000082: + EAX = amd_whcr & 0xffffffff; + EDX = amd_whcr >> 32; break; default: x86gpf(NULL, 0); @@ -1947,6 +2039,10 @@ i686_invalid_rdmsr: void cpu_WRMSR() { +#if defined(DEV_BRANCH) && defined(USE_AMD_K) + uint64_t temp; +#endif + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) { case CPU_WINCHIP: @@ -2003,11 +2099,18 @@ void cpu_WRMSR() case 0x83: ecx83_msr = EAX | ((uint64_t)EDX << 32); break; - case 0xC0000081: - star = EAX | ((uint64_t)EDX << 32); + case 0xC0000080: + temp = EAX | ((uint64_t)EDX << 32); + if (temp & ~1ULL) + x86gpf(NULL, 0); + else + amd_efer = temp; break; - case 0xC0000084: - sfmask = EAX | ((uint64_t)EDX << 32); + case 0xC0000082: + amd_whcr = EAX | ((uint64_t)EDX << 32); + break; + default: + x86gpf(NULL, 0); break; } break; diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 17ffebae8..12a50473b 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -31,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 @@ -79,18 +82,18 @@ typedef struct { - const char *name; - int cpu_type; - int rspeed; - int 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; + 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[]; @@ -102,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[]; @@ -109,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[]; @@ -329,6 +344,7 @@ 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) @@ -341,6 +357,9 @@ extern int hasfpu; 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; @@ -454,6 +473,8 @@ 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); @@ -484,6 +505,8 @@ extern void x87_reset(void); extern int cpu_effective, cpu_alt_reset; extern void cpu_dynamic_switch(int new_cpu); +extern void cpu_ven_reset(void); + #endif /*EMU_CPU_H*/ -#endif \ No newline at end of file +#endif diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index e82afef28..a0e77f414 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -97,7 +97,7 @@ CPU cpus_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, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"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}, @@ -126,7 +126,7 @@ CPU cpus_ps1_m2011[] = { 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, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"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}, @@ -173,7 +173,34 @@ CPU cpus_Am386DX[] = { {"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, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, @@ -197,91 +224,149 @@ CPU cpus_486DLC[] = { {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; -CPU cpus_i486[] = { +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, 8, 8,6,6, 6}, - {"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*/ - {"Pentium OverDrive/63", CPU_PENTIUM, 62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, 15/2}, - {"Pentium OverDrive/83", CPU_PENTIUM, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, 10}, + {"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_Am486[] = { - /*Am486/5x86*/ +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, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"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, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"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, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"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}, + {"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, 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, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"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, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20}, + {"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*/ + /*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, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"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, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"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, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14,16,16, 10}, + {"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, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"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, 80000000, 3, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, - {"6x86-PR120+", CPU_Cx6x86, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, - {"6x86-PR133+", CPU_Cx6x86, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, - {"6x86-PR150+", CPU_Cx6x86, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"6x86-PR166+", CPU_Cx6x86, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"6x86-PR200+", CPU_Cx6x86, 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, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, - {"6x86L-PR150+", CPU_Cx6x86L, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"6x86L-PR166+", CPU_Cx6x86L, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"6x86L-PR200+", CPU_Cx6x86L, 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, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"6x86MX-PR200", CPU_Cx6x86MX, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"6x86MX-PR233", CPU_Cx6x86MX, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2}, - {"6x86MX-PR266", CPU_Cx6x86MX, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, - {"6x86MX-PR300", CPU_Cx6x86MX, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 7, 7, 28}, - {"6x86MX-PR333", CPU_Cx6x86MX, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20, 9, 9, 30}, - {"6x86MX-PR366", CPU_Cx6x86MX, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 30}, - {"6x86MX-PR400", CPU_Cx6x86MX, 285000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 33}, + /*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 @@ -289,24 +374,24 @@ CPU cpus_6x86[] = { CPU cpus_WinChip[] = { /*IDT WinChip*/ - {"WinChip 75", CPU_WINCHIP, 75000000, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 9}, - {"WinChip 90", CPU_WINCHIP, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 21/2}, - {"WinChip 100", CPU_WINCHIP, 100000000, 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, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15, 7, 7, 35/2}, - {"WinChip 166", CPU_WINCHIP, 166666666, 3, 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, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 28}, + {"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, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, - {"Pentium 66", CPU_PENTIUM, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, + {"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} @@ -315,8 +400,8 @@ CPU cpus_Pentium5V[] = { 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, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, - {"Pentium 66", CPU_PENTIUM, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, + {"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}, @@ -325,54 +410,85 @@ CPU cpus_Pentium5V50[] = { CPU cpus_PentiumS5[] = { /*Intel Pentium (Socket 5)*/ - {"Pentium 75", CPU_PENTIUM, 75000000, 2, 25000000, 0x522, 0x522, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"Pentium 90", CPU_PENTIUM, 90000000, 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, 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 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, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 40}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 3, 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}, + {"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, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium 90", CPU_PENTIUM, 90000000, 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, 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, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium 166", CPU_PENTIUM, 166666666, 3, 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, 3, 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, 4, 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, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 166666666, 3, 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, 4, 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, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"Pentium OverDrive 125", CPU_PENTIUM, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, - {"Pentium OverDrive 150", CPU_PENTIUM, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 3, 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}, + {"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} }; @@ -380,69 +496,73 @@ CPU cpus_Pentium[] = { #ifdef USE_AMD_K CPU cpus_K5[] = { /*AMD K5 (Socket 5)*/ - {"K5 (5k86) 75 (P75)", CPU_K5, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, 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, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, - {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 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, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 3, 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}, + {"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, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, 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, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, - {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 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, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 3, 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}, - {"K6 (Model 6) 166", CPU_K6, 166666666, 3, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"K6 (Model 6) 200", CPU_K6, 200000000, 3, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 24}, - {"K6 (Model 6) 233", CPU_K6, 233333333, 4, 33333333, 0x562, 0x562, 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, 4, 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, 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, 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, 2, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium Pro 150", CPU_PENTIUMPRO, 150000000, 3, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium Pro 166", CPU_PENTIUMPRO, 166666666, 3, 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}, - {"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, 2, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium II Overdrive 210", CPU_PENTIUM2D, 210000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, - {"Pentium II Overdrive 233", CPU_PENTIUM2D, 233333333, 4, 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, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 33}, - {"Pentium II Overdrive 300/66", CPU_PENTIUM2D, 300000000, 5, 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}, + /*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 diff --git a/src/cpu/x86_ops.h b/src/cpu/x86_ops.h index 12a7e96bc..2c4a2f3e5 100644 --- a/src/cpu/x86_ops.h +++ b/src/cpu/x86_ops.h @@ -87,10 +87,6 @@ extern const OpFn dynarec_ops_pentiummmx_0f[1024]; 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]; -#endif - #if defined(DEV_BRANCH) && defined(USE_I686) extern const OpFn dynarec_ops_pentiumpro_0f[1024]; extern const OpFn dynarec_ops_pentium2d_0f[1024]; @@ -181,10 +177,6 @@ extern const OpFn ops_pentiummmx_0f[1024]; extern const OpFn ops_c6x86mx_0f[1024]; #endif -#if defined(DEV_BRANCH) && defined(USE_AMD_K) -extern const OpFn ops_k6_0f[1024]; -#endif - #if defined(DEV_BRANCH) && defined(USE_I686) extern const OpFn ops_pentiumpro_0f[1024]; extern const OpFn ops_pentium2d_0f[1024]; diff --git a/src/cpu/x86_ops_amd.h b/src/cpu/x86_ops_amd.h deleted file mode 100644 index 8f003e1fb..000000000 --- a/src/cpu/x86_ops_amd.h +++ /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. - * - * 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/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index b9d35a73c..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.2 2018/10/17 - * - * 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; @@ -71,14 +53,14 @@ static int opF6_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); if (cpu_mod != 3) { - SEG_CHECK_READ(cpu_state.ea_seg); + 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: + 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); @@ -128,7 +110,7 @@ static int opF6_a16(uint32_t fetchdat) { flags_rebuild(); cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ - cpu_state.flags &= ~1; + cpu_state.flags &= ~1; } } else @@ -151,7 +133,7 @@ static int opF6_a16(uint32_t fetchdat) { flags_rebuild(); cpu_state.flags|=0x8D5; /*Not a Cyrix*/ - cpu_state.flags &= ~1; + cpu_state.flags &= ~1; } } else @@ -164,7 +146,6 @@ static int opF6_a16(uint32_t fetchdat) break; default: - x386_dynarec_log("Bad F6 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -183,7 +164,7 @@ static int opF6_a32(uint32_t fetchdat) 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); @@ -233,7 +214,7 @@ static int opF6_a32(uint32_t fetchdat) { flags_rebuild(); cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ - cpu_state.flags &= ~1; + cpu_state.flags &= ~1; } } else @@ -255,8 +236,8 @@ static int opF6_a32(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - cpu_state.flags|=0x8D5; /*Not a Cyrix*/ - cpu_state.flags &= ~1; + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -269,7 +250,6 @@ static int opF6_a32(uint32_t fetchdat) break; default: - x386_dynarec_log("Bad F6 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -291,7 +271,7 @@ static int opF7_w_a16(uint32_t fetchdat) 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); @@ -370,7 +350,6 @@ static int opF7_w_a16(uint32_t fetchdat) break; default: - x386_dynarec_log("Bad F7 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -389,7 +368,7 @@ static int opF7_w_a32(uint32_t fetchdat) 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); @@ -442,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; } @@ -468,7 +448,6 @@ static int opF7_w_a32(uint32_t fetchdat) break; default: - x386_dynarec_log("Bad F7 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -487,7 +466,7 @@ static int opF7_l_a16(uint32_t fetchdat) 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); @@ -545,7 +524,6 @@ static int opF7_l_a16(uint32_t fetchdat) break; default: - x386_dynarec_log("Bad F7 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -563,7 +541,7 @@ static int opF7_l_a32(uint32_t fetchdat) 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); @@ -621,7 +599,6 @@ static int opF7_l_a32(uint32_t fetchdat) break; default: - x386_dynarec_log("Bad F7 opcode %02X\n", rmdat & 0x38); x86illegal(); } return 0; @@ -635,7 +612,7 @@ static int opHLT(uint32_t fetchdat) x86gpf(NULL,0); return 1; } - if (!((cpu_state.flags&I_FLAG) && pic_intpending)) + if (!((cpu_state.flags & I_FLAG) && pic_intpending)) { CLOCK_CYCLES_ALWAYS(100); cpu_state.pc--; @@ -655,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(); @@ -671,7 +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); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteaw(); high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -691,7 +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); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteaw(); high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -712,7 +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); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteal(); high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -732,7 +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); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteal(); high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -752,7 +729,6 @@ static int opCLTS(uint32_t fetchdat) { if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { - x386_dynarec_log("Can't CLTS\n"); x86gpf(NULL,0); return 1; } @@ -867,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 == &cpu_state.seg_cs) use32 = (segdat3 & 0x40) ? 0x300 : 0; - if (s == &cpu_state.seg_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; @@ -880,16 +859,16 @@ static void loadall_load_segment(uint32_t addr, x86seg *s) 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 == &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; } } @@ -933,6 +912,7 @@ static int opLOADALL386(uint32_t fetchdat) loadall_load_segment(la_addr + 0xc0, &cpu_state.seg_es); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; CLOCK_CYCLES(350); return 0; @@ -977,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_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index 1b5e7db71..becb0e095 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -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(); diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index d2dd5e8ad..036dfcfe4 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -765,6 +765,7 @@ void loadcsjmp(uint16_t seg, uint32_t old_pc) x86gpf(NULL,seg2&~3); return; } + /*FALLTHROUGH*/ case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ CS=seg2; do_seg_load(&cpu_state.seg_cs, segdat); @@ -1235,6 +1236,7 @@ void loadcscall(uint16_t seg) x86gpf(NULL,seg2&~3); return; } + /*FALLTHROUGH*/ case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ CS=seg2; do_seg_load(&cpu_state.seg_cs, segdat); @@ -1766,6 +1768,7 @@ void pmodeint(int num, int soft) x86gpf(NULL,seg&~3); return; } + /*FALLTHROUGH*/ case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ if (!(segdat2[2]&0x8000)) { diff --git a/src/cpu/x87.c b/src/cpu/x87.c index abc2f48a4..5016661a3 100644 --- a/src/cpu/x87.c +++ b/src/cpu/x87.c @@ -21,12 +21,12 @@ int fpu_do_log = ENABLE_FPU_LOG; -static void +void fpu_log(const char *fmt, ...) { va_list ap; - if (fpu_log) { + if (fpu_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); diff --git a/src/cpu_new/386.c b/src/cpu_new/386.c index 2b2268920..f70424b10 100644 --- a/src/cpu_new/386.c +++ b/src/cpu_new/386.c @@ -175,8 +175,12 @@ fetch_ea_16_long(uint32_t rmdat) #define OP_TABLE(name) ops_ ## name -#define CLOCK_CYCLES(c) cycles -= (c) -#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) +#define CLOCK_CYCLES(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) +#define CLOCK_CYCLES_ALWAYS(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) #include "x86_ops.h" diff --git a/src/cpu_new/386_dynarec.c b/src/cpu_new/386_dynarec.c index cbd8f063e..27d706061 100644 --- a/src/cpu_new/386_dynarec.c +++ b/src/cpu_new/386_dynarec.c @@ -260,13 +260,226 @@ static void prefetch_flush() #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) +#define CLOCK_CYCLES(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) +#define CLOCK_CYCLES_ALWAYS(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) #include "386_ops.h" - #define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG)) #ifdef USE_DYNAREC @@ -320,6 +533,9 @@ void exec386_dynarec(int cycs) 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) @@ -473,6 +689,9 @@ void exec386_dynarec(int cycs) 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(); @@ -540,6 +759,9 @@ void exec386_dynarec(int cycs) 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(); @@ -593,8 +815,13 @@ void exec386_dynarec(int cycs) } } } - - if (trap) + + if (in_smm && smi_line && is_pentium) + { + enter_smm(); + } + + else if (trap) { trap = 0; flags_rebuild(); diff --git a/src/cpu_new/386_dynarec_ops.c b/src/cpu_new/386_dynarec_ops.c index 343ab13c3..f5224c257 100644 --- a/src/cpu_new/386_dynarec_ops.c +++ b/src/cpu_new/386_dynarec_ops.c @@ -9,6 +9,7 @@ #endif #include "../86box.h" #include "cpu.h" +#include "../timer.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" @@ -63,6 +64,8 @@ static inline void fetch_ea_16_long(uint32_t rmdat) #define OP_TABLE(name) dynarec_ops_ ## name /*Temporary*/ #define CLOCK_CYCLES(c) -#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) do { cycles -= (c); \ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) \ + timer_process(); } while(0) #include "386_ops.h" diff --git a/src/cpu_new/386_ops.h b/src/cpu_new/386_ops.h index f2c54c0ce..b3d331423 100644 --- a/src/cpu_new/386_ops.h +++ b/src/cpu_new/386_ops.h @@ -739,7 +739,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, @@ -761,7 +761,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, @@ -783,7 +783,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, @@ -805,7 +805,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, @@ -830,7 +830,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, @@ -852,7 +852,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, @@ -874,7 +874,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, @@ -896,7 +896,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, @@ -921,7 +921,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, @@ -943,7 +943,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, @@ -965,7 +965,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, @@ -987,7 +987,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, @@ -1012,7 +1012,7 @@ const OpFn OP_TABLE(k62_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, @@ -1034,7 +1034,7 @@ const OpFn OP_TABLE(k62_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, @@ -1056,7 +1056,7 @@ const OpFn OP_TABLE(k62_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, @@ -1078,7 +1078,7 @@ const OpFn OP_TABLE(k62_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 +1103,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, @@ -1125,7 +1125,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, @@ -1147,7 +1147,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, @@ -1169,7 +1169,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, @@ -1196,7 +1196,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, @@ -1218,7 +1218,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, @@ -1240,7 +1240,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, @@ -1262,7 +1262,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, @@ -1288,7 +1288,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, @@ -1310,7 +1310,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, @@ -1332,7 +1332,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, @@ -1354,7 +1354,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, @@ -1380,7 +1380,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, @@ -1402,7 +1402,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, @@ -1424,7 +1424,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, @@ -1446,7 +1446,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_new/808x.c b/src/cpu_new/808x.c index 285f9644b..686ea9e0c 100644 --- a/src/cpu_new/808x.c +++ b/src/cpu_new/808x.c @@ -909,7 +909,10 @@ reset_common(int hard) cr0 = 1 << 30; else cr0 = 0; - cpu_cache_int_enabled = 0; + if (isibmcpu) + cpu_cache_int_enabled = 1; + else + cpu_cache_int_enabled = 0; cpu_update_waitstates(); cr4 = 0; cpu_state.eflags = 0; @@ -954,6 +957,8 @@ reset_common(int hard) prefetching = 1; takeint = 0; + + cpu_ven_reset(); } @@ -1205,7 +1210,7 @@ jcc(uint8_t opcode, int cond) wait(1, 0); cpu_data = pfq_fetchb(); wait(1, 0); - if ((!cond) == (opcode & 0x01)) + if ((!cond) == !!(opcode & 0x01)) jump_short(); } diff --git a/src/cpu_new/codegen_backend_x86-64_ops.c b/src/cpu_new/codegen_backend_x86-64_ops.c index 74173e626..8bb91da1c 100644 --- a/src/cpu_new/codegen_backend_x86-64_ops.c +++ b/src/cpu_new/codegen_backend_x86-64_ops.c @@ -1018,7 +1018,7 @@ void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_d codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ codegen_addlong(block, imm_data); } - else if (offset >= -80 || offset < 0x80) + else if (offset >= -0x80 && offset < 0x80) { codegen_alloc_bytes(block, 8); codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ diff --git a/src/cpu_new/codegen_backend_x86_ops.c b/src/cpu_new/codegen_backend_x86_ops.c index 18f0171a5..f5010e356 100644 --- a/src/cpu_new/codegen_backend_x86_ops.c +++ b/src/cpu_new/codegen_backend_x86_ops.c @@ -763,7 +763,7 @@ void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_d codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ codegen_addlong(block, imm_data); } - else if (offset >= -80 || offset < 0x80) + else if (offset >= -0x80 && offset < 0x80) { codegen_alloc_bytes(block, 8); codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ diff --git a/src/cpu_new/codegen_backend_x86_ops_sse.c b/src/cpu_new/codegen_backend_x86_ops_sse.c index 641d16532..d829e4097 100644 --- a/src/cpu_new/codegen_backend_x86_ops_sse.c +++ b/src/cpu_new/codegen_backend_x86_ops_sse.c @@ -204,7 +204,7 @@ void host_x86_MOVQ_STACK_OFFSET_XREG(codeblock_t *block, int offset, int src_reg codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVQ [ESP], src_reg*/ codegen_addbyte(block, 0x24); } - else if (offset >= -80 || offset < 0x80) + else if (offset >= -0x80 && offset < 0x80) { codegen_alloc_bytes(block, 6); codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x44 | (src_reg << 3)); /*MOVQ offset[ESP], src_reg*/ diff --git a/src/cpu_new/codegen_ops_jump.c b/src/cpu_new/codegen_ops_jump.c index 4363c9040..a4d2b8847 100644 --- a/src/cpu_new/codegen_ops_jump.c +++ b/src/cpu_new/codegen_ops_jump.c @@ -13,7 +13,7 @@ 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); + int32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); uint32_t dest_addr = op_pc+1+offset; if (!(op_32 & 0x100)) @@ -26,7 +26,7 @@ uint32_t ropJMP_r8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f } 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); + int32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); uint32_t dest_addr = op_pc+2+offset; dest_addr &= 0xffff; @@ -38,7 +38,7 @@ uint32_t ropJMP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t } 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); + int32_t offset = fastreadl(cs + op_pc); uint32_t dest_addr = op_pc+4+offset; if (offset < 0) diff --git a/src/cpu_new/codegen_timing_486.c b/src/cpu_new/codegen_timing_486.c index 6b744472b..b4054b32f 100644 --- a/src/cpu_new/codegen_timing_486.c +++ b/src/cpu_new/codegen_timing_486.c @@ -358,7 +358,7 @@ void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin { 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; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; opcode = (fetchdat >> 3) & 7; break; case 0x81: diff --git a/src/cpu_new/codegen_timing_686.c b/src/cpu_new/codegen_timing_686.c index 6bcb7c44d..609a5e068 100644 --- a/src/cpu_new/codegen_timing_686.c +++ b/src/cpu_new/codegen_timing_686.c @@ -885,7 +885,7 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uin { 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; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; opcode = (fetchdat >> 3) & 7; break; case 0x81: diff --git a/src/cpu_new/codegen_timing_pentium.c b/src/cpu_new/codegen_timing_pentium.c index ee893a361..1e4c104fd 100644 --- a/src/cpu_new/codegen_timing_pentium.c +++ b/src/cpu_new/codegen_timing_pentium.c @@ -1136,7 +1136,7 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, { 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; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; opcode = (fetchdat >> 3) & 7; break; case 0x81: diff --git a/src/cpu_new/codegen_timing_winchip.c b/src/cpu_new/codegen_timing_winchip.c index 90982349f..f488078a5 100644 --- a/src/cpu_new/codegen_timing_winchip.c +++ b/src/cpu_new/codegen_timing_winchip.c @@ -358,7 +358,7 @@ void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, { 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; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; opcode = (fetchdat >> 3) & 7; break; case 0x81: diff --git a/src/cpu_new/codegen_timing_winchip2.c b/src/cpu_new/codegen_timing_winchip2.c index 9da156b82..e7294b917 100644 --- a/src/cpu_new/codegen_timing_winchip2.c +++ b/src/cpu_new/codegen_timing_winchip2.c @@ -626,7 +626,7 @@ static void codegen_timing_winchip2_opcode(uint8_t opcode, uint32_t fetchdat, in { 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; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; opcode = (fetchdat >> 3) & 7; break; case 0x81: diff --git a/src/cpu_new/cpu.c b/src/cpu_new/cpu.c index 4dde87a96..6b277275c 100644 --- a/src/cpu_new/cpu.c +++ b/src/cpu_new/cpu.c @@ -128,6 +128,9 @@ 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; @@ -151,6 +154,7 @@ int is286, is386, is486 = 1, cpu_iscyrix, + isibmcpu, israpidcad, is_pentium; @@ -192,8 +196,12 @@ 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; +uint64_t star = 0; /* AMD K6-2+. */ + +uint64_t amd_efer = 0, amd_whcr = 0, /* AMD K6-2+ registers. */ + amd_uwccr = 0, amd_epmr = 0, + amd_psor = 0, amd_pfir = 0, + amd_l2aar = 0; int timing_rr; int timing_mr, timing_mrl; @@ -259,16 +267,14 @@ cpu_set(void) 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); + 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_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) { - if (cpu_s->pci_speed) - cpu_busspeed = cpu_s->pci_speed; - else cpu_busspeed = cpu_s->rspeed / cpu_s->multi; } cpu_multi = cpu_s->multi; @@ -484,7 +490,8 @@ cpu_set(void) 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*/ @@ -546,6 +553,79 @@ cpu_set(void) 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 @@ -663,6 +743,7 @@ cpu_set(void) case CPU_iDX4: cpu_features = CPU_FEATURE_CR4 | CPU_FEATURE_VME; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; + /*FALLTHROUGH*/ case CPU_i486SX: case CPU_i486DX: #ifdef USE_DYNAREC @@ -1203,9 +1284,9 @@ cpu_set(void) case CPU_K6: #ifdef USE_DYNAREC - x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); #else - x86_setopcodes(ops_386, ops_k6_0f); + x86_setopcodes(ops_386, ops_pentiummmx_0f); #endif timing_rr = 1; /*register dest - register src*/ timing_rm = 2; /*register dest - memory src*/ @@ -1245,6 +1326,7 @@ cpu_set(void) break; case CPU_K6_2: + case CPU_K6_2C: case CPU_K6_3: case CPU_K6_2P: case CPU_K6_3P: @@ -1308,38 +1390,39 @@ cpu_set(void) 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_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_rm = 9; - timing_int_v86 = 46; - timing_int_pm = 21; - timing_int_pm_outer = 32; + 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 = 26; + timing_iret_v86 = 27; /*unknown*/ timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 3; + timing_iret_pm_outer = 27; + timing_call_rm = 4; timing_call_pm = 4; - timing_call_pm_gate = 15; - timing_call_pm_gate_inner = 26; + 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 = 1; - timing_jmp_pm = 4; - timing_jmp_pm_gate = 14; - timing_misaligned = 2; + 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_686); + codegen_timing_set(&codegen_timing_k6); #endif break; @@ -1363,38 +1446,39 @@ cpu_set(void) 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_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_rm = 9; - timing_int_v86 = 46; - timing_int_pm = 21; - timing_int_pm_outer = 32; + 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 = 26; + timing_iret_v86 = 27; /*unknown*/ timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 3; + timing_iret_pm_outer = 27; + timing_call_rm = 4; timing_call_pm = 4; - timing_call_pm_gate = 15; - timing_call_pm_gate_inner = 26; + 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 = 1; - timing_jmp_pm = 4; - timing_jmp_pm_gate = 14; - timing_misaligned = 2; + 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_686); + codegen_timing_set(&codegen_timing_k6); #endif break; #endif @@ -1418,38 +1502,39 @@ cpu_set(void) 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_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_rm = 9; - timing_int_v86 = 46; - timing_int_pm = 21; - timing_int_pm_outer = 32; + 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 = 26; + timing_iret_v86 = 27; /*unknown*/ timing_iret_pm = 10; - timing_iret_pm_outer = 26; - timing_call_rm = 3; + timing_iret_pm_outer = 27; + timing_call_rm = 4; timing_call_pm = 4; - timing_call_pm_gate = 15; - timing_call_pm_gate_inner = 26; + 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 = 1; - timing_jmp_pm = 4; - timing_jmp_pm_gate = 14; - timing_misaligned = 2; + 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 | CR4_OSFXSR; #ifdef USE_DYNAREC - codegen_timing_set(&codegen_timing_686); + codegen_timing_set(&codegen_timing_k6); #endif break; #endif @@ -1793,6 +1878,7 @@ cpu_CPUID(void) break; case CPU_K6_2: + case CPU_K6_2C: switch (EAX) { case 0: @@ -2123,6 +2209,44 @@ cpu_CPUID(void) } } +void cpu_ven_reset(void) +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_K5: + case CPU_5K86: + case CPU_K6: + amd_efer = amd_whcr = 0ULL; + break; + case CPU_K6_2: + amd_efer = amd_whcr = 0ULL; + star = 0ULL; + break; + case CPU_K6_2C: + amd_efer = 2ULL; + amd_whcr = star = 0ULL; + amd_psor = 0x018cULL; + amd_uwccr = 0ULL; + break; + case CPU_K6_3: + amd_efer = 2ULL; + amd_whcr = star = 0ULL; + amd_psor = 0x008cULL; + amd_uwccr = 0ULL; + amd_pfir = amd_l2aar = 0ULL; + break; + case CPU_K6_2P: + case CPU_K6_3P: + amd_efer = 2ULL; + amd_whcr = star = 0ULL; + amd_psor = 0x008cULL; + amd_uwccr = 0ULL; + amd_pfir = amd_l2aar = 0ULL; + amd_epmr = 0ULL; + break; + } +} + void cpu_RDMSR() { switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) @@ -2161,31 +2285,208 @@ void cpu_RDMSR() 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: + case 0x0000000e: EAX = msr.tr12; break; - case 0x10: + case 0x00000010: EAX = tsc & 0xffffffff; EDX = tsc >> 32; break; - case 0x83: + case 0x00000083: EAX = ecx83_msr & 0xffffffff; EDX = ecx83_msr >> 32; break; + case 0xC0000080: + EAX = amd_efer & 0xffffffff; + EDX = amd_efer >> 32; + break; + case 0xC0000082: + EAX = amd_whcr & 0xffffffff; + EDX = amd_whcr >> 32; + break; + default: + x86gpf(NULL, 0); + break; + } + break; + + case CPU_K6_2: + EAX = EDX = 0; + switch (ECX) + { + case 0x0000000e: + EAX = msr.tr12; + break; + case 0x00000010: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x00000083: + EAX = ecx83_msr & 0xffffffff; + EDX = ecx83_msr >> 32; + break; + case 0xC0000080: + EAX = amd_efer & 0xffffffff; + EDX = amd_efer >> 32; + break; case 0xC0000081: EAX = star & 0xffffffff; EDX = star >> 32; break; - case 0xC0000084: - EAX = sfmask & 0xffffffff; - EDX = sfmask >> 32; + case 0xC0000082: + EAX = amd_whcr & 0xffffffff; + EDX = amd_whcr >> 32; + break; + default: + x86gpf(NULL, 0); + break; + } + break; + + case CPU_K6_2C: + EAX = EDX = 0; + switch (ECX) + { + case 0x0000000e: + EAX = msr.tr12; + break; + case 0x00000010: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x00000083: + EAX = ecx83_msr & 0xffffffff; + EDX = ecx83_msr >> 32; + break; + case 0xC0000080: + EAX = amd_efer & 0xffffffff; + EDX = amd_efer >> 32; + break; + case 0xC0000081: + EAX = star & 0xffffffff; + EDX = star >> 32; + break; + case 0xC0000082: + EAX = amd_whcr & 0xffffffff; + EDX = amd_whcr >> 32; + break; + case 0xC0000085: + EAX = amd_uwccr & 0xffffffff; + EDX = amd_uwccr >> 32; + break; + case 0xC0000087: + EAX = amd_psor & 0xffffffff; + EDX = amd_psor >> 32; + break; + case 0xC0000088: + EAX = amd_pfir & 0xffffffff; + EDX = amd_pfir >> 32; + break; + default: + x86gpf(NULL, 0); + break; + } + break; + + case CPU_K6_3: + EAX = EDX = 0; + switch (ECX) + { + case 0x0000000e: + EAX = msr.tr12; + break; + case 0x00000010: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x00000083: + EAX = ecx83_msr & 0xffffffff; + EDX = ecx83_msr >> 32; + break; + case 0xC0000080: + EAX = amd_efer & 0xffffffff; + EDX = amd_efer >> 32; + break; + case 0xC0000081: + EAX = star & 0xffffffff; + EDX = star >> 32; + break; + case 0xC0000082: + EAX = amd_whcr & 0xffffffff; + EDX = amd_whcr >> 32; + break; + case 0xC0000085: + EAX = amd_uwccr & 0xffffffff; + EDX = amd_uwccr >> 32; + break; + case 0xC0000087: + EAX = amd_psor & 0xffffffff; + EDX = amd_psor >> 32; + break; + case 0xC0000088: + EAX = amd_pfir & 0xffffffff; + EDX = amd_pfir >> 32; + break; + case 0xC0000089: + EAX = amd_l2aar & 0xffffffff; + EDX = amd_l2aar >> 32; + break; + default: + x86gpf(NULL, 0); + break; + } + break; + + case CPU_K6_2P: + case CPU_K6_3P: + EAX = EDX = 0; + switch (ECX) + { + case 0x0000000e: + EAX = msr.tr12; + break; + case 0x00000010: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x00000083: + EAX = ecx83_msr & 0xffffffff; + EDX = ecx83_msr >> 32; + break; + case 0xC0000080: + EAX = amd_efer & 0xffffffff; + EDX = amd_efer >> 32; + break; + case 0xC0000081: + EAX = star & 0xffffffff; + EDX = star >> 32; + break; + case 0xC0000082: + EAX = amd_whcr & 0xffffffff; + EDX = amd_whcr >> 32; + break; + case 0xC0000085: + EAX = amd_uwccr & 0xffffffff; + EDX = amd_uwccr >> 32; + break; + case 0xC0000086: + EAX = amd_epmr & 0xffffffff; + EDX = amd_epmr >> 32; + break; + case 0xC0000087: + EAX = amd_psor & 0xffffffff; + EDX = amd_psor >> 32; + break; + case 0xC0000088: + EAX = amd_pfir & 0xffffffff; + EDX = amd_pfir >> 32; + break; + case 0xC0000089: + EAX = amd_l2aar & 0xffffffff; + EDX = amd_l2aar >> 32; break; default: x86gpf(NULL, 0); @@ -2348,6 +2649,8 @@ i686_invalid_rdmsr: void cpu_WRMSR() { + uint64_t temp; + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) { case CPU_WINCHIP: @@ -2397,8 +2700,147 @@ void cpu_WRMSR() case CPU_K5: case CPU_5K86: case CPU_K6: + switch (ECX) + { + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x83: + ecx83_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000080: + temp = EAX | ((uint64_t)EDX << 32); + if (temp & ~1ULL) + x86gpf(NULL, 0); + else + amd_efer = temp; + break; + case 0xC0000082: + amd_whcr = EAX | ((uint64_t)EDX << 32); + break; + default: + x86gpf(NULL, 0); + break; + } + break; + case CPU_K6_2: + 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 0xC0000080: + temp = EAX | ((uint64_t)EDX << 32); + if (temp & ~1ULL) + x86gpf(NULL, 0); + else + amd_efer = temp; + break; + case 0xC0000081: + star = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000082: + amd_whcr = EAX | ((uint64_t)EDX << 32); + break; + default: + x86gpf(NULL, 0); + break; + } + break; + + case CPU_K6_2C: + 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 0xC0000080: + temp = EAX | ((uint64_t)EDX << 32); + if (temp & ~0xfULL) + x86gpf(NULL, 0); + else + amd_efer = temp; + break; + case 0xC0000081: + star = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000082: + amd_whcr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000085: + amd_uwccr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000087: + amd_psor = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000088: + amd_pfir = EAX | ((uint64_t)EDX << 32); + break; + default: + x86gpf(NULL, 0); + break; + } + break; + case CPU_K6_3: + 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 0xC0000080: + temp = EAX | ((uint64_t)EDX << 32); + if (temp & ~0x1fULL) + x86gpf(NULL, 0); + else + amd_efer = temp; + break; + case 0xC0000081: + star = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000082: + amd_whcr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000085: + amd_uwccr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000087: + amd_psor = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000088: + amd_pfir = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000089: + amd_l2aar = EAX | ((uint64_t)EDX << 32); + break; + default: + x86gpf(NULL, 0); + break; + } + break; + case CPU_K6_2P: case CPU_K6_3P: switch (ECX) @@ -2412,11 +2854,36 @@ void cpu_WRMSR() case 0x83: ecx83_msr = EAX | ((uint64_t)EDX << 32); break; + case 0xC0000080: + temp = EAX | ((uint64_t)EDX << 32); + if (temp & ~0x1fULL) + x86gpf(NULL, 0); + else + amd_efer = temp; + break; case 0xC0000081: star = EAX | ((uint64_t)EDX << 32); break; - case 0xC0000084: - sfmask = EAX | ((uint64_t)EDX << 32); + case 0xC0000082: + amd_whcr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000085: + amd_uwccr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000086: + amd_epmr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000087: + amd_psor = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000088: + amd_pfir = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000089: + amd_l2aar = EAX | ((uint64_t)EDX << 32); + break; + default: + x86gpf(NULL, 0); break; } break; diff --git a/src/cpu_new/cpu.h b/src/cpu_new/cpu.h index 953f0bee1..185250319 100644 --- a/src/cpu_new/cpu.h +++ b/src/cpu_new/cpu.h @@ -27,34 +27,38 @@ #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_WINCHIP2 17 -#define CPU_PENTIUM 18 -#define CPU_PENTIUMMMX 19 -#define CPU_Cx6x86 20 -#define CPU_Cx6x86MX 21 -#define CPU_Cx6x86L 22 -#define CPU_CxGX1 23 -#define CPU_K5 24 -#define CPU_5K86 25 -#define CPU_K6 26 -#define CPU_K6_2 27 -#define CPU_K6_3 28 -#define CPU_K6_2P 29 -#define CPU_K6_3P 30 -#define CPU_PENTIUMPRO 31 /* 686 class CPUs */ -#define CPU_PENTIUM2D 32 +#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_2C 31 +#define CPU_K6_3 32 +#define CPU_K6_2P 33 +#define CPU_K6_3P 34 +#define CPU_PENTIUMPRO 35 /* 686 class CPUs */ +#define CPU_PENTIUM2D 36 #define MANU_INTEL 0 #define MANU_AMD 1 @@ -67,18 +71,18 @@ typedef struct { - const char *name; - int cpu_type; - int rspeed; - int 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; + 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[]; @@ -90,6 +94,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[]; @@ -98,11 +108,14 @@ 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[]; @@ -324,6 +337,7 @@ 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) @@ -336,6 +350,9 @@ extern int hasfpu; 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; @@ -450,6 +467,8 @@ 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); @@ -482,5 +501,7 @@ extern void x87_reset(void); extern int cpu_effective, cpu_alt_reset; extern void cpu_dynamic_switch(int new_cpu); +extern void cpu_ven_reset(void); + #endif /*EMU_CPU_H*/ diff --git a/src/cpu_new/cpu_table.c b/src/cpu_new/cpu_table.c index ee1d4d2ec..34767b870 100644 --- a/src/cpu_new/cpu_table.c +++ b/src/cpu_new/cpu_table.c @@ -97,7 +97,7 @@ CPU cpus_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, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"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}, @@ -126,7 +126,7 @@ CPU cpus_ps1_m2011[] = { 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, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"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}, @@ -144,7 +144,7 @@ CPU cpus_i386SX[] = { }; CPU cpus_i386DX[] = { - /*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}, @@ -158,7 +158,7 @@ CPU cpus_i386DX[] = { }; CPU cpus_Am386SX[] = { - /*Am386*/ + /*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}, @@ -168,7 +168,7 @@ CPU cpus_Am386SX[] = { }; CPU cpus_Am386DX[] = { - /*Am386*/ + /*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}, @@ -186,6 +186,35 @@ CPU cpus_486SLC[] = { {"", -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}, @@ -197,140 +226,229 @@ CPU cpus_486DLC[] = { {"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*/ - {"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, 8, 8,6,6, 6}, - {"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*/ - {"Pentium OverDrive/63", CPU_PENTIUM, 62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, 15/2}, - {"Pentium OverDrive/83", CPU_PENTIUM, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, 10}, + /*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, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"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)*/ + {"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, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"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, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14, 6, 6, 10}, + {"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, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"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, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20}, + {"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*/ + /*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, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"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, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7, 7, 3, 3, 5}, + {"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, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14,16,16, 10}, + {"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, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21, 9, 9, 15}, + {"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*/ - {"6x86-P90", CPU_Cx6x86, 80000000, 3, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8, 6, 6, 10}, - {"6x86-PR120+", CPU_Cx6x86, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 12}, - {"6x86-PR133+", CPU_Cx6x86, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, - {"6x86-PR150+", CPU_Cx6x86, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"6x86-PR166+", CPU_Cx6x86, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"6x86-PR200+", CPU_Cx6x86, 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, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10, 6, 6, 14}, - {"6x86L-PR150+", CPU_Cx6x86L, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 14}, - {"6x86L-PR166+", CPU_Cx6x86L, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"6x86L-PR200+", CPU_Cx6x86L, 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, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 6, 6, 16}, - {"6x86MX-PR200", CPU_Cx6x86MX, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"6x86MX-PR233", CPU_Cx6x86MX, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 45/2}, - {"6x86MX-PR266", CPU_Cx6x86MX, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, - {"6x86MX-PR300", CPU_Cx6x86MX, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21, 7, 7, 28}, - {"6x86MX-PR333", CPU_Cx6x86MX, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20, 9, 9, 30}, - {"6x86MX-PR366", CPU_Cx6x86MX, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 30}, - {"6x86MX-PR400", CPU_Cx6x86MX, 285000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18, 9, 9, 33}, + /*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, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 9}, - {"WinChip 90", CPU_WINCHIP, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 21/2}, - {"WinChip 100", CPU_WINCHIP, 100000000, 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, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 35/2}, - {"WinChip 166", CPU_WINCHIP, 166666666, 3, 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 240", CPU_WINCHIP, 240000000, 6, 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/240", CPU_WINCHIP2, 240000000, 6, 30000000, 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, 3, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, (7*8)/2}, + {"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, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8, 8, 4, 4, 9}, - {"WinChip 90", CPU_WINCHIP, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9, 9, 4, 4, 21/2}, - {"WinChip 100", CPU_WINCHIP, 100000000, 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, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15, 15, 7, 7, 35/2}, - {"WinChip 166", CPU_WINCHIP, 166666666, 3, 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, 6, 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, 6, 30000000, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, - {"WinChip 2/250", CPU_WINCHIP2, 250000000, 6, 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, 3, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18, 18, 9, 9, (7*8)/2}, - {"WinChip 2A/266", CPU_WINCHIP2, 233333333, 6, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 28}, - {"WinChip 2A/300", CPU_WINCHIP2, 250000000, 6, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 24, 24, 12, 12, 30}, + {"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, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, - {"Pentium 66", CPU_PENTIUM, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, + {"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} @@ -339,8 +457,8 @@ CPU cpus_Pentium5V[] = { 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, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 7}, - {"Pentium 66", CPU_PENTIUM, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6, 6,3,3, 8}, + {"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}, @@ -349,170 +467,211 @@ CPU cpus_Pentium5V50[] = { CPU cpus_PentiumS5[] = { /*Intel Pentium (Socket 5)*/ - {"Pentium 75", CPU_PENTIUM, 75000000, 2, 25000000, 0x522, 0x522, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"Pentium 90", CPU_PENTIUM, 90000000, 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, 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 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, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 40}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 3, 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}, + {"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, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium OverDrive MMX 75", CPU_PENTIUMMMX, 75000000, 2, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium 90", CPU_PENTIUM, 90000000, 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, 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, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium 166", CPU_PENTIUM, 166666666, 3, 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, 3, 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, 4, 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, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 166666666, 3, 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, 4, 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, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"Pentium OverDrive 125", CPU_PENTIUM, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, - {"Pentium OverDrive 150", CPU_PENTIUM, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium OverDrive 166", CPU_PENTIUM, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 20}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, 125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12, 7, 7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, 150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, 166000000, 3, 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}, + {"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, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7,4,4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, 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, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9,4,4, 12}, - {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 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, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 3, 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}, + {"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, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, 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, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, - {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 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, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 3, 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}, - {"K6 (Model 6) 166", CPU_K6, 166666666, 3, 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, 4, 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, 4, 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, 5, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"K6-2/233", CPU_K6_2, 233333333, 4, 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, 5, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + /*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 and K6 (Socket 7)*/ - {"K5 (5k86) 75 (P75)", CPU_K5, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, 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, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9, 9, 4, 4, 12}, - {"K5 (SSA/5) 100 (PR100)", CPU_K5, 100000000, 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, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"K5 (5k86) 116.5 (PR166)", CPU_5K86, 166666666, 3, 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}, - {"K6 (Model 6) 166", CPU_K6, 166666666, 3, 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, 4, 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, 4, 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, 5, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"K6-2/233", CPU_K6_2, 233333333, 4, 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, 5, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"K6-2/333", CPU_K6_2, 333333333, 5, 31666667, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, - {"K6-2/350", CPU_K6_2, 350000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 42}, - {"K6-2/366", CPU_K6_2, 366666666, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 44}, - {"K6-2/380", CPU_K6_2, 380000000, 5, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 46}, - {"K6-2/400", CPU_K6_2, 400000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 48}, - {"K6-2/450", CPU_K6_2, 450000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 54}, - {"K6-2/475", CPU_K6_2, 475000000, 5, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 57}, - {"K6-2/500", CPU_K6_2, 500000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 60}, - {"K6-2/533", CPU_K6_2, 533333333, 5, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 64}, - {"K6-2/550", CPU_K6_2, 550000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 66}, - {"K6-2+/450", CPU_K6_2P, 450000000, 5, 33333333, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 54}, - {"K6-2+/475", CPU_K6_2P, 475000000, 5, 31666667, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 57}, - {"K6-2+/500", CPU_K6_2P, 500000000, 5, 33333333, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 60}, - {"K6-2+/533", CPU_K6_2P, 533333333, 5, 31666667, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 64}, - {"K6-2+/550", CPU_K6_2P, 550000000, 5, 33333333, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 66}, - {"K6-III/400", CPU_K6_3, 400000000, 5, 33333333, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 48}, - {"K6-III/450", CPU_K6_3, 450000000, 5, 33333333, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 54}, - {"K6-III+/400", CPU_K6_3P, 400000000, 5, 33333333, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 48}, - {"K6-III+/450", CPU_K6_3P, 450000000, 5, 33333333, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 54}, - {"K6-III+/475", CPU_K6_3P, 475000000, 5, 31666667, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 57}, - {"K6-III+/500", CPU_K6_3P, 500000000, 5, 33333333, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 60}, + /*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_2C, 350000000, 7/2, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 32, 32, 11, 11, 42}, + {"K6-2/366", CPU_K6_2C, 366666666, 11/2, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 33, 33, 17, 17, 44}, + {"K6-2/380", CPU_K6_2C, 380000000, 4, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 34, 34, 12, 12, 46}, + {"K6-2/400", CPU_K6_2C, 400000000, 4, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 36, 36, 12, 12, 48}, + {"K6-2/450", CPU_K6_2C, 450000000, 9/2, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 41, 41, 14, 14, 54}, + {"K6-2/475", CPU_K6_2C, 475000000, 5, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 43, 43, 15, 15, 57}, + {"K6-2/500", CPU_K6_2C, 500000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 45, 45, 15, 15, 60}, + {"K6-2/533", CPU_K6_2C, 533333333, 11/2, 32323232, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 48, 48, 17, 17, 64}, + {"K6-2/550", CPU_K6_2C, 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 and II Overdrive*/ - {"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, 2, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium Pro 150", CPU_PENTIUMPRO, 150000000, 3, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15, 7, 7, 35/2}, - {"Pentium Pro 166", CPU_PENTIUMPRO, 166666666, 3, 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}, - {"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, 2, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, - {"Pentium II Overdrive 210", CPU_PENTIUM2D, 210000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17, 7, 7, 25}, - {"Pentium II Overdrive 233", CPU_PENTIUM2D, 233333333, 4, 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, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 33}, - {"Pentium II Overdrive 300/66", CPU_PENTIUM2D, 300000000, 5, 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}, + /*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 diff --git a/src/cpu_new/x86_ops_misc.h b/src/cpu_new/x86_ops_misc.h index 6ecfe268a..f8db6c592 100644 --- a/src/cpu_new/x86_ops_misc.h +++ b/src/cpu_new/x86_ops_misc.h @@ -957,3 +957,15 @@ static int opWRMSR(uint32_t fetchdat) 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_mov_ctrl.h b/src/cpu_new/x86_ops_mov_ctrl.h index 55326dfe1..06a89884b 100644 --- a/src/cpu_new/x86_ops_mov_ctrl.h +++ b/src/cpu_new/x86_ops_mov_ctrl.h @@ -120,9 +120,11 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) 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))) + 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; diff --git a/src/cpu_new/x86seg.c b/src/cpu_new/x86seg.c index 2a438d862..c07f002ea 100644 --- a/src/cpu_new/x86seg.c +++ b/src/cpu_new/x86seg.c @@ -761,6 +761,7 @@ void loadcsjmp(uint16_t seg, uint32_t old_pc) x86gpf(NULL,seg2&~3); return; } + /*FALLTHROUGH*/ case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ CS=seg2; do_seg_load(&cpu_state.seg_cs, segdat); @@ -1228,6 +1229,7 @@ void loadcscall(uint16_t seg, uint32_t old_pc) x86gpf(NULL,seg2&~3); return; } + /*FALLTHROUGH*/ case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ CS=seg2; do_seg_load(&cpu_state.seg_cs, segdat); @@ -1762,6 +1764,7 @@ void pmodeint(int num, int soft) x86gpf(NULL,seg&~3); return; } + /*FALLTHROUGH*/ case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ if (!(segdat2[2]&0x8000)) { diff --git a/src/cpu_new/x87.c b/src/cpu_new/x87.c index 367948656..7d27e29f3 100644 --- a/src/cpu_new/x87.c +++ b/src/cpu_new/x87.c @@ -21,12 +21,12 @@ int fpu_do_log = ENABLE_FPU_LOG; -static void +void fpu_log(const char *fmt, ...) { va_list ap; - if (fpu_log) { + if (fpu_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); diff --git a/src/device.h b/src/device.h index e59952205..dbf9976a2 100644 --- a/src/device.h +++ b/src/device.h @@ -50,6 +50,7 @@ #define CONFIG_HEX16 7 #define CONFIG_HEX20 8 #define CONFIG_MAC 9 +#define CONFIG_MIDI_IN 10 enum { diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index 6e3946a80..920c087d5 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -304,6 +304,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) esdi->command &= ~0x03; if (val & 0x02) fatal("Read with ECC\n"); + /*FALLTHROUGH*/ case 0xa0: esdi->status = STAT_BUSY; @@ -351,6 +352,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) default: esdi_at_log("WD1007: bad command %02X\n", val); + /*FALLTHROUGH*/ case 0xe8: /*???*/ esdi->status = STAT_BUSY; timer_set_delay_u64(&esdi->callback_timer, 200 * HDC_TIME); diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index a9d1e8e59..5fedee57d 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.65 2019/11/19 + * Version: @(#)hdc_ide.c 1.0.66 2020/01/14 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. */ #define __USE_LARGEFILE64 #define _LARGEFILE_SOURCE @@ -249,8 +249,6 @@ ide_get_period(ide_t *ide, int size) break; } - 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 */ } @@ -450,7 +448,7 @@ static void ide_hd_identify(ide_t *ide) char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; uint32_t d_hpc, d_spt, d_tracks; - uint64_t full_size = (hdd[ide->hdd_num].tracks * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + uint64_t full_size = (((uint64_t) hdd[ide->hdd_num].tracks) * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); device_identify[6] = (ide->hdd_num / 10) + 0x30; device_identify[7] = (ide->hdd_num % 10) + 0x30; @@ -759,6 +757,7 @@ ide_set_features(ide_t *ide) default: return 0; } + break; case FEATURE_ENABLE_IRQ_OVERLAPPED: case FEATURE_ENABLE_IRQ_SERVICE: @@ -1461,6 +1460,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) /* 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); + /*FALLTHROUGH*/ case WIN_READ: case WIN_READ_NORETRY: @@ -1494,6 +1494,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) /* 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); + /*FALLTHROUGH*/ case WIN_WRITE: case WIN_WRITE_NORETRY: @@ -2315,7 +2316,7 @@ ide_set_handlers(uint8_t board) if (ide_boards[board] == NULL) return; - if (ide_boards[board]->base_main & 0x300) { + if (ide_boards[board]->base_main) { if (ide_boards[board]->bit32) { io_sethandler(ide_boards[board]->base_main, 1, ide_readb, ide_readw, ide_readl, @@ -2332,7 +2333,7 @@ ide_set_handlers(uint8_t board) ide_writeb, NULL, NULL, ide_boards[board]); } - if (ide_boards[board]->side_main & 0x300) { + if (ide_boards[board]->side_main) { io_sethandler(ide_boards[board]->side_main, 1, ide_read_alt_status, NULL, NULL, ide_write_devctl, NULL, NULL, @@ -2347,25 +2348,29 @@ ide_remove_handlers(uint8_t board) if (ide_boards[board] == NULL) return; - if (ide_boards[board]->bit32) { - 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_boards[board]->base_main, 1, - ide_readb, ide_readw, NULL, - ide_writeb, ide_writew, NULL, + if (ide_boards[board]->base_main) { + if (ide_boards[board]->bit32) { + 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_boards[board]->base_main, 1, + ide_readb, ide_readw, NULL, + ide_writeb, ide_writew, NULL, + ide_boards[board]); + } + io_removehandler(ide_boards[board]->base_main + 1, 7, + ide_readb, NULL, NULL, + ide_writeb, NULL, NULL, + ide_boards[board]); + } + if (ide_boards[board]->side_main) { + io_removehandler(ide_boards[board]->side_main, 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, ide_boards[board]); } - io_removehandler(ide_boards[board]->base_main + 1, 7, - ide_readb, NULL, NULL, - ide_writeb, NULL, NULL, - ide_boards[board]); - io_removehandler(ide_boards[board]->side_main, 1, - ide_read_alt_status, NULL, NULL, - ide_write_devctl, NULL, NULL, - ide_boards[board]); } @@ -2556,10 +2561,8 @@ ide_board_init(int board, int irq, int base_main, int side_main, int type) 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_boards[board]->base_main = base_main; + ide_boards[board]->side_main = side_main; ide_set_handlers(board); timer_add(&ide_boards[board]->timer, ide_callback, ide_boards[board], 0); @@ -2607,7 +2610,7 @@ ide_qua_close(void *priv) void * ide_xtide_init(void) { - ide_board_init(0, -1, -1, -1, 0); + ide_board_init(0, -1, 0, 0, 0); return ide_boards[0]; } diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index bf712bcc8..1e6fce712 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -10,13 +10,13 @@ * 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 + * Version: @(#)hdc_ide_sff8038i.c 1.0.1 2020/01/14 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. */ #include #include @@ -370,13 +370,17 @@ sff_bus_master_set_irq(int channel, void *priv) channel &= 0x01; if (dev->status & 0x04) { - if (channel && pci_use_mirq(0)) + if ((dev->irq_mode == 2) && (channel & 1) && pci_use_mirq(0)) pci_set_mirq(0, 0); + else if (dev->irq_mode == 1) + pci_set_irq(dev->slot, dev->irq_pin); else picint(1 << (14 + channel)); } else { - if ((channel & 1) && pci_use_mirq(0)) + if ((dev->irq_mode == 2) && (channel & 1) && pci_use_mirq(0)) pci_clear_mirq(0, 0); + else if (dev->irq_mode == 1) + pci_clear_irq(dev->slot, dev->irq_pin); else picintc(1 << (14 + channel)); } @@ -425,6 +429,27 @@ sff_reset(void *p) } +void +sff_set_slot(sff8038i_t *dev, int slot) +{ + dev->slot = slot; +} + + +void +sff_set_irq_mode(sff8038i_t *dev, int irq_mode) +{ + dev->irq_mode = irq_mode; +} + + +void +sff_set_irq_pin(sff8038i_t *dev, int irq_pin) +{ + dev->irq_pin = irq_pin; +} + + static void sff_close(void *p) { @@ -450,6 +475,10 @@ static void ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); + dev->slot = 7; + dev->irq_mode = 2; + dev->irq_pin = PCI_INTA; + next_id++; return dev; diff --git a/src/disk/hdc_ide_sff8038i.h b/src/disk/hdc_ide_sff8038i.h index 0be341eff..16b6ce524 100644 --- a/src/disk/hdc_ide_sff8038i.h +++ b/src/disk/hdc_ide_sff8038i.h @@ -8,12 +8,12 @@ * * Emulation core dispatcher. * - * Version: @(#)hdc_ide_sff8038i.h 1.0.0 2019/05/12 + * Version: @(#)hdc_ide_sff8038i.h 1.0.1 2020/01/14 * * 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. */ typedef struct @@ -22,7 +22,9 @@ typedef struct ptr0, enabled; uint32_t ptr, ptr_cur, addr; - int count, eot; + int count, eot, + slot, + irq_mode, irq_pin; } sff8038i_t; @@ -36,3 +38,8 @@ extern int sff_bus_master_dma_write(int channel, uint8_t *data, int transfer_len extern void sff_bus_master_set_irq(int channel, void *priv); extern void sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base); + +extern void sff_set_slot(sff8038i_t *dev, int slot); + +extern void sff_set_irq_mode(sff8038i_t *dev, int irq_mode); +extern void sff_set_irq_pin(sff8038i_t *dev, int irq_pin); diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index a49e866fe..a980ec6e8 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -1310,6 +1310,13 @@ loadrom(hdc_t *dev, const wchar_t *fn) uint32_t size; FILE *fp; + if (fn == NULL) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: NULL BIOS ROM file pointer!\n"); +#endif + return; + } + if ((fp = rom_fopen((wchar_t *) fn, L"rb")) == NULL) { st506_xt_log("ST506: BIOS ROM '%ls' not found!\n", fn); return; @@ -1326,7 +1333,8 @@ loadrom(hdc_t *dev, const wchar_t *fn) /* 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); + if (fread(dev->bios_rom.rom, 1, size, fp) != size) + fatal("ST-506 XT loadrom(): Error reading data\n"); (void)fclose(fp); /* Set up an address mask for this memory. */ diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index 9aa8f8faf..c821ef98d 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -385,9 +385,6 @@ do_seek(hdc_t *dev, drive_t *drive, int cyl) drive->cur_cyl = (drive->tracks - 1); else drive->cur_cyl = dev->track; - - if (drive->cur_cyl < 0) - drive->cur_cyl = 0; } @@ -628,12 +625,6 @@ do_send: } break; -#if 0 - case CMD_WRITE_VERIFY: - no_data = 1; - /*FALLTHROUGH*/ -#endif - case CMD_WRITE_SECTORS: if (! drive->present) { dev->comp |= COMP_ERR; @@ -666,19 +657,14 @@ do_recv: /* Ready to transfer the data in. */ dev->state = STATE_RDATA; dev->buf_idx = 0; - if (no_data) { - /* Delay a bit, no actual transfer. */ + if (dev->intr & DMA_ENA) { + /* DMA enabled. */ + dev->buf_ptr = dev->sector_buf; xta_set_callback(dev, HDC_TIME); } else { - if (dev->intr & DMA_ENA) { - /* DMA enabled. */ - dev->buf_ptr = dev->sector_buf; - xta_set_callback(dev, HDC_TIME); - } else { - /* No DMA, do PIO. */ - dev->buf_ptr = dev->data; - dev->status |= STAT_REQ; - } + /* No DMA, do PIO. */ + dev->buf_ptr = dev->data; + dev->status |= STAT_REQ; } break; diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 3a6cf6656..2e7a5b359 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -135,7 +135,7 @@ xtide_init(const device_t *info) memset(xtide, 0x00, sizeof(xtide_t)); rom_init(&xtide->bios_rom, ROM_PATH_XT, - 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); xtide->ide_board = ide_xtide_init(); @@ -162,7 +162,7 @@ xtide_at_init(const device_t *info) memset(xtide, 0x00, sizeof(xtide_t)); rom_init(&xtide->bios_rom, ROM_PATH_AT, - 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); device_add(&ide_isa_2ch_device); @@ -185,7 +185,7 @@ xtide_acculogic_init(const device_t *info) memset(xtide, 0x00, sizeof(xtide_t)); rom_init(&xtide->bios_rom, ROM_PATH_PS2, - 0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); xtide->ide_board = ide_xtide_init(); @@ -223,7 +223,7 @@ xtide_at_ps2_init(const device_t *info) memset(xtide, 0x00, sizeof(xtide_t)); rom_init(&xtide->bios_rom, ROM_PATH_PS2AT, - 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); device_add(&ide_isa_2ch_device); diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index a34f2b5cb..6a6e4ee02 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -125,12 +125,18 @@ image_is_hdx(const wchar_t *s, int check_signature) f = plat_fopen((wchar_t *)s, L"rb"); if (!f) return 0; - fseeko64(f, 0, SEEK_END); + if (fseeko64(f, 0, SEEK_END)) + fatal("image_is_hdx(): Error while seeking"); filelen = ftello64(f); - fseeko64(f, 0, SEEK_SET); - if (filelen < 44) + if (fseeko64(f, 0, SEEK_SET)) + fatal("image_is_hdx(): Error while seeking"); + if (filelen < 44) { + if (f != NULL) + fclose(f); return 0; - fread(&signature, 1, 8, f); + } + if (fread(&signature, 1, 8, f) != 8) + fatal("image_is_hdx(): Error reading signature\n"); fclose(f); if (signature == 0xD778A82044445459ll) return 1; @@ -163,10 +169,17 @@ image_is_vhd(const wchar_t *s, int check_signature) return 0; fseeko64(f, 0, SEEK_END); filelen = ftello64(f); - fseeko64(f, -512, SEEK_END); - if (filelen < 512) + if (fseeko64(f, -512, SEEK_END) == -1) { + fclose(f); + fatal("image_is_vhd(): Error seeking\n"); + } + if (filelen < 512) { + if (f != NULL) + fclose(f); return 0; - fread(&signature, 1, 8, f); + } + if (fread(&signature, 1, 8, f) != 8) + fatal("image_is_vhd(): Error reading signature\n"); fclose(f); if (signature == 0x78697463656E6F63ll) return 1; @@ -632,13 +645,19 @@ hdd_image_load(int id) } } else { if (image_is_hdi(fn)) { - fseeko64(hdd_images[id].file, 0x8, SEEK_SET); - fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file); - fseeko64(hdd_images[id].file, 0xC, SEEK_SET); + if (fseeko64(hdd_images[id].file, 0x8, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offset 0x8\n"); + if (fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading base offset\n"); + if (fseeko64(hdd_images[id].file, 0xC, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offest 0xC\n"); full_size = 0LL; - fread(&full_size, 1, 4, hdd_images[id].file); - fseeko64(hdd_images[id].file, 0x10, SEEK_SET); - fread(§or_size, 1, 4, hdd_images[id].file); + if (fread(&full_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading full size\n"); + if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offset 0x10\n"); + if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sector size\n"); if (sector_size != 512) { /* Sector size is not 512 */ hdd_image_log("HDI: Sector size is not 512\n"); @@ -647,19 +666,26 @@ hdd_image_load(int id) memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); return 0; } - fread(&spt, 1, 4, hdd_images[id].file); - fread(&hpc, 1, 4, hdd_images[id].file); - fread(&tracks, 1, 4, hdd_images[id].file); + if (fread(&spt, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); + if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); + if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading number of tracks\n"); hdd[id].spt = spt; hdd[id].hpc = hpc; hdd[id].tracks = tracks; hdd_images[id].type = 1; } else if (is_hdx[1]) { hdd_images[id].base = 0x28; - fseeko64(hdd_images[id].file, 8, SEEK_SET); - fread(&full_size, 1, 8, hdd_images[id].file); - fseeko64(hdd_images[id].file, 0x10, SEEK_SET); - fread(§or_size, 1, 4, hdd_images[id].file); + if (fseeko64(hdd_images[id].file, 8, SEEK_SET) == -1) + fatal("hdd_image_load(): HDX: Error seeking to offset 0x8\n"); + if (fread(&full_size, 1, 8, hdd_images[id].file) != 8) + fatal("hdd_image_load(): HDX: Error reading full size\n"); + if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) + fatal("hdd_image_load(): HDX: Error seeking to offset 0x10\n"); + if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDX: Error reading sector size\n"); if (sector_size != 512) { /* Sector size is not 512 */ hdd_image_log("HDX: Sector size is not 512\n"); @@ -668,16 +694,21 @@ hdd_image_load(int id) memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); return 0; } - fread(&spt, 1, 4, hdd_images[id].file); - fread(&hpc, 1, 4, hdd_images[id].file); - fread(&tracks, 1, 4, hdd_images[id].file); + if (fread(&spt, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); + if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); + if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDX: Error reading number of tracks\n"); hdd[id].spt = spt; hdd[id].hpc = hpc; hdd[id].tracks = tracks; hdd_images[id].type = 2; } else if (is_vhd[1]) { - fseeko64(hdd_images[id].file, -512, SEEK_END); - fread(empty_sector, 1, 512, hdd_images[id].file); + if (fseeko64(hdd_images[id].file, -512, SEEK_END) == -1) + fatal("hdd_image_load(): VHD: Error seeking to 512 bytes before the end of file\n"); + if (fread(empty_sector, 1, 512, hdd_images[id].file) != 512) + fatal("hdd_image_load(): HDX: Error reading the footer\n"); new_vhd_footer(&vft); vhd_footer_from_bytes(vft, (uint8_t *) empty_sector); if (vft->type != 2) { @@ -711,7 +742,8 @@ hdd_image_load(int id) } } - fseeko64(hdd_images[id].file, 0, SEEK_END); + if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1) + fatal("hdd_image_load(): Error seeking to the end of file\n"); s = ftello64(hdd_images[id].file); if (s < (full_size + hdd_images[id].base)) ret = prepare_new_hard_disk(id, full_size); @@ -722,7 +754,8 @@ hdd_image_load(int id) } if (is_vhd[0]) { - fseeko64(hdd_images[id].file, 0, SEEK_END); + if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1) + fatal("hdd_image_load(): VHD: Error seeking to the end of file\n"); s = ftello64(hdd_images[id].file); if (s == (full_size + hdd_images[id].base)) { /* VHD image. */ @@ -741,7 +774,8 @@ hdd_image_seek(uint8_t id, uint32_t sector) addr = (uint64_t)sector << 9LL; hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET); + if (fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET) == -1) + fatal("hdd_image_seek(): Error seeking\n"); } @@ -750,7 +784,10 @@ hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { int i; - fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET); + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Read error during seek\n", id); + return; + } for (i = 0; i < count; i++) { if (feof(hdd_images[id].file)) @@ -792,7 +829,10 @@ hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { int i; - fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET); + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Write error during seek\n", id); + return; + } for (i = 0; i < count; i++) { if (feof(hdd_images[id].file)) @@ -828,7 +868,10 @@ hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) memset(empty_sector, 0, 512); - fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET); + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Zero error during seek\n", id); + return; + } for (i = 0; i < count; i++) { if (feof(hdd_images[id].file)) diff --git a/src/disk/zip.c b/src/disk/zip.c index 60c775810..1bbec776b 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -527,9 +527,10 @@ zip_load(zip_t *dev, wchar_t *fn) dev->drv->medium_size = size >> 9; - fseek(dev->drv->f, dev->drv->base, SEEK_SET); + if (fseek(dev->drv->f, dev->drv->base, SEEK_SET) == -1) + fatal("zip_load(): Error seeking to the beginning of the file\n"); - memcpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path)); + wcsncpy(dev->drv->image_path, fn, sizeof_w(dev->drv->image_path)); return 1; } @@ -859,14 +860,15 @@ zip_bus_speed(zip_t *dev) { double ret = -1.0; - if (dev->drv->bus_type == ZIP_BUS_SCSI) { + if (dev && dev->drv && (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; + if (dev) + dev->callback = -1.0; return 0.0; } else return ret * 1000000.0; @@ -1173,15 +1175,19 @@ zip_blocks(zip_t *dev, int32_t *len, int first_batch, int out) *len = dev->requested_blocks << 9; for (i = 0; i < dev->requested_blocks; i++) { - fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9) + (i << 9), SEEK_SET); + if (fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9) + (i << 9), SEEK_SET) == 1) + break; 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); + if (out) { + if (fwrite(dev->buffer + (i << 9), 1, 512, dev->drv->f) != 512) + fatal("zip_blocks(): Error writing data\n"); + } else { + if (fread(dev->buffer + (i << 9), 1, 512, dev->drv->f) != 512) + fatal("zip_blocks(): Error reading data\n"); + } } zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); @@ -1442,6 +1448,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_invalid_field(dev); return; } + /*FALLTHROUGH*/ case GPCMD_SCSI_RESERVE: case GPCMD_SCSI_RELEASE: case GPCMD_TEST_UNIT_READY: @@ -2123,8 +2130,10 @@ zip_phase_data_out(scsi_common_t *sc) dev->buffer[6] = (s >> 8) & 0xff; dev->buffer[7] = s & 0xff; } - fseek(dev->drv->f, dev->drv->base + (i << 9), SEEK_SET); - fwrite(dev->buffer, 1, 512, dev->drv->f); + if (fseek(dev->drv->f, dev->drv->base + (i << 9), SEEK_SET) == -1) + fatal("zip_phase_data_out(): Error seeking\n"); + if (fwrite(dev->buffer, 1, 512, dev->drv->f) != 512) + fatal("zip_phase_data_out(): Error writing data\n"); } break; case GPCMD_MODE_SELECT_6: @@ -2367,7 +2376,7 @@ zip_hard_reset(void) zip_log("ZIP hard_reset drive=%d\n", c); /* 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)) + if ((zip_drives[c].bus_type == ZIP_BUS_SCSI) && (zip_drives[c].scsi_device_id >= SCSI_ID_MAX)) continue; /* Make sure to ignore any ATAPI ZIP drive that has an out of range IDE channel. */ diff --git a/src/dma.c b/src/dma.c index 7322f471e..f9a02f365 100644 --- a/src/dma.c +++ b/src/dma.c @@ -8,15 +8,15 @@ * * Implementation of the Intel DMA controllers. * - * Version: @(#)dma.c 1.0.7 2019/09/28 + * Version: @(#)dma.c 1.0.8 2020/01/14 * * 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. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #include #include @@ -38,6 +38,7 @@ dma_t dma[8]; +uint8_t dma_e; static uint8_t dmaregs[16]; @@ -615,6 +616,8 @@ dma_reset(void) dma_wp = dma16_wp = 0; dma_m = 0; + dma_e = 0xff; + for (c = 0; c < 16; c++) dmaregs[c] = dma16regs[c] = 0; for (c = 0; c < 8; c++) { @@ -736,6 +739,8 @@ dma_channel_read(int channel) return(DMA_NODATA); } + if (!(dma_e & (1 << channel))) + return(DMA_NODATA); if ((dma_m & (1 << channel)) && !dma_req_is_soft) return(DMA_NODATA); if ((dma_c->mode & 0xC) != 8) @@ -809,6 +814,8 @@ dma_channel_write(int channel, uint16_t val) return(DMA_NODATA); } + if (!(dma_e & (1 << channel))) + return(DMA_NODATA); if ((dma_m & (1 << channel)) && !dma_req_is_soft) return(DMA_NODATA); if ((dma_c->mode & 0xC) != 4) diff --git a/src/dma.h b/src/dma.h index 75f923e66..5340ba2ea 100644 --- a/src/dma.h +++ b/src/dma.h @@ -8,15 +8,15 @@ * * Definitions for the Intel DMA controller. * - * Version: @(#)dma.h 1.0.2 2018/03/12 + * Version: @(#)dma.h 1.0.3 2020/01/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-2020 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + * Copyright 2008-2020 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 @@ -63,6 +63,7 @@ typedef struct { extern dma_t dma[8]; +extern uint8_t dma_e; extern void dma_init(void); diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 401093ef0..495f8c3d1 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -994,6 +994,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 0x16: /* Verify */ if (fdc->params[0] & 0x80) fdc->sc = fdc->params[7]; + /*FALLTHROUGH*/ case 0x06: /* Read data */ case 0x0c: /* Read deleted data */ fdc_io_command_phase1(fdc, 0); diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 92bffd9be..24bd46313 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -491,7 +491,8 @@ fdd_load(int drive, wchar_t *fn) f = plat_fopen(fn, L"rb"); if (!f) return; - fseek(f, -1, SEEK_END); + if (fseek(f, -1, SEEK_END) == -1) + fatal("fdd_load(): Error seeking to the end of the file\n"); size = ftell(f) + 1; fclose(f); while (loaders[c].ext) { diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 4fb68c606..860c424c2 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -1174,15 +1174,8 @@ d86f_put_bit(int drive, int side, int bit) if (d86f_has_surface_desc(drive)) { surface_bit = (surface_data >> track_bit) & 1; if (! surface_bit) { - if (! current_bit) { - /* Bit is 0 and is not set to fuzzy, we overwrite it as is. */ - dev->last_word[side] |= bit; - current_bit = bit; - } else { - /* Bit is 1 and is not set to fuzzy, we overwrite it as is. */ - dev->last_word[side] |= bit; - current_bit = bit; - } + dev->last_word[side] |= bit; + current_bit = bit; } else { if (current_bit) { /* Bit is 1 and is set to fuzzy, we overwrite it with a non-fuzzy bit. */ @@ -2949,10 +2942,13 @@ d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *da, ui if (dev->track_offset[logical_track]) { if (! thin_track) { - fseek(dev->f, dev->track_offset[logical_track], SEEK_SET); - fread(&(dev->side_flags[side]), 2, 1, dev->f); + if (fseek(dev->f, dev->track_offset[logical_track], SEEK_SET) == -1) + fatal("d86f_read_track(): Error seeking to offset dev->track_offset[logical_track]\n"); + if (fread(&(dev->side_flags[side]), 1, 2, dev->f) != 2) + fatal("d86f_read_track(): Error reading side flags\n"); if (d86f_has_extra_bit_cells(drive)) { - fread(&(dev->extra_bit_cells[side]), 4, 1, dev->f); + if (fread(&(dev->extra_bit_cells[side]), 1, 4, dev->f) != 4) + fatal("d86f_read_track(): Error reading number of extra bit cells\n"); /* 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)) { @@ -3146,7 +3142,8 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) } if (tbl[logical_track]) { - fseek(*f, tbl[logical_track], SEEK_SET); + if (fseek(*f, tbl[logical_track], SEEK_SET) == -1) + fatal("d86f_write_tracks(): Error seeking to offset tbl[logical_track]\n"); d86f_write_track(drive, f, side, d86f_handler[drive].encoded_data(drive, side), dev->track_surface_data[side]); } } @@ -3161,7 +3158,7 @@ d86f_writeback(int drive) { d86f_t *dev = d86f[drive]; uint8_t header[32]; - int header_size; + int header_size, size; #ifdef D86F_COMPRESS uint32_t len; int ret = 0; @@ -3172,11 +3169,16 @@ d86f_writeback(int drive) if (! dev->f) return; /* First write the track offsets table. */ - fseek(dev->f, 0, SEEK_SET); - fread(header, 1, header_size, dev->f); + if (fseek(dev->f, 0, SEEK_SET) == -1) + fatal("86F write_back(): Error seeking to the beginning of the file\n"); + if (fread(header, 1, header_size, dev->f) != header_size) + fatal("86F write_back(): Error reading header size\n"); - fseek(dev->f, 8, SEEK_SET); - fwrite(dev->track_offset, 1, d86f_get_track_table_size(drive), dev->f); + if (fseek(dev->f, 8, SEEK_SET) == -1) + fatal("86F write_back(): Error seeking\n"); + size = d86f_get_track_table_size(drive); + if (fwrite(dev->track_offset, 1, size, dev->f) != size) + fatal("86F write_back(): Error writing data\n"); d86f_write_tracks(drive, &dev->f, NULL); @@ -3586,7 +3588,9 @@ d86f_load(int drive, wchar_t *fn) return; } - fread(&(dev->version), 2, 1, dev->f); + if (fread(&(dev->version), 1, 2, dev->f) != 2) + fatal("d86f_load(): Error reading format version\n"); + if (dev->version != D86FVER) { /* File is not of a recognized format version, abort. */ if (dev->version == 0x0063) { @@ -3779,10 +3783,13 @@ d86f_load(int drive, wchar_t *fn) } /* Load track 0 flags as default. */ - fseek(dev->f, dev->track_offset[0], SEEK_SET); - fread(&(dev->side_flags[0]), 2, 1, dev->f); + if (fseek(dev->f, dev->track_offset[0], SEEK_SET) == -1) + fatal("d86f_load(): Track 0: Error seeking to the beginning of the file\n"); + if (fread(&(dev->side_flags[0]), 1, 2, dev->f) != 2) + fatal("d86f_load(): Track 0: Error reading side flags\n"); if (dev->disk_flags & 0x80) { - fread(&(dev->extra_bit_cells[0]), 4, 1, dev->f); + if (fread(&(dev->extra_bit_cells[0]), 1, 4, dev->f) != 4) + fatal("d86f_load(): Track 0: Error reading the amount of extra bit cells\n"); 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; @@ -3792,10 +3799,13 @@ d86f_load(int drive, wchar_t *fn) } if (d86f_get_sides(drive) == 2) { - fseek(dev->f, dev->track_offset[1], SEEK_SET); - fread(&(dev->side_flags[1]), 2, 1, dev->f); + if (fseek(dev->f, dev->track_offset[1], SEEK_SET) == -1) + fatal("d86f_load(): Track 1: Error seeking to the beginning of the file\n"); + if (fread(&(dev->side_flags[1]), 1, 2, dev->f) != 2) + fatal("d86f_load(): Track 1: Error reading side flags\n"); if (dev->disk_flags & 0x80) { - fread(&(dev->extra_bit_cells[1]), 4, 1, dev->f); + if (fread(&(dev->extra_bit_cells[1]), 1, 4, dev->f) != 4) + fatal("d86f_load(): Track 4: Error reading the amount of extra bit cells\n"); 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; diff --git a/src/floppy/fdd_fdi.c b/src/floppy/fdd_fdi.c index d49c851a5..f9e42ed6b 100644 --- a/src/floppy/fdd_fdi.c +++ b/src/floppy/fdd_fdi.c @@ -329,19 +329,21 @@ fdi_load(int drive, wchar_t *fn) /* Allocate a drive block. */ dev = (fdi_t *)malloc(sizeof(fdi_t)); - memset(dev, 0x00, sizeof(fdi_t)); - dev->f = plat_fopen(fn, L"rb"); if (dev == NULL) { - free(dev); memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); return; } + memset(dev, 0x00, sizeof(fdi_t)); + d86f_unregister(drive); - fread(header, 1, 25, dev->f); - fseek(dev->f, 0, SEEK_SET); + dev->f = plat_fopen(fn, L"rb"); + if (fread(header, 1, 25, dev->f) != 25) + fatal("fdi_load(): Error reading header\n"); + if (fseek(dev->f, 0, SEEK_SET) == -1) + fatal("fdi_load(): Error seeking to the beginning of the file\n"); header[25] = 0; if (strcmp(header, "Formatted Disk Image file") != 0) { /* This is a Japanese FDI file. */ diff --git a/src/floppy/fdd_imd.c b/src/floppy/fdd_imd.c index 421e339cf..a9c9c21fa 100644 --- a/src/floppy/fdd_imd.c +++ b/src/floppy/fdd_imd.c @@ -190,8 +190,8 @@ track_is_xdf(int drive, int side, int track) dev->current_side_flags[side] = (dev->tracks[track][side].params[3] == 19) ? 0x08 : 0x28; return((dev->tracks[track][side].params[3] == 19) ? 2 : 1); } - return(0); } + return(0); } else { if (dev->tracks[track][side].params[4] != 0xFF) return(0); @@ -629,6 +629,7 @@ imd_load(int drive, wchar_t *fn) dev->f = plat_fopen(fn, L"rb"); if (dev->f == NULL) { memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); return; } writeprot[drive] = 1; @@ -638,8 +639,10 @@ imd_load(int drive, wchar_t *fn) writeprot[drive] = 1; fwriteprot[drive] = writeprot[drive]; - fseek(dev->f, 0, SEEK_SET); - fread(&magic, 1, 4, dev->f); + if (fseek(dev->f, 0, SEEK_SET) == -1) + fatal("imd_load(): Error seeking to the beginning of the file\n"); + if (fread(&magic, 1, 4, dev->f) != 4) + fatal("imd_load(): Error reading the magic number\n"); if (magic != 0x20444D49) { imd_log("IMD: Not a valid ImageDisk image\n"); fclose(dev->f); @@ -649,14 +652,24 @@ imd_load(int drive, wchar_t *fn) } else imd_log("IMD: Valid ImageDisk image\n"); - fseek(dev->f, 0, SEEK_END); + if (fseek(dev->f, 0, SEEK_END) == -1) + fatal("imd_load(): Error seeking to the end of the file\n"); fsize = ftell(dev->f); - fseek(dev->f, 0, SEEK_SET); + if (fsize <= 0) { + imd_log("IMD: Too small ImageDisk image\n"); + fclose(dev->f); + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + if (fseek(dev->f, 0, SEEK_SET) == -1) + fatal("imd_load(): Error seeking to the beginning of the file again\n"); dev->buffer = malloc(fsize); - fread(dev->buffer, 1, fsize, dev->f); + if (fread(dev->buffer, 1, fsize, dev->f) != fsize) + fatal("imd_load(): Error reading data\n"); buffer = dev->buffer; - buffer2 = strchr(buffer, 0x1A); + buffer2 = memchr(buffer, 0x1A, fsize); if (buffer2 == NULL) { imd_log("IMD: No ASCII EOF character\n"); fclose(dev->f); diff --git a/src/floppy/fdd_img.c b/src/floppy/fdd_img.c index 5e0bfaacd..e1417254a 100644 --- a/src/floppy/fdd_img.c +++ b/src/floppy/fdd_img.c @@ -393,15 +393,19 @@ write_back(int drive) { img_t *dev = img[drive]; int ssize = 128 << ((int) dev->sector_size); - int side; + int side, size; if (dev->f == NULL) return; if (dev->disk_at_once) return; - fseek(dev->f, dev->base + (dev->track * dev->sectors * ssize * dev->sides), SEEK_SET); - for (side = 0; side < dev->sides; side++) - fwrite(dev->track_data[side], dev->sectors * ssize, 1, dev->f); + if (fseek(dev->f, dev->base + (dev->track * dev->sectors * ssize * dev->sides), SEEK_SET) == -1) + pclog("IMG write_back(): Error seeking to the beginning of the file\n"); + for (side = 0; side < dev->sides; side++) { + size = dev->sectors * ssize; + if (fwrite(dev->track_data[side], 1, size, dev->f) != size) + fatal("IMG write_back(): Error writing data\n"); + } } @@ -486,8 +490,10 @@ img_seek(int drive, int track) is_t0 = (track == 0) ? 1 : 0; - if (! dev->disk_at_once) - fseek(dev->f, dev->base + (track * dev->sectors * ssize * dev->sides), SEEK_SET); + if (! dev->disk_at_once) { + if (fseek(dev->f, dev->base + (track * dev->sectors * ssize * dev->sides), SEEK_SET) == -1) + fatal("img_seek(): Error seeking\n"); + } for (side = 0; side < dev->sides; side++) { if (dev->disk_at_once) { @@ -1103,7 +1109,8 @@ jump_if_fdf: /* The BPB readings appear to be valid, so let's set the values. */ if (fdi) { /* The image is a Japanese FDI, therefore we read the number of tracks from the header. */ - fseek(dev->f, 0x1C, SEEK_SET); + if (fseek(dev->f, 0x1C, SEEK_SET) == -1) + fatal("Japanese FDI: Failed when seeking to 0x1C\n"); fread(&(dev->tracks), 1, 4, dev->f); } else { if (!cqm && !fdf) { @@ -1155,8 +1162,12 @@ jump_if_fdf: dev->gap2_size = (temp_rate == 3) ? 41 : 22; if (dev->dmf) dev->gap3_size = 8; - else - dev->gap3_size = gap3_sizes[temp_rate][dev->sector_size][dev->sectors]; + else { + if (dev->sectors == -1) + dev->gap3_size = 8; + else + dev->gap3_size = gap3_sizes[temp_rate][dev->sector_size][dev->sectors]; + } if (! dev->gap3_size) { img_log("ERROR: Floppy image of unknown format was inserted into drive %c:!\n", drive + 0x41); fclose(dev->f); diff --git a/src/floppy/fdd_json.c b/src/floppy/fdd_json.c index d194b811d..465e1d6a0 100644 --- a/src/floppy/fdd_json.c +++ b/src/floppy/fdd_json.c @@ -395,7 +395,6 @@ json_seek(int drive, int track) int side, sector; int rate, gap2, gap3, pos; int ssize, rsec, asec; - int interleave_type; if (dev->f == NULL) { json_log("JSON: seek: no file loaded!\n"); @@ -415,8 +414,6 @@ json_seek(int drive, int track) d86f_reset_index_hole_pos(drive, 1); d86f_destroy_linked_lists(drive, 1); - interleave_type = 0; - if (track > dev->tracks) { d86f_zero_track(drive); return; @@ -438,13 +435,9 @@ json_seek(int drive, int track) pos = d86f_prepare_pretrack(drive, side, 0); for (sector=0; sectorspt[track][side]; sector++) { - if (interleave_type == 0) { - rsec = dev->sects[track][side][sector].sector; - asec = sector; - } else { - rsec = fdd_dmf_r[sector]; - asec = dev->interleave_ordered[rsec][side]; - } + rsec = dev->sects[track][side][sector].sector; + asec = sector; + id[0] = track; id[1] = side; id[2] = rsec; diff --git a/src/floppy/fdd_mfm.c b/src/floppy/fdd_mfm.c index 879bc200e..507a0c0a2 100644 --- a/src/floppy/fdd_mfm.c +++ b/src/floppy/fdd_mfm.c @@ -338,7 +338,7 @@ mfm_read_side(int drive, int side) { mfm_t *dev = mfm[drive]; int track_index, track_size; - int track_bytes; + int track_bytes, ret; if (dev->hdr.if_type & 0x80) track_index = get_adv_track_index(drive, side, dev->cur_track); @@ -354,10 +354,13 @@ mfm_read_side(int drive, int side) 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); + ret = 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); + ret = fseek(dev->f, dev->tracks[track_index].track_offset, SEEK_SET); + if (ret == -1) + fatal("mfm_read_side(): Error seeking to the beginning of the file\n"); + if (fread(dev->track_data[side], 1, track_bytes, dev->f) != track_bytes) + fatal("mfm_read_side(): Error reading track bytes\n"); } mfm_log("drive = %i, side = %i, dev->cur_track = %i, track_index = %i, track_size = %i\n", @@ -399,7 +402,7 @@ mfm_load(int drive, wchar_t *fn) { mfm_t *dev; double dbr; - int i; + int i, size; writeprot[drive] = fwriteprot[drive] = 1; @@ -417,16 +420,22 @@ mfm_load(int drive, wchar_t *fn) d86f_unregister(drive); /* Read the header. */ - fread(&dev->hdr, 1, sizeof(mfm_header_t), dev->f); + size = sizeof(mfm_header_t); + if (fread(&dev->hdr, 1, size, dev->f) != size) + fatal("mfm_load(): Error reading header\n"); /* 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); + size = dev->total_tracks * sizeof(mfm_adv_track_t); + if (fread(dev->adv_tracks, 1, size, dev->f) != size) + fatal("mfm_load(): Error reading advanced tracks\n"); } 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); + size = dev->total_tracks * sizeof(mfm_track_t); + if (fread(dev->tracks, 1, size, dev->f) != size) + fatal("mfm_load(): Error reading tracks\n"); } /* The chances of finding a HxC MFM image of a single-sided thin track diff --git a/src/floppy/fdd_td0.c b/src/floppy/fdd_td0.c index fd4d4419f..a230a7ae8 100644 --- a/src/floppy/fdd_td0.c +++ b/src/floppy/fdd_td0.c @@ -231,8 +231,10 @@ fdd_image_read(int drive, char *buffer, uint32_t offset, uint32_t len) { td0_t *dev = td0[drive]; - fseek(dev->f, offset, SEEK_SET); - fread(buffer, 1, len, dev->f); + if (fseek(dev->f, offset, SEEK_SET) == -1) + fatal("fdd_image_read(): Error seeking to the beginning of the file\n"); + if (fread(buffer, 1, len, dev->f) != len) + fatal("fdd_image_read(): Error reading data\n"); } @@ -260,8 +262,10 @@ state_data_read(td0dsk_t *state, uint8_t *buf, uint16_t size) image_size = ftell(state->fdd_file); if (size > image_size - state->fdd_file_offset) size = (image_size - state->fdd_file_offset) & 0xffff; - fseek(state->fdd_file, state->fdd_file_offset, SEEK_SET); - fread(buf, 1, size, state->fdd_file); + if (fseek(state->fdd_file, state->fdd_file_offset, SEEK_SET) == -1) + fatal("TD0: Failed to seek in state_data_read()\n"); + if (fread(buf, 1, size, state->fdd_file) != size) + fatal("TD0: Error reading data in state_data_read()\n"); state->fdd_file_offset += size; return(size); @@ -652,8 +656,10 @@ td0_initialize(int drive) state_Decode(&disk_decode, dev->imagebuf, TD0_MAX_BUFSZ); } else { td0_log("TD0: File is uncompressed\n"); - fseek(dev->f, 12, SEEK_SET); - fread(dev->imagebuf, 1, file_size - 12, dev->f); + if (fseek(dev->f, 12, SEEK_SET) == -1) + fatal("td0_initialize(): Error seeking to offet 12\n"); + if (fread(dev->imagebuf, 1, file_size - 12, dev->f) != (file_size - 12)) + fatal("td0_initialize(): Error reading image buffer\n"); } if (header[7] & 0x80) @@ -904,15 +910,15 @@ static void set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) { td0_t *dev = td0[drive]; - int i = 0; + int i = 0, cyl = c; dev->current_sector_index[side] = 0; - if (c != dev->track) return; - for (i = 0; i < dev->track_spt[c][side]; i++) { - if ((dev->sects[c][side][i].track == c) && - (dev->sects[c][side][i].head == h) && - (dev->sects[c][side][i].sector == r) && - (dev->sects[c][side][i].size == n)) { + if (cyl != dev->track) return; + for (i = 0; i < dev->track_spt[cyl][side]; i++) { + if ((dev->sects[cyl][side][i].track == c) && + (dev->sects[cyl][side][i].head == h) && + (dev->sects[cyl][side][i].sector == r) && + (dev->sects[cyl][side][i].size == n)) { dev->current_sector_index[side] = i; } } diff --git a/src/floppy/fdi2raw.c b/src/floppy/fdi2raw.c index b42ca2f1d..d01054e97 100644 --- a/src/floppy/fdi2raw.c +++ b/src/floppy/fdi2raw.c @@ -187,10 +187,14 @@ static uae_u8 temp, temp2; static uae_u8 *expand_tree (uae_u8 *stream, NODE *node) { if (temp & temp2) { - fdi_free (node->left); - node->left = 0; - fdi_free (node->right); - node->right = 0; + if (node->left) { + fdi_free (node->left); + node->left = 0; + } + if (node->right) { + fdi_free (node->right); + node->right = 0; + } temp2 >>= 1; if (!temp2) { temp = *stream++; @@ -322,7 +326,9 @@ static void fdi_decode (uae_u8 *stream, int size, uae_u8 *out) ((uae_u32*)out)[i] = v; } free_nodes (root.left); + root.left = 0; free_nodes (root.right); + root.right = 0; } } @@ -2029,9 +2035,16 @@ FDI *fdi2raw_header(FILE *f) memset (fdi, 0, sizeof (FDI)); fdi->file = f; oldseek = ftell (fdi->file); - fseek (fdi->file, 0, SEEK_SET); - fread (fdi->header, 2048, 1, fdi->file); - fseek (fdi->file, oldseek, SEEK_SET); + if (oldseek == -1) { + fdi_free(fdi); + return NULL; + } + if (fseek (fdi->file, 0, SEEK_SET) == -1) + fatal("fdi2raw_header(): Error seeking to the beginning of the file\n"); + if (fread (fdi->header, 1, 2048, fdi->file) != 2048) + fatal("fdi2raw_header(): Error reading header\n"); + if (fseek (fdi->file, oldseek, SEEK_SET) == -1) + fatal("fdi2raw_header(): Error seeking to offset oldseek\n"); if (memcmp (fdiid, fdi->header, strlen ((char *)fdiid)) ) { fdi_free(fdi); return NULL; @@ -2127,8 +2140,10 @@ int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int trac fdi->err = 0; fdi->track_src_len = fdi->track_offsets[track + 1] - fdi->track_offsets[track]; - fseek (fdi->file, fdi->track_offsets[track], SEEK_SET); - fread (fdi->track_src_buffer, fdi->track_src_len, 1, fdi->file); + if (fseek (fdi->file, fdi->track_offsets[track], SEEK_SET) == -1) + fatal("fdi2raw_loadtrack(): Error seeking to the beginning of the file\n"); + if (fread (fdi->track_src_buffer, 1, fdi->track_src_len, fdi->file) != fdi->track_src_len) + fatal("fdi2raw_loadtrack(): Error reading data\n"); memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER); fdi->track_dst_buffer_timing[0] = 0; @@ -2167,7 +2182,7 @@ int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int trac zxx (fdi); outlen = -1; - } else if (fdi->track_type < 0x10) { + } else if (fdi->track_type < 0x0f) { decode_normal_track[fdi->track_type](fdi); fix_mfm_sync (fdi); diff --git a/src/game/gameport.c b/src/game/gameport.c index eb3eaf893..e41489111 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -90,6 +90,7 @@ static const joystick_if_t *joystick_list[] = { &joystick_standard_4button, &joystick_standard_6button, &joystick_standard_8button, + &joystick_4axis_4button, &joystick_ch_flightstick_pro, &joystick_sw_pad, &joystick_tm_fcs, @@ -265,7 +266,7 @@ gameport_init(const device_t *info) { gameport_t *p = NULL; - if (joystick_type == 7) { + if (joystick_type == JOYSTICK_TYPE_NONE) { p = NULL; return(p); } @@ -284,7 +285,7 @@ gameport_201_init(const device_t *info) { gameport_t *p; - if (joystick_type == 7) { + if (joystick_type == JOYSTICK_TYPE_NONE) { p = NULL; return(p); } diff --git a/src/game/gameport.h b/src/game/gameport.h index e1fec8fb8..0ef53921d 100644 --- a/src/game/gameport.h +++ b/src/game/gameport.h @@ -45,8 +45,10 @@ #define POV_X 0x80000000 #define POV_Y 0x40000000 +#define SLIDER 0x20000000 #define AXIS_NOT_PRESENT -99999 +#define JOYSTICK_TYPE_NONE 8 #define JOYSTICK_PRESENT(n) (joystick_state[n].plat_joystick_nr != 0) @@ -57,6 +59,7 @@ typedef struct { int a[8]; int b[32]; int p[4]; + int s[2]; struct { char name[260]; @@ -73,9 +76,16 @@ typedef struct { int id; } pov[4]; + struct + { + char name[260]; + int id; + } slider[2]; + int nr_axes; int nr_buttons; int nr_povs; + int nr_sliders; } plat_joystick_t; typedef struct { diff --git a/src/game/joystick_standard.c b/src/game/joystick_standard.c index f05634a9b..e207b5173 100644 --- a/src/game/joystick_standard.c +++ b/src/game/joystick_standard.c @@ -144,6 +144,27 @@ static int joystick_standard_read_axis_4button(void *p, int axis) return 0; } } + +static int joystick_standard_read_axis_4axis(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return joystick_state[0].axis[2]; + case 3: + return joystick_state[0].axis[3]; + default: + return 0; + } +} + static int joystick_standard_read_axis_6button(void *p, int axis) { if (!JOYSTICK_PRESENT(0)) @@ -227,6 +248,22 @@ const joystick_if_t joystick_standard_4button = {"X axis", "Y axis"}, {"Button 1", "Button 2", "Button 3", "Button 4"} }; +const joystick_if_t joystick_4axis_4button = +{ + "4-axis 4-button joystick", + joystick_standard_init, + joystick_standard_close, + joystick_standard_read_4button, + joystick_standard_write, + joystick_standard_read_axis_4axis, + joystick_standard_a0_over, + 4, + 4, + 0, + 1, + {"X axis", "Y axis", "Z axis", "zX axis"}, + {"Button 1", "Button 2", "Button 3", "Button 4"} +}; const joystick_if_t joystick_standard_6button = { "Standard 6-button joystick", diff --git a/src/game/joystick_standard.h b/src/game/joystick_standard.h index 26b16998e..4aa593f0d 100644 --- a/src/game/joystick_standard.h +++ b/src/game/joystick_standard.h @@ -37,5 +37,6 @@ extern const joystick_if_t joystick_standard; extern const joystick_if_t joystick_standard_4button; +extern const joystick_if_t joystick_4axis_4button; extern const joystick_if_t joystick_standard_6button; extern const joystick_if_t joystick_standard_8button; diff --git a/src/intel_flash.c b/src/intel_flash.c index 4dd041a48..faddf4ec4 100644 --- a/src/intel_flash.c +++ b/src/intel_flash.c @@ -330,7 +330,10 @@ intel_flash_init(const device_t *info) flash_name = (wchar_t *)malloc(l*sizeof(wchar_t)); swprintf(flash_name, l, L"%ls.bin", machine_name); - wcscpy(flash_path, flash_name); + if (wcslen(flash_name) <= 1024) + wcscpy(flash_path, flash_name); + else + wcsncpy(flash_path, flash_name, 1024); dev->flags = info->local & 0xff; diff --git a/src/intel_sio.c b/src/intel_sio.c index b9e3a07d3..45cdf2975 100644 --- a/src/intel_sio.c +++ b/src/intel_sio.c @@ -123,7 +123,7 @@ sio_write(int func, int addr, uint8_t val, void *priv) if (func > 0) return; - if (addr >= 0x0f && addr < 0x4c) + if (((addr >= 0x0f) && (addr < 0x4c)) && (addr != 0x40)) return; /* The IB (original) variant of the SIO has no PCI IRQ steering. */ diff --git a/src/keyboard_at.c b/src/keyboard_at.c index b001b1815..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.45 2019/11/15 + * Version: @(#)keyboard_at.c 1.0.46 2020/01/11 * * 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. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #include #include @@ -623,7 +623,7 @@ kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - timer_advance_u64(&dev->send_delay_timer, (1000 * TIMER_USEC)); + timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); if ((dev->out_new != -1) && !dev->last_irq) { dev->wantirq = 0; @@ -658,11 +658,11 @@ kbd_poll(void *priv) dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { - dev->out_new = dev->out_delayed; - 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; + 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)) { dev->out_new = mouse_queue[mouse_queue_start] | 0x100; @@ -1931,6 +1931,8 @@ do_command: #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; @@ -2273,6 +2275,7 @@ kbd_reset(void *priv) 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; diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 6a9b56b1c..3ebfee31a 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -2508,7 +2508,7 @@ machine_amstrad_init(const machine_t *model, int type) mouse_set_poll(ms_poll, ams); } - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); } diff --git a/src/machine/m_at.c b/src/machine/m_at.c index 2497ad2f7..ca93a489e 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -8,15 +8,15 @@ * * Standard PC/AT implementation. * - * Version: @(#)m_at.c 1.0.11 2019/11/15 + * Version: @(#)m_at.c 1.0.12 2020/01/13 * * 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. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + * Copyright 2008-2020 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 @@ -59,7 +59,7 @@ void -machine_at_common_init_ex(const machine_t *model, int is_ibm) +machine_at_common_init_ex(const machine_t *model, int type) { machine_common_init(model); @@ -67,12 +67,12 @@ machine_at_common_init_ex(const machine_t *model, int is_ibm) pic2_init(); dma16_init(); - if (is_ibm) + if (type == 1) device_add(&ibmat_nvr_device); - else + else if (type == 0) device_add(&at_nvr_device); - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); } diff --git a/src/machine/m_at_socket7_s7.c b/src/machine/m_at_socket7_s7.c index e97bc5c74..c7ec4cc15 100644 --- a/src/machine/m_at_socket7_s7.c +++ b/src/machine/m_at_socket7_s7.c @@ -12,9 +12,11 @@ * * Authors: Sarah Walker, * Miran Grca, + * Melissa Goad, * - * Copyright 2010-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2010-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2020 Melissa Goad. */ #include #include @@ -35,6 +37,8 @@ #include "../intel_sio.h" #include "../piix.h" #include "../sio.h" +#include "../sst_flash.h" +#include "../via_vt82c586b.h" #include "../video/video.h" #include "../video/vid_cl54xx.h" #include "../video/vid_s3.h" @@ -486,3 +490,32 @@ machine_at_j656vxd_init(const machine_t *model) return ret; } + +int +machine_at_mvp3_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ficva503p/je4333.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_ONBOARD, 1, 2, 3, 4); + 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(0x07, PCI_CARD_SPECIAL, 1, 2, 3, 4); + device_add(&via_mvp3_device); + device_add(&via_vt82c586b_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877tf_device); + device_add(&sst_flash_39sf010_device); + + return ret; +} diff --git a/src/machine/m_at_t3100e.c b/src/machine/m_at_t3100e.c index 8f69fc951..6d25453b6 100644 --- a/src/machine/m_at_t3100e.c +++ b/src/machine/m_at_t3100e.c @@ -571,8 +571,13 @@ uint8_t t3100e_ems_in(uint16_t addr, void *p) { struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; - return regs->page[port_to_page(addr)]; - + int page = port_to_page(addr); + if (page >= 0) + return regs->page[page]; + else { + fatal("t3100e_ems_in(): invalid address"); + return 0xff; + } } /* Write EMS page register */ @@ -581,6 +586,9 @@ void t3100e_ems_out(uint16_t addr, uint8_t val, void *p) struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; int pg = port_to_page(addr); + if (pg == -1) + return; + regs->page_exec[pg & 3] = t3100e_ems_execaddr(regs, pg, val); t3100e_log("EMS: page %d %02x -> %02x [%06x]\n", pg, regs->page[pg], val, regs->page_exec[pg & 3]); diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c index 04e464726..c50fe6364 100644 --- a/src/machine/m_europc.c +++ b/src/machine/m_europc.c @@ -615,7 +615,7 @@ europc_boot(const device_t *info) mouse_bus_set_irq(sys->mouse, 2); /* Configure the port for (Bus Mouse Compatible) Mouse. */ b |= 0x01; - } else if (joystick_type != 7) + } else if (joystick_type != JOYSTICK_TYPE_NONE) b |= 0x02; /* enable port as joysticks */ sys->nvr.regs[MRTC_CONF_C] = b; diff --git a/src/machine/m_olivetti_m24.c b/src/machine/m_olivetti_m24.c index 694fec24c..9bb84198f 100644 --- a/src/machine/m_olivetti_m24.c +++ b/src/machine/m_olivetti_m24.c @@ -892,7 +892,7 @@ machine_olim24_init(const machine_t *model) keyboard_set_table(scancode_xt); - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); /* FIXME: make sure this is correct?? */ diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 2bfd6e7f7..9ff547d45 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -459,12 +459,6 @@ ps1_setup(int model) lpt2_remove(); - /* Enable the PS/1 VGA controller. */ - if (model == 2011) - device_add(&ps1vga_device); - else - device_add(&ibm_ps1_2121_device); - device_add(&snd_device); device_add(&fdc_at_actlow_device); @@ -505,6 +499,12 @@ ps1_setup(int model) device_add(&ide_isa_device); } #endif + + /* Enable the PS/1 VGA controller. */ + if (model == 2011) + device_add(&ps1vga_device); + else + device_add(&ibm_ps1_2121_device); } @@ -525,7 +525,7 @@ ps1_common_init(const machine_t *model) device_add(&keyboard_ps2_ps1_device); /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_201_device); } diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index e4eb3fbd3..bbcf7786c 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -8,7 +8,7 @@ * * Emulation of Tandy models 1000, 1000HX and 1000SL2. * - * Version: @(#)m_tandy.c 1.0.10 2019/10/20 + * Version: @(#)m_tandy.c 1.0.11 2019/12/28 * * Authors: Sarah Walker, * Miran Grca, @@ -74,11 +74,7 @@ typedef struct { int crtcreg; int array_index; -#if 0 - uint8_t array[32]; -#else uint8_t array[256]; -#endif int memctrl; uint8_t mode, col; uint8_t stat; @@ -95,13 +91,13 @@ typedef struct { int con, coff, cursoron, blink; - int vsynctime; + int vsynctime; int vadj; uint16_t ma, maback; uint64_t dispontime, dispofftime; - pc_timer_t timer; + pc_timer_t timer; int firstline, lastline; @@ -857,8 +853,8 @@ vid_poll(void *priv) } } } 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; @@ -872,6 +868,10 @@ vid_poll(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]; @@ -1293,7 +1293,8 @@ eep_init(const device_t *info) f = nvr_fopen(eep->path, L"rb"); if (f != NULL) { - fread(eep->store, 128, 1, f); + if (fread(eep->store, 1, 128, f) != 128) + fatal("eep_init(): Error reading Tandy EEPROM\n"); (void)fclose(f); } @@ -1526,7 +1527,7 @@ machine_tandy1k_init(const machine_t *model, int type) device_add(&eep_1000sl2_device); } - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); eep_data_out = 0x0000; diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 22a01c882..c3bf07897 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -26,7 +26,7 @@ machine_xt_common_init(const machine_t *model) device_add(&fdc_xt_device); nmi_init(); - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); } @@ -157,10 +157,10 @@ machine_xt86_init(const machine_t *model) 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); + (void) bios_load_aux_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", + 0x000f8000, 24576, 0); + (void) bios_load_aux_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U19_62X0819_68X4370_27256_F000.BIN", + 0x000f0000, 32768, 0); } if (bios_only || !ret) diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c index 6af9079fa..1e312fe10 100644 --- a/src/machine/m_xt_compaq.c +++ b/src/machine/m_xt_compaq.c @@ -55,7 +55,7 @@ machine_xt_compaq_init(const machine_t *model) device_add(&keyboard_xt_compaq_device); device_add(&fdc_xt_device); nmi_init(); - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); lpt1_remove(); diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index 0b06a238b..f8408952e 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -171,7 +171,7 @@ machine_xt_lxt3_init(const machine_t *model) device_add(&keyboard_xt_lxt3_device); device_add(&fdc_xt_device); nmi_init(); - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); laserxt_init(1); diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index 3471b0c12..ee9bb8cd0 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -240,6 +240,7 @@ tc8521_time_get(uint8_t *regs, struct tm *tm) tm->tm_hour = ((nibbles(TC8521_HOUR) % 12) + (regs[TC8521_HOUR10] & 0x02) ? 12 : 0); //FIXME: wday + tm->tm_wday = 1; /* Dummy value so it is not uninitialized. */ tm->tm_mday = nibbles(TC8521_DAY); tm->tm_mon = (nibbles(TC8521_MONTH) - 1); tm->tm_year = (nibbles(TC8521_YEAR) + 1980); @@ -881,7 +882,8 @@ machine_xt_t1000_init(const machine_t *model) t1000.romdrive = malloc(T1000_ROMSIZE); if (t1000.romdrive) { memset(t1000.romdrive, 0xff, T1000_ROMSIZE); - fread(t1000.romdrive, T1000_ROMSIZE, 1, f); + if (fread(t1000.romdrive, 1, T1000_ROMSIZE, f) != T1000_ROMSIZE) + fatal("machine_xt_t1000_init(): Error reading DOS ROM data\n"); } fclose(f); } @@ -1015,11 +1017,14 @@ static void t1000_configsys_load(void) { FILE *f; + int size; memset(t1000.t1000_nvram, 0x1a, sizeof(t1000.t1000_nvram)); f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"rb"); if (f != NULL) { - fread(t1000.t1000_nvram, sizeof(t1000.t1000_nvram), 1, f); + size = sizeof(t1000.t1000_nvram); + if (fread(t1000.t1000_nvram, size, 1, f) != size) + fatal("t1000_configsys_load(): Error reading data\n"); fclose(f); } } @@ -1029,10 +1034,13 @@ static void t1000_configsys_save(void) { FILE *f; + int size; f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"wb"); if (f != NULL) { - fwrite(t1000.t1000_nvram, sizeof(t1000.t1000_nvram), 1, f); + size = sizeof(t1000.t1000_nvram); + if (fwrite(t1000.t1000_nvram, 1, size, f) != size) + fatal("t1000_configsys_save(): Error writing data\n"); fclose(f); } } @@ -1042,11 +1050,14 @@ static void t1200_state_load(void) { FILE *f; + int size; 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); + size = sizeof(t1000.t1200_nvram); + if (fread(t1000.t1200_nvram, 1, size, f) != size) + fatal("t1200_state_load(): Error reading data\n"); fclose(f); } } @@ -1056,10 +1067,13 @@ static void t1200_state_save(void) { FILE *f; + int size; f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"wb"); if (f != NULL) { - fwrite(t1000.t1200_nvram, sizeof(t1000.t1200_nvram), 1, f); + size = sizeof(t1000.t1200_nvram); + if (fwrite(t1000.t1200_nvram, 1, size, f) != size) + fatal("t1200_state_save(): Error writing data\n"); fclose(f); } } diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index 101e8a0ae..bd832e96c 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -175,7 +175,7 @@ machine_xt_xi8088_init(const machine_t *model) nmi_init(); device_add(&ibmat_nvr_device); pic2_init(); - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); return ret; diff --git a/src/machine/machine.h b/src/machine/machine.h index b04d997e9..bd0561a98 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -8,15 +8,15 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.h 1.0.34 2019/03/08 + * Version: @(#)machine.h 1.0.35 2020/01/13 * * 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. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #ifndef EMU_MACHINE_H # define EMU_MACHINE_H @@ -151,7 +151,7 @@ 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_ex(const machine_t *, int type); 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 *); @@ -282,6 +282,8 @@ 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 *); +extern int machine_at_mvp3_init(const machine_t *); + #ifdef EMU_DEVICE_H extern const device_t *at_pb640_get_device(void); #endif diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 791efd86e..7668af65a 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.50 2019/11/19 + * Version: @(#)machine_table.c 1.0.51 2020/01/14 * * 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. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #include #include @@ -133,11 +133,13 @@ const machine_t machines[] = { { "[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 ISA] Goldstar 386", "goldstar386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_goldstar386_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] 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] 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 }, @@ -149,13 +151,13 @@ const machine_t machines[] = { { "[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 }, + { "[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 @@ -211,6 +213,8 @@ const machine_t machines[] = { { "[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 }, + { "[Super Socket 7] FIC VA503P", "ficva503p", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_mvp3_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 }, diff --git a/src/machine/machine_table_new.c b/src/machine/machine_table_new.c index 60405cbbd..b630da425 100644 --- a/src/machine/machine_table_new.c +++ b/src/machine/machine_table_new.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.50 2019/11/19 + * Version: @(#)machine_table.c 1.0.51 2020/01/14 * * 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. + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #include #include @@ -33,9 +33,10 @@ #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}} +#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}} +#define MACHINE_CPUS_PENTIUM_SS7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip_SS7}, {"AMD", cpus_K56_SS7}, {"Cyrix", cpus_6x86SS7}, {"", 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 }, @@ -117,7 +118,9 @@ const machine_t machines[] = { { "[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 ISA] Goldstar 386", "goldstar386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_goldstar386_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 }, @@ -195,6 +198,8 @@ const machine_t machines[] = { { "[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 }, + { "[Super Socket 7] FIC VA503P", "ficva503p", MACHINE_CPUS_PENTIUM_SS7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_mvp3_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 }, diff --git a/src/mem.c b/src/mem.c index 4610e7ee2..0741e18d5 100644 --- a/src/mem.c +++ b/src/mem.c @@ -512,7 +512,8 @@ writemembl(uint32_t addr, uint8_t val) mem_mapping_t *map; mem_logical_addr = addr; - if (page_lookup[addr>>12]) { + if (page_lookup[addr>>12]) + { page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); return; @@ -893,6 +894,25 @@ mem_readw_phys(uint32_t 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) @@ -905,6 +925,23 @@ mem_writeb_phys(uint32_t addr, uint8_t val) 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) @@ -1533,7 +1570,8 @@ 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 < pages_sz; c++) { pages[c].mem = &ram[c << 12]; diff --git a/src/mem.h b/src/mem.h index 64d851b30..6b5641ee6 100644 --- a/src/mem.h +++ b/src/mem.h @@ -265,7 +265,9 @@ extern void mem_set_mem_state(uint32_t base, uint32_t size, int state); extern uint8_t mem_readb_phys(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_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); diff --git a/src/mem_new.c b/src/mem_new.c index 199c7cd20..84f3aa597 100644 --- a/src/mem_new.c +++ b/src/mem_new.c @@ -870,6 +870,26 @@ mem_readw_phys(uint32_t 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) @@ -882,6 +902,23 @@ mem_writeb_phys(uint32_t addr, uint8_t val) 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) @@ -1574,7 +1611,8 @@ 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)); + if (byte_dirty_mask) { free(byte_dirty_mask); @@ -1650,6 +1688,9 @@ mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); mem_mapping_disable(&ram_remapped_mapping); mem_a20_init(); + + purgable_page_list_head = 0; + purgeable_page_count = 0; } diff --git a/src/mouse_serial.c b/src/mouse_serial.c index c96a7598d..b306e1252 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -623,6 +623,7 @@ ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) switch (data) { default: mouse_serial_log("Serial mouse: Invalid period %02X, using 1200 bps\n", data); + /*FALLTHROUGH*/ case 0x6E: dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); break; diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index 5acc9c170..771b55e8e 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -260,10 +260,16 @@ net_pcap_prepare(netdev_t *list) } for (dev=devlist; dev!=NULL; dev=dev->next) { - strcpy(list->device, dev->name); - if (dev->description) - strcpy(list->description, dev->description); - else + if (strlen(dev->name) <= 127) + strcpy(list->device, dev->name); + else + strncpy(list->device, dev->name, 127); + if (dev->description) { + if (strlen(dev->description) <= 127) + strcpy(list->description, dev->description); + else + strncpy(list->description, dev->description, 127); + } else memset(list->description, '\0', sizeof(list->description)); list++; i++; } diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index fa5cab9d6..49de94317 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -907,6 +907,24 @@ pcnetInit(nic_t *dev) dev->GCTDRA = PHYSADDR(dev, initblk.tdra); \ } while (0) +#define PCNET_INIT16() do { \ + DMAPageRead(PHYSADDR(dev, CSR_IADR(dev)), \ + (uint8_t *)&initblk, sizeof(initblk)); \ + dev->aCSR[15] = le32_to_cpu(initblk.mode); \ + CSR_RCVRL(dev) = (1 << initblk.rlen); \ + CSR_XMTRL(dev) = (1 << initblk.tlen); \ + 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; @@ -916,7 +934,7 @@ pcnetInit(nic_t *dev) } else { struct INITBLK16 initblk; dev->GCUpperPhys = (0xff00 & (uint32_t)dev->aCSR[2]) << 16; - PCNET_INIT(); + PCNET_INIT16(); pcnetlog(3, "%s: initblk.rlen=%#04x, initblk.tlen=%#04x\n", dev->name, initblk.rlen, initblk.tlen); } @@ -1263,22 +1281,18 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) /* 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; - uint32_t fcs = UINT32_MAX; - uint8_t *p = src; + while (p != &src[size]) + CRC(fcs, *p++); - while (p != &src[size]) - CRC(fcs, *p++); + /* FCS at the end of the packet */ + ((uint32_t *)&src[size])[0] = htonl(fcs); + size += 4; + } - /* FCS at the end of the packet */ - ((uint32_t *)&src[size])[0] = htonl(fcs); - size += 4; - } - - cbPacket = size; + cbPacket = size; pcnetRmdLoad(dev, &rmd, PHYSADDR(dev, crda), 0); /* if (!CSR_LAPPEN(dev)) */ diff --git a/src/nvr.c b/src/nvr.c index 53376295f..bb72ebf2d 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -264,7 +264,8 @@ nvr_load(void) fp = plat_fopen(path, L"rb"); if (fp != NULL) { /* Read NVR contents from file. */ - (void)fread(saved_nvr->regs, saved_nvr->size, 1, fp); + if (fread(saved_nvr->regs, 1, saved_nvr->size, fp) != saved_nvr->size) + fatal("nvr_load(): Error reading data\n"); (void)fclose(fp); } } diff --git a/src/nvr.h b/src/nvr.h index f315b7a51..7929ce642 100644 --- a/src/nvr.h +++ b/src/nvr.h @@ -8,13 +8,13 @@ * * Definitions for the generic NVRAM/CMOS driver. * - * Version: @(#)nvr.h 1.0.11 2019/03/16 + * Version: @(#)nvr.h 1.0.12 2020/01/13 * * Author: Fred N. van Kempen, , * David HrdliÄka, * - * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2018,2019 David HrdliÄka. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2018-2020 David HrdliÄka. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -91,6 +91,7 @@ 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; +extern const device_t via_nvr_device; #endif @@ -109,5 +110,7 @@ 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_at_handler(int set, uint16_t base, nvr_t *nvr); + #endif /*EMU_NVR_H*/ diff --git a/src/nvr_at.c b/src/nvr_at.c index 967f14018..d4b1cfde1 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.16 2019/11/19 + * Version: @(#)nvr_at.c 1.0.17 2020/01/13 * * Authors: Fred N. van Kempen, * Miran Grca, * Mahod, * Sarah Walker, * - * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2019 Miran Grca. - * Copyright 2008-2019 Sarah Walker. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + * Copyright 2008-2020 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 @@ -281,6 +281,9 @@ # define REGD_VRT 0x80 #define RTC_CENTURY_AT 0x32 /* century register for AT etc */ #define RTC_CENTURY_PS 0x37 /* century register for PS/1 PS/2 */ +#define RTC_ALDAY 0x7D /* VIA VT82C586B - alarm day */ +#define RTC_ALMONTH 0x7E /* VIA VT82C586B - alarm month */ +#define RTC_CENTURY_VIA 0x7F /* century register for VIA VT82C586B */ #define RTC_REGS 14 /* number of registers */ @@ -290,7 +293,7 @@ typedef struct { uint8_t cent; uint8_t def; - uint8_t addr; + uint8_t addr[8]; int16_t count, state; @@ -402,6 +405,20 @@ check_alarm(nvr_t *nvr, int8_t addr) } +/* Check for VIA stuff. */ +static int8_t +check_alarm_via(nvr_t *nvr, int8_t addr, int8_t addr_2) +{ + local_t *local = (local_t *)nvr->data; + + if (local->cent == RTC_CENTURY_VIA) { + return((nvr->regs[addr_2] == nvr->regs[addr]) || + ((nvr->regs[addr_2] & AL_DONTCARE) == AL_DONTCARE)); + } else + return 0; +} + + /* Update the NVR registers from the internal clock. */ static void timer_update(void *priv) @@ -425,7 +442,9 @@ timer_update(void *priv) /* Check for any alarms we need to handle. */ if (check_alarm(nvr, RTC_SECONDS) && check_alarm(nvr, RTC_MINUTES) && - check_alarm(nvr, RTC_HOURS)) { + check_alarm(nvr, RTC_HOURS) && + check_alarm_via(nvr, RTC_DOM, RTC_ALDAY) && + check_alarm_via(nvr, RTC_MONTH, RTC_ALMONTH)) { nvr->regs[RTC_REGC] |= REGC_AF; if (nvr->regs[RTC_REGB] & REGB_AIE) { nvr->regs[RTC_REGC] |= REGC_IRQF; @@ -535,12 +554,13 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) local_t *local = (local_t *)nvr->data; struct tm tm; uint8_t old; + uint8_t addr_id = (addr & 0x0e) >> 1; sub_cycles(ISA_CYCLES(8)); if (addr & 1) { - old = nvr->regs[local->addr]; - switch(local->addr) { + old = nvr->regs[local->addr[addr_id]]; + switch(local->addr[addr_id]) { case RTC_REGA: nvr->regs[RTC_REGA] = val; timer_load_count(nvr); @@ -560,15 +580,15 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) break; default: /* non-RTC registers are just NVRAM */ - if (nvr->regs[local->addr] != val) { - nvr->regs[local->addr] = val; + if (nvr->regs[local->addr[addr_id]] != val) { + nvr->regs[local->addr[addr_id]] = val; nvr_dosave = 1; } break; } - if ((local->addr < RTC_REGA) || ((local->cent != 0xff) && (local->addr == local->cent))) { - if ((local->addr != 1) && (local->addr != 3) && (local->addr != 5)) { + if ((local->addr[addr_id] < RTC_REGA) || ((local->cent != 0xff) && (local->addr[addr_id] == local->cent))) { + if ((local->addr[addr_id] != 1) && (local->addr[addr_id] != 3) && (local->addr[addr_id] != 5)) { if ((old != val) && !(time_sync & TIME_SYNC_ENABLED)) { /* Update internal clock. */ time_get(nvr, &tm); @@ -578,7 +598,10 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) } } } else { - local->addr = (val & (nvr->size - 1)); + local->addr[addr_id] = (val & (nvr->size - 1)); + /* Some chipsets use a 256 byte NVRAM but ports 70h and 71h always access only 128 bytes. */ + if (addr_id == 0x0) + local->addr[addr_id] &= 0x7f; if (!(machines[machine].flags & MACHINE_MCA) && !(machines[machine].flags & MACHINE_NONMI)) nmi_mask = (~val & 0x80); @@ -593,10 +616,11 @@ nvr_read(uint16_t addr, void *priv) nvr_t *nvr = (nvr_t *)priv; local_t *local = (local_t *)nvr->data; uint8_t ret; + uint8_t addr_id = (addr & 0x0e) >> 1; sub_cycles(ISA_CYCLES(8)); - if (addr & 1) switch(local->addr) { + if (addr & 1) switch(local->addr[addr_id]) { case RTC_REGA: ret = (nvr->regs[RTC_REGA] & 0x7f) | local->stat; break; @@ -613,10 +637,10 @@ nvr_read(uint16_t addr, void *priv) break; default: - ret = nvr->regs[local->addr]; + ret = nvr->regs[local->addr[addr_id]]; break; } else - ret = local->addr; + ret = local->addr[addr_id]; return(ret); } @@ -692,6 +716,14 @@ nvr_at_speed_changed(void *priv) } +void +nvr_at_handler(int set, uint16_t base, nvr_t *nvr) +{ + io_handler(set, base, 2, + nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); +} + + static void * nvr_at_init(const device_t *info) { @@ -710,7 +742,7 @@ nvr_at_init(const device_t *info) /* This is machine specific. */ nvr->size = machines[machine].nvrmask + 1; local->def = 0x00; - switch(info->local) { + switch(info->local & 7) { case 0: /* standard AT, no century register */ nvr->irq = 8; local->cent = 0xff; @@ -738,6 +770,10 @@ nvr_at_init(const device_t *info) local->def = 0xff; break; + case 5: /* VIA VT82C586B */ + nvr->irq = 8; + local->cent = RTC_CENTURY_VIA; + break; } /* Set up any local handlers here. */ @@ -758,6 +794,10 @@ nvr_at_init(const device_t *info) /* Set up the I/O handler for this device. */ io_sethandler(0x0070, 2, nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); + if (info->local & 8) { + io_sethandler(0x0072, 2, + nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); + } return(nvr); } @@ -829,3 +869,13 @@ const device_t ibmat_nvr_device = { NULL, nvr_at_speed_changed, NULL }; + +const device_t via_nvr_device = { + "VIA PC/AT NVRAM", + DEVICE_ISA | DEVICE_AT, + 9, + 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 5c943a0eb..483d67529 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -128,7 +128,8 @@ ps2_nvr_init(const device_t *info) memset(nvr->ram, 0xff, 8192); if (f != NULL) { - (void)fread(nvr->ram, 8192, 1, f); + if (fread(nvr->ram, 1, 8192, f) != 8192) + fatal("ps2_nvr_init(): Error reading EEPROM data\n"); fclose(f); } @@ -149,8 +150,6 @@ ps2_nvr_close(void *priv) fclose(f); } - free(nvr->ram); - free(nvr); } diff --git a/src/pc.c b/src/pc.c index 9f0bcc926..c1218ac7a 100644 --- a/src/pc.c +++ b/src/pc.c @@ -149,7 +149,7 @@ int output; int atfullspeed; int clockrate; -wchar_t exe_path[1024]; /* path (dir) of executable */ +wchar_t exe_path[2048]; /* path (dir) of executable */ wchar_t usr_path[1024]; /* path (dir) of user data */ wchar_t cfg_path[1024]; /* full path of config file */ FILE *stdlog = NULL; /* file to log output to */ @@ -323,7 +323,7 @@ pc_init(int argc, wchar_t *argv[]) uint32_t *uid, *shwnd; /* Grab the executable's full path. */ - plat_get_exe_name(exe_path, sizeof(exe_path)-1); + plat_get_exe_name(exe_path, sizeof_w(exe_path)-1); p = plat_get_filename(exe_path); *p = L'\0'; @@ -554,8 +554,8 @@ pc_init_modules(void) /* Load the ROMs for the selected machine. */ if (! machine_available(machine)) { c = 0; + machine = -1; while (machine_get_internal_name_ex(c) != NULL) { - machine = -1; if (machine_available(c)) { ui_msgbox(MBX_INFO, (wchar_t *)IDS_2063); machine = c; @@ -767,7 +767,7 @@ pc_reset_hard_init(void) /* Reset and reconfigure the Network Card layer. */ network_reset(); - if (joystick_type != 7) + if (joystick_type != JOYSTICK_TYPE_NONE) gameport_update_joystick_type(); ui_sb_update_panes(); diff --git a/src/pci.c b/src/pci.c index 05519cc2e..082361c36 100644 --- a/src/pci.c +++ b/src/pci.c @@ -8,15 +8,15 @@ * * Implementation the PCI bus. * - * Version: @(#)pci.c 1.0.4 2019/11/06 + * Version: @(#)pci.c 1.0.6 2020/01/11 * * Authors: Miran Grca, * Fred N. van Kempen, * Sarah Walker, * - * Copyright 2016-2019 Miran Grca. - * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2008-2020 Sarah Walker. */ #include #include @@ -58,7 +58,7 @@ 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]; +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, @@ -68,7 +68,7 @@ static int pci_type, pci_bus, pci_enable, pci_key; -static int trc_reg = 0; +static int trc_reg = 0, elcr_enabled = 1; #ifdef ENABLE_PCI_LOG @@ -278,6 +278,13 @@ pci_set_irq_routing(int pci_int, int irq) } +void +pci_set_irq_level(int pci_int, int level) +{ + pci_irq_level[pci_int - 1] = !!level; +} + + void pci_enable_mirq(int mirq) { @@ -297,13 +304,20 @@ pci_irq_is_level(int irq) { int real_irq = irq & 7; - if ((irq <= 2) || (irq == 8) || (irq == 13)) - return 0; + if (elcr_enabled) { + if ((irq <= 2) || (irq == 8) || (irq == 13)) + return 0; - if (irq > 7) - return !!(elcr[1] & (1 << real_irq)); + if (irq > 7) + return !!(elcr[1] & (1 << real_irq)); - return !!(elcr[0] & (1 << real_irq)); + return !!(elcr[0] & (1 << real_irq)); + } else { + if (irq < 8) + return (pic.icw1 & 8) ? 1 : 0; + else + return (pic2.icw1 & 8) ? 1 : 0; + } } @@ -401,6 +415,7 @@ pci_set_irq(uint8_t card, uint8_t pci_int) pci_log("pci_set_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); irq_line = pci_irqs[irq_routing]; + level = pci_irq_level[irq_routing]; } if (irq_line > 0x0f) { @@ -416,10 +431,6 @@ pci_set_irq(uint8_t card, uint8_t pci_int) } pci_log("pci_set_irq(%02X, %02X): Card not yet holding the IRQ\n", card, pci_int); - if (pci_type & PCI_NO_IRQ_STEERING) - level = 0; /* PCI without IRQ steering - IRQ always edge. */ - else - level = 1; /* PCI with IRQ steering - IRQ always level per the Intel datasheets. */ 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 "); @@ -433,7 +444,7 @@ pci_set_irq(uint8_t card, uint8_t pci_int) } /* If the IRQ is level-triggered, mark that this card is holding it. */ - if (pci_irq_is_level(irq_line)) { + 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 { @@ -522,6 +533,7 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) pci_log("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); irq_line = pci_irqs[irq_routing]; + level = pci_irq_level[irq_routing]; } if (irq_line > 0x0f) { @@ -531,17 +543,12 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) pci_log("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - if (pci_irq_is_level(irq_line) && - !(pci_irq_hold[irq_line] & (1ULL << 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_type & PCI_NO_IRQ_STEERING) - level = 0; /* PCI without IRQ steering - IRQ always edge. */ - else - level = 1; /* PCI with IRQ steering - IRQ always level per the Intel datasheets. */ 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); @@ -559,6 +566,13 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) } +void +pci_elcr_set_enabled(int enabled) +{ + elcr_enabled = enabled; +} + + void pci_reset(void) { @@ -635,7 +649,10 @@ trc_write(uint16_t port, uint8_t val, void *priv) if (!(trc_reg & 4) && (val & 4)) trc_reset(val); - trc_reg = val & 0xfb; + trc_reg = val & 0xfd; + + if (val & 2) + trc_reg &= 0xfb; } @@ -681,13 +698,17 @@ pci_init(int type) pci_type2_read,NULL,NULL, pci_type2_write,NULL,NULL, NULL); } - for (c = 0; c < 4; c++) + 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; } diff --git a/src/pci.h b/src/pci.h index be7347757..18a93d9fb 100644 --- a/src/pci.h +++ b/src/pci.h @@ -8,15 +8,15 @@ * * Definitions for the PCI handler module. * - * Version: @(#)pci.h 1.0.1 2019/10/30 + * Version: @(#)pci.h 1.0.2 2020/01/11 * * Authors: Miran Grca, * Fred N. van Kempen, * Sarah Walker, * - * Copyright 2016-2019 Miran Grca. - * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2008-2019 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 @@ -68,6 +68,7 @@ extern int pci_burst_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); @@ -89,6 +90,7 @@ 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 60297734c..4ed1d4315 100644 --- a/src/pic.c +++ b/src/pic.c @@ -8,11 +8,11 @@ * * Implementation of the Intel PIC chip emulation. * - * Version: @(#)pic.c 1.0.5 2019/09/20 + * Version: @(#)pic.c 1.0.6 2020/01/17 * * Author: Miran Grca, * - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2020 Miran Grca. */ #include #include @@ -30,12 +30,15 @@ #include "pit.h" -int output; -int intclear; -int keywaiting=0; -int pic_intpending; -PIC pic, pic2; -uint16_t pic_current; +int output; +int intclear; +int keywaiting = 0; +int pic_intpending; +PIC pic, pic2; +uint16_t pic_current; + + +static int shadow = 0; #ifdef ENABLE_PIC_LOG @@ -98,6 +101,13 @@ pic_reset() } +void +pic_set_shadow(int sh) +{ + shadow = sh; +} + + void pic_update_mask(uint8_t *mask, uint8_t ins) { @@ -198,6 +208,7 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic_updatepending(); } else if (!(val & 8)) { /*OCW2*/ + pic.ocw2 = val; if ((val & 0xE0) == 0x60) { pic.ins &= ~(1 << (val & 7)); pic_update_mask(&pic.mask2, pic.ins); @@ -226,6 +237,7 @@ pic_write(uint16_t addr, uint8_t val, void *priv) } } } else { /*OCW3*/ + pic.ocw3 = val; if (val & 2) pic.read=(val & 1); } @@ -236,27 +248,36 @@ pic_write(uint16_t addr, uint8_t val, void *priv) uint8_t pic_read(uint16_t addr, void *priv) { - addr &= ~0x06; + uint8_t ret = 0xff; - 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); + if ((addr == 0x20) && shadow) { + ret = ((pic.ocw3 & 0x20) >> 5) << 4; + ret |= ((pic.ocw2 & 0x80) >> 7) << 3; + ret |= ((pic.icw4 & 0x10) >> 4) << 2; + ret |= ((pic.icw4 & 0x02) >> 1) << 1; + ret |= ((pic.icw4 & 0x08) >> 3) << 0; + } else if ((addr == 0x21) && shadow) + ret = ((pic.vector & 0xf8) >> 3) << 0; + else if (addr & 1) + ret = pic.mask; + else if (pic.read) { if (AT) - return pic.ins | (pic2.ins ? 4 : 0); + ret = pic.ins | (pic2.ins ? 4 : 0); else - return pic.ins; - } - return pic.pend; + ret = pic.ins; + } else + ret = pic.pend; + + pic_log("%04X:%04X: Read PIC 1 port %04X, value %02X\n", CS, cpu_state.pc, addr, val); + + return ret; } void pic_init() { + shadow = 0; io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, NULL); } @@ -264,6 +285,7 @@ pic_init() void pic_init_pcjr() { + shadow = 0; io_sethandler(0x0020, 0x0008, pic_read, NULL, NULL, pic_write, NULL, NULL, NULL); } @@ -323,6 +345,7 @@ pic2_write(uint16_t addr, uint8_t val, void *priv) pic.pend &= ~4; pic_updatepending(); } else if (!(val & 8)) { /*OCW2*/ + pic2.ocw2 = val; if ((val & 0xE0) == 0x60) { pic2.ins &= ~(1 << (val & 7)); pic_update_mask(&pic2.mask2, pic2.ins); @@ -339,6 +362,7 @@ pic2_write(uint16_t addr, uint8_t val, void *priv) } } } else { /*OCW3*/ + pic2.ocw3 = val; if (val & 2) pic2.read=(val & 1); } @@ -349,16 +373,26 @@ pic2_write(uint16_t addr, uint8_t val, void *priv) uint8_t pic2_read(uint16_t addr, void *priv) { - if (addr&1) { - pic_log("Read PIC2 mask %02X\n", pic2.mask); - return pic2.mask; - } - if (pic2.read) { - pic_log("Read PIC2 ins %02X\n", pic2.ins); - return pic2.ins; - } - pic_log("Read PIC2 pend %02X\n", pic2.pend); - return pic2.pend; + uint8_t ret = 0xff; + + if ((addr == 0x20) && shadow) { + ret = ((pic2.ocw3 & 0x20) >> 5) << 4; + ret |= ((pic2.ocw2 & 0x80) >> 7) << 3; + ret |= ((pic2.icw4 & 0x10) >> 4) << 2; + ret |= ((pic2.icw4 & 0x02) >> 1) << 1; + ret |= ((pic2.icw4 & 0x08) >> 3) << 0; + } else if ((addr == 0x21) && shadow) + ret = ((pic2.vector & 0xf8) >> 3) << 0; + else if (addr & 1) + ret = pic2.mask; + else if (pic.read) + ret = pic2.ins; + else + ret = pic2.pend; + + pic_log("%04X:%04X: Read PIC 2 port %04X, value %02X\n", CS, cpu_state.pc, addr, val); + + return ret; } diff --git a/src/pic.h b/src/pic.h index c164a0aa9..10684958a 100644 --- a/src/pic.h +++ b/src/pic.h @@ -3,10 +3,8 @@ typedef struct PIC { - uint8_t icw1,icw3,icw4,mask,ins,pend,mask2; - int icw; - uint8_t vector; - int read; + uint8_t icw1, icw3, icw4, mask, ins, pend, mask2, vector, ocw2, ocw3; + int icw, read; } PIC; @@ -14,6 +12,7 @@ extern PIC pic, pic2; extern int pic_intpending; +extern void pic_set_shadow(int sh); extern void pic_init(void); extern void pic_init_pcjr(void); extern void pic2_init(void); diff --git a/src/pit.c b/src/pit.c index 3fe4fb1dd..eaab7a4e3 100644 --- a/src/pit.c +++ b/src/pit.c @@ -57,8 +57,9 @@ int io_delay = 5; int64_t firsttime = 1; -#define PIT_PS2 16 -#define PIT_EXT_IO 32 +#define PIT_PS2 16 /* The PIT is the PS/2's second PIT. */ +#define PIT_EXT_IO 32 /* The PIT has externally specified port I/O. */ +#define PIT_CUSTOM_CLOCK 64 /* The PIT uses custom clock inputs provided by another provider. */ enum { @@ -99,6 +100,55 @@ ctr_set_out(ctr_t *ctr, int out) } +static void +ctr_decrease_count(ctr_t *ctr) +{ + uint8_t units, tens, hundreds, thousands, myriads; + int dec_cnt = 1; + + if (ctr->ctrl & 0x01) { + units = ctr->count & 0x0f; + tens = (ctr->count >> 4) & 0x0f; + hundreds = (ctr->count >> 8) & 0x0f; + thousands = (ctr->count >> 12) & 0x0f; + myriads = (ctr->count >> 16) & 0x0f; + + dec_cnt -= units; + units = (10 - dec_cnt % 10) % 10; + + dec_cnt = (dec_cnt + 9) / 10; /* The +9 is so we get a carry if dec_cnt % 10 was not a 0. */ + if (dec_cnt <= tens) + tens -= dec_cnt; + else { + dec_cnt -= tens; + tens = (10 - dec_cnt % 10) % 10; + + dec_cnt = (dec_cnt + 9) / 10; + if (dec_cnt <= hundreds) + hundreds -= dec_cnt; + else { + dec_cnt -= hundreds; + hundreds = (10 - dec_cnt % 10) % 10; + + dec_cnt = (dec_cnt + 9) / 10; + if (dec_cnt <= thousands) + thousands -= dec_cnt; + else { + dec_cnt -= thousands; + thousands = (10 - dec_cnt % 10) % 10; + + dec_cnt = (dec_cnt + 9) / 10; + myriads = (10 + myriads - dec_cnt % 10) % 10; + } + } + } + + ctr->count = (myriads << 16) | (thousands << 12) | (hundreds << 8) | (tens << 4) | units; + } else + ctr->count = (ctr->count - 1) & 0xffff; +} + + static void ctr_load_count(ctr_t *ctr) { @@ -124,7 +174,7 @@ ctr_tick(ctr_t *ctr) break; case 2: if (ctr->gate && (ctr->count >= 1)) { - ctr->count--; + ctr_decrease_count(ctr); if (ctr->count < 1) { ctr->state = 3; ctr_set_out(ctr, 1); @@ -132,7 +182,7 @@ ctr_tick(ctr_t *ctr) } break; case 3: - ctr->count = (ctr->count - 1) & 0xffff; + ctr_decrease_count(ctr); break; } break; @@ -146,7 +196,7 @@ ctr_tick(ctr_t *ctr) break; case 2: if (ctr->count >= 1) { - ctr->count--; + ctr_decrease_count(ctr); if (ctr->count < 1) { ctr->state = 3; ctr_set_out(ctr, 1); @@ -154,7 +204,7 @@ ctr_tick(ctr_t *ctr) } break; case 3: - ctr->count = (ctr->count - 1) & 0xffff; + ctr_decrease_count(ctr); break; } break; @@ -171,7 +221,7 @@ ctr_tick(ctr_t *ctr) if (ctr->gate == 0) break; else if (ctr->count >= 2) { - ctr->count--; + ctr_decrease_count(ctr); if (ctr->count < 2) { ctr->state = 3; ctr_set_out(ctr, 0); @@ -221,7 +271,7 @@ ctr_tick(ctr_t *ctr) if ((ctr->gate != 0) || (ctr->m != 4)) { switch(ctr->state) { case 0: - ctr->count--; + ctr_decrease_count(ctr); break; case 1: ctr_load_count(ctr); @@ -229,7 +279,7 @@ ctr_tick(ctr_t *ctr) break; case 2: if (ctr->count >= 1) { - ctr->count--; + ctr_decrease_count(ctr); if (ctr->count < 1) { ctr->state = 3; ctr_set_out(ctr, 0); @@ -406,6 +456,38 @@ pit_ctr_set_gate(ctr_t *ctr, int gate) } +void +pit_ctr_set_clock(ctr_t *ctr, int clock) +{ + int old = ctr->clock; + + ctr->clock = clock; + + if (ctr->using_timer && ctr->latch) { + if (old && !ctr->clock) { + ctr_set_state_1(ctr); + ctr->latch = 0; + } + } else if (ctr->using_timer && !ctr->latch) { + if (ctr->state == 1) { + if (!old && ctr->clock) + ctr->s1_det = 1; /* Rising edge. */ + else if (old && !ctr->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 && !ctr->clock) + ctr_tick(ctr); + } +} + + void pit_ctr_set_using_timer(ctr_t *ctr, int using_timer) { @@ -420,38 +502,11 @@ 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); - } - } + for (i = 0; i < 3; i++) + pit_ctr_set_clock(&dev->counters[i], dev->clock); timer_advance_u64(&dev->callback_timer, PITCONST >> 1ULL); } @@ -780,7 +835,7 @@ pit_init(const device_t *info) pit_t *dev = (pit_t *) malloc(sizeof(pit_t)); pit_reset(dev); - if (!(dev->flags & PIT_PS2)) { + if (!(dev->flags & PIT_PS2) && !(dev->flags & PIT_CUSTOM_CLOCK)) { timer_add(&dev->callback_timer, pit_timer_over, (void *) dev, 0); timer_set_delay_u64(&dev->callback_timer, PITCONST >> 1ULL); } diff --git a/src/pit.h b/src/pit.h index e0a4a42ff..f019327a6 100644 --- a/src/pit.h +++ b/src/pit.h @@ -9,10 +9,10 @@ * Header of the implementation of the Intel 8253/8254 * Programmable Interval Timer. * - * Version: @(#)pit.h 1.0.0 2019/12/02 + * Version: @(#)pit.h 1.0.1 2020/01/17 * * Author: Miran Grca, - * Copyright 2019 Miran Grca. + * Copyright 2019,2020 Miran Grca. */ #ifndef EMU_PIT_H # define EMU_PIT_H @@ -27,7 +27,7 @@ typedef struct { int rm, wm, gate, out, newcount, count, using_timer, latched, - state, null_count, do_read_status, pad1; + state, null_count, do_read_status, clock; uint32_t l; @@ -60,10 +60,17 @@ extern uint64_t PITCONST, ISACONST, RTCCONST; +/* Gets a counter's count. */ extern uint16_t pit_ctr_get_count(ctr_t *ctr); +/* Sets a counter's load count handler. */ extern void pit_ctr_set_load_func(ctr_t *ctr, void (*func)(uint8_t new_m, int new_count)); +/* Sets a counter's OUT output handler. */ extern void pit_ctr_set_out_func(ctr_t *ctr, void (*func)(int new_out, int old_out)); +/* Sets a counter's GATE input. */ extern void pit_ctr_set_gate(ctr_t *ctr, int gate); +/* Sets a counter's CLOCK input. */ +extern void pit_ctr_set_clock(ctr_t *ctr, int clock); +/* Sets if a counter's CLOCK input is from the timer or not - used by PCjr. */ extern void pit_ctr_set_using_timer(ctr_t *ctr, int using_timer); extern pit_t * pit_common_init(int type, void (*out0)(int new_out, int old_out), void (*out1)(int new_out, int old_out)); diff --git a/src/plat.h b/src/plat.h index 065d50aa0..ec5391bae 100644 --- a/src/plat.h +++ b/src/plat.h @@ -58,7 +58,7 @@ GLOBAL int dopause, /* system is paused */ mouse_capture; /* mouse is captured in app */ GLOBAL uint64_t timer_freq; GLOBAL int infocus; -GLOBAL char emu_version[128]; /* version ID string */ +GLOBAL char emu_version[200]; /* version ID string */ GLOBAL int rctrl_is_lalt; GLOBAL int update_icons; diff --git a/src/plat_midi.h b/src/plat_midi.h index 5070de68a..933e49ee6 100644 --- a/src/plat_midi.h +++ b/src/plat_midi.h @@ -7,3 +7,9 @@ extern int plat_midi_write(uint8_t val); 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/printer/prt_escp.c b/src/printer/prt_escp.c index 597105cd4..c74449ba6 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -10,12 +10,12 @@ * * Version: @(#)prt_escp.c 1.0.7 2019/09/23 * - * Authors: Michael Drüing, + * Authors: Michael Dr�ing, * Fred N. van Kempen, * * Based on code by Frederic Weymann (originally for DosBox.) * - * Copyright 2018,2019 Michael Drüing. + * Copyright 2018,2019 Michael Dr�ing. * Copyright 2019,2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with @@ -228,7 +228,7 @@ typedef struct { double horizontal_tabs[32]; uint8_t num_horizontal_tabs; double vertical_tabs[16]; - uint8_t num_vertical_tabs; + int8_t num_vertical_tabs; /* bit graphics data */ uint16_t bg_h_density; /* in dpi */ @@ -410,15 +410,17 @@ static void new_page(escp_t *dev, int8_t save, int8_t resetx) { /* Dump the current page if needed. */ - if (save) + if (save && dev->page) 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); + if (dev->page) { + 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"); @@ -2056,6 +2058,11 @@ escp_init(void *lpt) dev->lpt = lpt; /* Create a full pathname for the font files. */ + if(wcslen(exe_path) >= sizeof_w(dev->fontpath)) { + free(dev); + return(NULL); + } + wcscpy(dev->fontpath, exe_path); plat_path_slash(dev->fontpath); wcscat(dev->fontpath, L"roms/printer/fonts/"); diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index effb2d07e..92ce3d83c 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -86,7 +86,7 @@ typedef struct wchar_t filename[260]; char buffer[POSTSCRIPT_BUFFER_LENGTH]; - uint16_t buffer_pos; + size_t buffer_pos; } ps_t; static void @@ -271,13 +271,13 @@ static void process_data(ps_t *dev) { if (dev->data < 0x20 || dev->data == 0x7F) { - if (process_nonprintable(dev)) { + if (process_nonprintable(dev)) return; - } } if (dev->buffer_pos == POSTSCRIPT_BUFFER_LENGTH) { write_buffer(dev, false); + dev->buffer_pos = 0; } dev->buffer[dev->buffer_pos++] = dev->data; diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index aa56ae2e1..404e27c86 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -465,13 +465,14 @@ prnt_close(void *priv) { prnt_t *dev = (prnt_t *)priv; - if (dev == NULL) return; + if (dev == NULL) + return; - /* print last page if it contains data */ - if (dev->page->dirty) - dump_page(dev); + if (dev->page) { + /* 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); diff --git a/src/rom.c b/src/rom.c index 204fd0eee..8d8c23e99 100644 --- a/src/rom.c +++ b/src/rom.c @@ -62,7 +62,10 @@ rom_fopen(wchar_t *fn, wchar_t *mode) { wchar_t temp[1024]; - wcscpy(temp, exe_path); + if (wcslen(exe_path) <= 1024) + wcscpy(temp, exe_path); + else + wcsncpy(temp, exe_path, 1024); plat_put_backslash(temp); wcscat(temp, fn); @@ -171,17 +174,15 @@ rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) /* Make sure we only look at the base-256K offset. */ if (addr >= 0x40000) - { addr = 0; - } else - { addr &= 0x03ffff; - } if (ptr != NULL) { - (void)fseek(f, off, SEEK_SET); - (void)fread(ptr+addr, sz, 1, f); + if (fseek(f, off, SEEK_SET) == -1) + fatal("rom_load_linear(): Error seeking to the beginning of the file\n"); + if (fread(ptr+addr, 1, sz, f) > sz) + fatal("rom_load_linear(): Error reading data\n"); } (void)fclose(f); @@ -218,9 +219,12 @@ rom_load_linear_inverted(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *p } 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); + if (fseek(f, off, SEEK_SET) == -1) + fatal("rom_load_linear_inverted(): Error seeking to the beginning of the file\n"); + if (fread(ptr+addr+0x10000, 1, sz >> 1, f) > (sz >> 1)) + fatal("rom_load_linear_inverted(): Error reading the upper half of the data\n"); + if (fread(ptr+addr, sz >> 1, 1, f) > (sz >> 1)) + fatal("rom_load_linear_inverted(): Error reading the lower half of the data\n"); } (void)fclose(f); @@ -260,8 +264,8 @@ rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int off, (void)fseek(fl, off, SEEK_SET); (void)fseek(fh, off, SEEK_SET); for (c=0; cnvr_path, L"rb"); if (f) { - fread(dev->nvr, 1, NVR_SIZE, f); + if (fread(dev->nvr, 1, NVR_SIZE, f) != NVR_SIZE) + fatal("aha_setnvr(): Error reading data\n"); fclose(f); f = NULL; } else diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 15a4dc7d4..28ecdb612 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -410,7 +410,8 @@ BuslogicInitializeAutoSCSIRam(x54x_t *dev) f = nvr_fopen(BuslogicGetNVRFileName(bl), L"rb"); if (f) { - fread(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); + if (fread(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f) != 64) + fatal("BuslogicInitializeAutoSCSIRam(): Error reading data\n"); fclose(f); f = NULL; if (bl->chip == CHIP_BUSLOGIC_PCI) { @@ -624,10 +625,6 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u buslogic_log("Transfer Control %02X\n", ESCSICmd->DataDirection); buslogic_log("CDB Length %i\n", ESCSICmd->CDBLength); - if (ESCSICmd->DataDirection > 0x03) { - buslogic_log("Invalid control byte: %02X\n", - ESCSICmd->DataDirection); - } } target_cdb_len = 12; @@ -1229,6 +1226,7 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) case 0x10: val &= 0xe0; val |= 1; + /*FALLTHROUGH*/ case 0x11: case 0x12: case 0x13: /* I/O Base set. */ @@ -1250,6 +1248,7 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) case 0x14: val &= 0xe0; + /*FALLTHROUGH*/ case 0x15: case 0x16: case 0x17: /* MMIO Base set. */ diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 045c78fa9..2f87dac04 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -9,11 +9,11 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)scsi_cdrom.c 1.0.72 2019/11/19 + * Version: @(#)scsi_cdrom.c 1.0.74 2020/01/17 * * Author: Miran Grca, * - * Copyright 2016-2019 Miran Grca. + * Copyright 2016-2020 Miran Grca. */ #include #include @@ -450,7 +450,8 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) 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); + if (fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f) != 0x10) + fatal("scsi_cdrom_mode_sense_load(): Error reading data\n"); fclose(f); } } @@ -606,14 +607,15 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) { double ret = -1.0; - if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev && dev->drv && (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; + if (dev) + dev->callback = -1.0; return 0.0; } else return ret * 1000000.0; @@ -1078,29 +1080,31 @@ scsi_cdrom_read_dvd_structure(scsi_cdrom_t *dev, int format, const uint8_t *pack 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 */ + buf[4] = 18; /* Length of Layer Information */ + buf[5] = 0; + + buf[6] = 1; /* DVD-ROM, part version 1 */ + buf[7] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[8] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[9] = 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[10] = 0x00; + buf[11] = 0x03; + buf[12] = buf[13] = 0; /* start sector */ - 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; + buf[14] = 0x00; + buf[15] = (total_sectors >> 16) & 0xff; /* end sector */ + buf[16] = (total_sectors >> 8) & 0xff; + buf[17] = total_sectors & 0xff; - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048 +2 ) >> 8) & 0xff; - buf[1] = (2048 + 2) & 0xff; + buf[18] = 0x00; + buf[19] = (total_sectors >> 16) & 0xff; /* l0 end sector */ + buf[20] = (total_sectors >> 8) & 0xff; + buf[21] = total_sectors & 0xff; - /* 2k data + 4 byte header */ - return (2048 + 4); + /* 20 bytes of data + 4 byte header */ + return (20 + 4); case 0x01: /* DVD copyright information */ buf[4] = 0; /* no copyright data */ @@ -1133,8 +1137,8 @@ scsi_cdrom_read_dvd_structure(scsi_cdrom_t *dev, int format, const uint8_t *pack buf[4] = 0x00; /* Physical format */ buf[5] = 0x40; /* Not writable, is readable */ - buf[6] = ((2048 + 4) >> 8) & 0xff; - buf[7] = (2048 + 4) & 0xff; + buf[6] = ((20 + 4) >> 8) & 0xff; + buf[7] = (20 + 4) & 0xff; buf[8] = 0x01; /* Copyright info */ buf[9] = 0x40; /* Not writable, is readable */ @@ -1536,6 +1540,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) /* IMPORTANT: Convert the command to new read CD for pass through purposes. */ dev->current_cdb[0] = 0xbe; + /*FALLTHROUGH*/ + case GPCMD_READ_6: case GPCMD_READ_10: case GPCMD_READ_12: @@ -1891,7 +1897,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } gesn_event_header->len = used_len - sizeof(*gesn_event_header); - memcpy(dev->buffer, gesn_event_header, 4); + memmove(dev->buffer, gesn_event_header, 4); scsi_cdrom_set_buf_len(dev, BufLen, &used_len); @@ -2076,10 +2082,13 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) 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) && (alloc_length != 4)) { + if (cdb[3] <= 3) { dev->buffer[pos++] = cdb[3]; /*Format code*/ - dev->buffer[1] = cdrom_get_current_subchannel(dev->drv, &dev->buffer[4], msf); - dev->buffer[2] = alloc_length - 4; + + 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: @@ -2123,7 +2132,10 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { if (cdb[1] == 0) { ret = scsi_cdrom_read_dvd_structure(dev, format, cdb, dev->buffer); - if (ret) { + dev->buffer[0] = (ret >> 8); + dev->buffer[1] = (ret & 0xff); + dev->buffer[2] = dev->buffer[3] = 0x00; + if (ret) { scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); @@ -2542,7 +2554,7 @@ scsi_cdrom_drive_reset(int c) 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)) + 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. */ diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index f989d7423..5527dae0e 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -248,7 +248,7 @@ #define CHECK_READY 2 #define ALLOW_UA 1 -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) +#define MSFtoLBA(m,s,f) ((((m * 60) + s) * 75) + f) #define MSG_COMMAND_COMPLETE 0x00 diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 91256b4dc..61ee5c43f 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -155,7 +155,8 @@ scsi_disk_mode_sense_load(scsi_disk_t *dev) 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); + if (fread(dev->ms_pages_saved.pages[0x30], 1, 0x18, f) != 0x18) + fatal("scsi_disk_mode_sense_load(): Error reading data\n"); fclose(f); } } @@ -613,6 +614,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) scsi_disk_invalid_field(dev); return; } + /*FALLTHROUGH*/ case GPCMD_SCSI_RESERVE: case GPCMD_SCSI_RELEASE: case GPCMD_TEST_UNIT_READY: @@ -1212,7 +1214,7 @@ scsi_disk_hard_reset(void) scsi_disk_log("SCSI disk hard_reset drive=%d\n", c); /* Make sure to ignore any SCSI disk that has an out of range ID. */ - if (hdd[c].scsi_id > SCSI_ID_MAX) + if (hdd[c].scsi_id >= SCSI_ID_MAX) continue; /* Make sure to ignore any SCSI disk whose image file name is empty. */ diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index a2991cce8..c361c2d14 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -430,7 +430,7 @@ ncr_bus_update(void *priv, int bus) 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) { + if (ncr->is_msgout) { ncr->is_msgout = 0; ncr->command[1] &= ~(0x80 | 0x40 | 0x20); ncr->command[1] |= ncr->msglun << 5; diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index cd4edbf79..8c8a5985d 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -260,6 +260,11 @@ x54x_bios_scsi_command(scsi_device_t *dev, uint8_t *cdb, uint8_t *buf, int len, return(completion_code(scsi_device_sense(dev))); if (len > 0) { + if (dev->buffer_length == -1) { + fatal("Buffer length -1 when doing SCSI DMA\n"); + return(0xff); + } + if (dev->phase == SCSI_PHASE_DATA_IN) { if (buf) memcpy(buf, dev->sc->temp_buffer, dev->buffer_length); @@ -410,7 +415,7 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) x54x_log("BIOS Command = 0x%02X\n", cmd->command); - if ((cmd->id > max_id) || (cmd->lun > 7)) { + if (cmd->id > max_id) { x54x_log("BIOS Target ID %i or LUN %i are above maximum\n", cmd->id, cmd->lun); ret = 0x80; @@ -1091,14 +1096,6 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) return; } - if (req->CmdBlock.common.ControlByte > 0x03) { - 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); - dev->callback_sub_phase = 4; - return; - } - dev->callback_sub_phase = 1; } } diff --git a/src/sio_fdc37c66x.c b/src/sio_fdc37c66x.c index 21003e648..c1560f920 100644 --- a/src/sio_fdc37c66x.c +++ b/src/sio_fdc37c66x.c @@ -9,13 +9,13 @@ * Implementation of the SMC FDC37C663 and FDC37C665 Super * I/O Chips. * - * Version: @(#)sio_fdc37c66x.c 1.0.14 2018/11/12 + * 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 @@ -129,7 +129,17 @@ lpt1_handler(fdc37c66x_t *dev) } -static void fdc37c66x_write(uint16_t port, uint8_t val, void *priv) +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; @@ -148,6 +158,10 @@ static void fdc37c66x_write(uint16_t port, uint8_t val, void *priv) 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); @@ -173,7 +187,9 @@ static void fdc37c66x_write(uint16_t port, uint8_t val, void *priv) if (valxor & 2) fdc_update_enh_mode(dev->fdc, (dev->regs[3] & 2) ? 1 : 0); break; - case 5: + 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) diff --git a/src/sio_fdc37c93x.c b/src/sio_fdc37c93x.c index e93ffea54..ef3380ee4 100644 --- a/src/sio_fdc37c93x.c +++ b/src/sio_fdc37c93x.c @@ -203,7 +203,7 @@ static void fdc37c93x_gpio_handler(fdc37c93x_t *dev) break; } dev->gpio_base = ld_port; - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFE)) + if (ld_port > 0x0000) io_sethandler(dev->gpio_base, 0x0002, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); } diff --git a/src/sio_w83877f.c b/src/sio_w83877f.c index 98d514c32..69ad67286 100644 --- a/src/sio_w83877f.c +++ b/src/sio_w83877f.c @@ -11,10 +11,10 @@ * Winbond W83877F Super I/O Chip * Used by the Award 430HX * - * Version: @(#)sio_w83877f.c 1.0.15 2019/05/17 + * 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 @@ -167,12 +167,21 @@ static void w83877f_write(uint16_t port, uint8_t val, void *priv) { w83877f_t *dev = (w83877f_t *) priv; - uint8_t index = (port & 1) ? 0 : 1; uint8_t valxor = 0; uint8_t max = 0x2A; uint8_t lpt_irq; - if (index) { + if (port == 0x250) { + if (val == dev->key) + dev->locked = 1; + else + 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) { @@ -196,7 +205,7 @@ w83877f_write(uint16_t port, uint8_t val, void *priv) } } return; - } else { + } else if ((port == 0x252) || (port == 0x3f1)) { if (dev->locked) { if (dev->rw_locked) return; @@ -214,7 +223,7 @@ w83877f_write(uint16_t port, uint8_t val, void *priv) switch (dev->cur_reg) { case 0: - if (valxor & 0xc0) { + if (valxor & 0x0c) { lpt1_remove(); if (!(dev->regs[4] & 0x80)) lpt1_init(make_port(dev, 0x23)); @@ -340,12 +349,11 @@ w83877f_read(uint16_t port, void *priv) { w83877f_t *dev = (w83877f_t *) priv; uint8_t ret = 0xff; - uint8_t index = (port & 1) ? 0 : 1; if (dev->locked) { - if (index) + if ((port == 0x3f0) || (port == 0x251)) ret = dev->cur_reg; - else { + 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) 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 1f5f0ed47..31a8b86bf 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -8,7 +8,7 @@ * * MIDI device core module. * - * Version: @(#)midi.c 1.0.1 2018/10/10 + * Version: @(#)midi.c 1.0.2 2018/12/31 * * Authors: Sarah Walker, * Miran Grca, @@ -37,28 +37,23 @@ #ifdef USE_MUNT # include "midi_mt32.h" #endif +#include "midi_input.h" -#define SYSEX_SIZE 1024 -#define RAWBUF 1024 - 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; -typedef struct -{ - uint8_t midi_rt_buf[1024], midi_cmd_buf[1024], - midi_status, midi_sysex_data[1026]; - int midi_cmd_pos, midi_cmd_len; - unsigned int midi_sysex_start, midi_sysex_delay, - midi_pos; - midi_device_t* m_device; -} midi_t; +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; -static midi_t *midi = NULL; +uint8_t MIDI_InSysexBuf[SYSEX_SIZE]; -static uint8_t MIDI_evt_len[256] = { +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 */ @@ -85,7 +80,7 @@ typedef struct { const char *name, *internal_name; const device_t *device; -} MIDI_DEVICE; +} MIDI_DEVICE, MIDI_IN_DEVICE; static const MIDI_DEVICE devices[] = { @@ -101,6 +96,12 @@ static const MIDI_DEVICE devices[] = {"", "", NULL} }; +static const MIDI_IN_DEVICE midi_in_devices[] = +{ + {"None", "none", NULL}, + {MIDI_INPUT_NAME, MIDI_INPUT_INTERNAL_NAME, &midi_input_device}, + {"", "", NULL} +}; int midi_device_available(int card) @@ -172,16 +173,25 @@ midi_init(midi_device_t* device) midi = (midi_t *) malloc(sizeof(midi_t)); memset(midi, 0, sizeof(midi_t)); - midi->m_device = device; + midi->m_out_device = device; +} + +void +midi_in_init(midi_device_t* device, midi_t **mididev) +{ + *mididev = (midi_t *)malloc(sizeof(midi_t)); + memset(*mididev, 0, sizeof(midi_t)); + + (*mididev)->m_in_device = device; } void midi_close(void) { - if (midi && midi->m_device) { - free(midi->m_device); - midi->m_device = NULL; + if (midi && midi->m_out_device) { + free(midi->m_out_device); + midi->m_out_device = NULL; } if (midi) { @@ -190,41 +200,137 @@ midi_close(void) } } +void +midi_in_close(void) +{ + if (midi_in && midi_in->m_in_device) { + free(midi_in->m_in_device); + midi_in->m_in_device = NULL; + } + + if (midi_in) { + free(midi_in); + midi_in = NULL; + } +} + void midi_poll(void) { - if (midi && midi->m_device && midi->m_device->poll) - midi->m_device->poll(); + 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_device->play_msg) - midi->m_device->play_msg(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_device->play_sysex) - midi->m_device->play_sysex(sysex, 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_write(uint8_t val) +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_device) + if (!midi || !midi->m_out_device) { return; + } - if (midi->m_device->write && midi->m_device->write(val)) + 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; @@ -289,3 +395,13 @@ midi_write(uint8_t val) } } } + +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_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_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/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 06a4fcee5..d4a29412d 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -20,11 +20,11 @@ typedef struct adgold_t { int adgold_irq_status; - uint8_t adgold_eeprom[0x19]; + uint8_t adgold_eeprom[0x1a]; uint8_t adgold_status; int adgold_38x_state, adgold_38x_addr; - uint8_t adgold_38x_regs[0x19]; + uint8_t adgold_38x_regs[0x1a]; int adgold_mma_addr; uint8_t adgold_mma_regs[2][0xe]; @@ -211,9 +211,9 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) { case 0x00: /*Control/ID*/ if (val & 1) - memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x1a); if (val & 2) - memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x19); + memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x1a); break; case 0x04: /*Final output volume left*/ @@ -384,7 +384,7 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) adgold->adgold_mma_regs[0][adgold->adgold_mma_addr] = val; break; case 7: - if (adgold->adgold_mma_addr >= 0xf) break; + if (adgold->adgold_mma_addr >= 0xe) break; switch (adgold->adgold_mma_addr) { case 0x9: @@ -503,8 +503,10 @@ uint8_t adgold_read(uint16_t addr, void *p) } break; case 7: - if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; - temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; + if (adgold->adgold_mma_addr >= 0xf) + temp = 0xff; + else + temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; break; } return temp; @@ -774,7 +776,8 @@ void *adgold_init(const device_t *info) f = nvr_fopen(L"adgold.bin", L"rb"); if (f) { - fread(adgold->adgold_eeprom, 0x18, 1, f); + if (fread(adgold->adgold_eeprom, 1, 0x1a, f) != 0x1a) + fatal("adgold_init(): Error reading data\n"); fclose(f); } diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index c6bbefc6b..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; @@ -116,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 @@ -164,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; @@ -219,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: @@ -253,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; } @@ -340,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); } @@ -374,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; } @@ -382,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: @@ -412,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: @@ -481,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: @@ -593,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); } @@ -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: @@ -1107,10 +1164,33 @@ static void es1371_poll(void *p) timer_advance_u64(&es1371->dac[1].timer, es1371->dac[1].latch); - es1371_update(es1371); - - if (es1371->int_ctrl & INT_DAC1_EN) - { + 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]; diff --git a/src/sound/snd_dbopl.cc b/src/sound/snd_dbopl.cc deleted file mode 100644 index 2ccc9e56c..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, 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; - - 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[samples]; - - 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[samples*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 f5d19daac..9be46bb4c 100644 --- a/src/sound/snd_emu8k.c +++ b/src/sound/snd_emu8k.c @@ -2143,7 +2143,8 @@ void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) fatal("AWE32.RAW not found\n"); emu8k->rom = malloc(1024 * 1024); - fread(emu8k->rom, 1024 * 1024, 1, f); + if (fread(emu8k->rom, 1, 1048576, f) != 1048576) + fatal("emu8k_init(): Error reading data\n"); fclose(f); /*AWE-DUMP creates ROM images offset by 2 bytes, so if we detect this then correct it*/ diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 46bd3408d..3df40d2a0 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 { @@ -51,12 +82,14 @@ typedef struct gus_t uint64_t samp_latch; uint8_t *ram; + uint32_t gus_end_ram; int irqnext; 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; @@ -68,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; @@ -78,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[]= @@ -102,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; @@ -157,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*/ @@ -231,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; @@ -259,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]; @@ -294,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; @@ -449,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; @@ -466,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); } } @@ -493,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; @@ -542,67 +598,98 @@ 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: + /*FALLTHROUGH*/ + 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*/ @@ -632,7 +719,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*/ @@ -681,16 +768,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: @@ -708,15 +799,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 @@ -727,14 +818,15 @@ uint8_t readgus(uint16_t addr, void *p) } break; - case 0x249: + case 0x209: gus->ad_status &= ~0x01; nmi = 0; + /*FALLTHROUGH*/ case 0x389: val = gus->ad_data; break; - case 0x24A: + case 0x20A: val = gus->adcommand; break; @@ -756,9 +848,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; } } @@ -767,10 +859,11 @@ 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) @@ -787,8 +880,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; } @@ -798,8 +891,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); } } @@ -998,16 +1091,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++) { @@ -1026,10 +1160,14 @@ void *gus_init(const device_t *info) 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->samp_timer, gus_poll_wave, gus, 1); timer_add(&gus->timer_1, gus_poll_timer_1, gus, 1); @@ -1037,6 +1175,10 @@ void *gus_init(const device_t *info) sound_add_handler(gus_get_buffer, gus); + input_msg = gus_input_msg; + input_sysex = gus_input_sysex; + midi_in_p = gus; + return gus; } @@ -1058,11 +1200,76 @@ void gus_speed_changed(void *p) 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_mpu401.c b/src/sound/snd_mpu401.c index 15105268f..b2be5e1cd 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -29,6 +29,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../device.h" +#include "../plat.h" #include "../io.h" #include "../machine/machine.h" #include "../mca.h" @@ -38,6 +39,8 @@ #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, @@ -48,7 +51,10 @@ enum { int mpu401_standalone_enable = 0; 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 @@ -72,38 +78,141 @@ mpu401_log(const char *fmt, ...) static void -QueueByte(mpu_t *mpu, uint8_t data) +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 +MPU401_StartClock(mpu_t *mpu) +{ + 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; + } + 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->mode == M_INTELLIGENT)) { + + 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"); + } } 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; } @@ -116,8 +225,10 @@ MPU401_Reset(mpu_t *mpu) 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; @@ -129,27 +240,64 @@ MPU401_Reset(mpu_t *mpu) 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); + } } @@ -163,6 +311,7 @@ MPU401_ResetDone(void *priv) timer_disable(&mpu->mpu401_reset_callback); mpu->state.reset = 0; + if (mpu->state.cmd_pending) { MPU401_WriteCommand(mpu, mpu->state.cmd_pending - 1); mpu->state.cmd_pending = 0; @@ -173,162 +322,286 @@ MPU401_ResetDone(void *priv) static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val) { - uint8_t i, was_uart; + uint8_t i, j, was_uart, recmsg[3]; if (mpu->state.reset) mpu->state.cmd_pending = val + 1; + /* The only command recognized in UART mode is 0xFF: Reset and return to Intelligent mode. */ + if ((val != 0xff) && (mpu->mode == M_UART)) + return; + + /* In Intelligent mode, UART-only variants of the MPU-401 only support commands 0x3F and 0xFF. */ if ((val != 0x3f) && (val != 0xff) && !mpu->intelligent) return; - if (val <= 0x2f) { - switch (val&3) { /* MIDI stop, start, continue */ - case 1: - midi_write(0xfc); - break; + /* Hack: Enable midi through after the first mpu401 command is written. */ + mpu->midi_thru = 1; - case 2: - midi_write(0xfa); - break; - - case 3: - midi_write(0xfb); - break; + 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; - timer_disable(&mpu->mpu401_event_callback); - - 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; - timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / (mpu->clock.tempo*mpu->clock.timebase)) * 1000 * 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 0xdf: /* Send system message */ - mpu->state.wsd = 0; - mpu->state.wsm = 1; - mpu->state.wsd_start = 1; + case 0x30: /* Configuration 0x30 - 0x39 */ + mpu->filter.allnotesoff_out = 0; break; - - case 0x8e: /* Conductor */ - mpu->state.cond_set = 0; + case 0x32: + mpu->filter.rt_out = 0; break; - - case 0x8f: - mpu->state.cond_set = 1; + 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; j < 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->clock.clock_to_host = 0; + mpu->state.clock_to_host = 0; + MPU401_StopClock(mpu); break; - case 0x95: - mpu->clock.clock_to_host = 1; + mpu->state.clock_to_host = 1; + MPU401_StartClock(mpu); break; - - case 0xc2: /* Internal timebase */ - mpu->clock.timebase = 48; + case 0x96: case 0x97: /* Sysex input allow */ + mpu->filter.sysex_in = !!(val & 1); + if (val & 1) + mpu->filter.sysex_thru = 0; break; - - case 0xc3: - mpu->clock.timebase = 72; + 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; - - 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; - break; - /* Commands 0xa# returning data */ case 0xab: /* Request and clear recording counter */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, 0); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, 0); return; - case 0xac: /* Request version */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, MPU401_VERSION); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MPU401_VERSION); return; - case 0xad: /* Request revision */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, MPU401_REVISION); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MPU401_REVISION); return; - case 0xaf: /* Request tempo */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, mpu->clock.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 = 40; + mpu->clock.tempo_rel = 0x40; 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); - } + 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; - 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; + 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; + /* 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; break; - case 0xff: /* Reset MPU-401 */ - mpu401_log("MPU-401:Reset %X\n",val); + 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); @@ -337,27 +610,22 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) return; /* do not send ack in UART mode */ break; - case 0x3f: /* UART mode */ - mpu401_log("MPU-401:Set UART mode %X\n",val); - QueueByte(mpu, MSG_MPU_ACK); - mpu->mode = M_UART; - return; - /* 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) { - static int length, cnt, posd; + static int length, cnt; + uint8_t i; if (mpu->mode == M_UART) { - midi_write(val); + midi_raw_out_byte(val); return; } @@ -369,39 +637,55 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) switch (mpu->state.command_byte) { /* 0xe# command data */ case 0x00: break; - case 0xe0: /* Set tempo */ mpu->state.command_byte = 0; - mpu->clock.tempo = val; + 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; 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; + 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; return; - case 0xed: /* Set play counter mask */ 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; return; - case 0xef: /* Set 9-16 MIDI channel mask */ mpu->state.command_byte = 0; mpu->state.midi_mask &= 0x00ff; @@ -413,53 +697,49 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) return; } - 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; + 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; + 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; + 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 (cnt < length) { - midi_write(val); + mpu->playbuf[mpu->state.track].value[cnt] = val; cnt++; } if (cnt == length) { + MPU401_IntelligentOut(mpu, mpu->state.track); mpu->state.wsd = 0; - mpu->state.channel = mpu->state.old_chan; + 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; @@ -481,12 +761,17 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) 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 || (cnt < length)) { - midi_write(val); + midi_raw_out_byte(val); cnt++; } @@ -501,37 +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; + 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; } - 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)) + if ((val == 0xf8) || (val == 0xf9) || (val == 0xfc)) mpu->condbuf.type = T_OVERFLOW; - mpu->condbuf.value[mpu->condbuf.vlength] = val; - mpu->condbuf.vlength++; - if ((val & 0xf0) != 0xe0) - MPU401_EOIHandlerDispatch(mpu); - else + 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; @@ -540,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; + mpu->state.data_onoff++; else { mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); + mpu->state.track_req = 0; return; } mpu->state.send_now = !val ? 1 : 0; - mpu->playbuf[mpu->state.channel].counter = val; + 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) { + cnt = 0; + mpu->state.data_onoff++; + switch (val & 0xf0) { + case 0xc0: case 0xd0: /* MIDI Message */ + 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: + length = mpu->playbuf[mpu->state.track].length = 3; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + break; case 0xf0: /* System message or mark */ + mpu->playbuf[mpu->state.track].sys_val = val; if (val > 0xf7) { - mpu->playbuf[mpu->state.channel].type = T_MARK; - mpu->playbuf[mpu->state.channel].sys_val = val; + 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.channel].type = T_MIDI_SYS; - mpu->playbuf[mpu->state.channel].sys_val = val; + mpu->playbuf[mpu->state.track].type = T_OVERFLOW; } - length = 1; - break; - - case 0xc0: case 0xd0: /* MIDI Message */ - mpu->playbuf[mpu->state.channel].type = T_MIDI_NORM; - length = mpu->playbuf[mpu->state.channel].length = 2; - 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; - 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; + 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; } @@ -627,15 +954,14 @@ 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 << chan); + if (mpu->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); @@ -643,6 +969,7 @@ UpdateTrack(mpu_t *mpu, uint8_t chan) } +#if 0 static void UpdateConductor(mpu_t *mpu) { @@ -659,6 +986,7 @@ UpdateConductor(mpu_t *mpu) mpu->condbuf.counter = 0xf0; mpu->state.req_mask |= (1 << 9); } +#endif /* Updates counters and requests new data on "End of Input" */ @@ -674,19 +1002,24 @@ MPU401_EOIHandler(void *priv) 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); + if (mpu->state.cond_req) { + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); + } else UpdateTrack(mpu, mpu->state.track); } + if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) + return; + mpu->state.irq_pending = 0; - if (!mpu->state.playing || !mpu->state.req_mask) + if (!(mpu->state.req_mask && mpu->clock.active)) return; i = 0; do { if (mpu->state.req_mask & (1 << i)) { - QueueByte(mpu, 0xf0 + i); + MPU401_QueueByte(mpu, 0xf0 + i); mpu->state.req_mask &= ~(1 << i); break; } @@ -702,7 +1035,7 @@ MPU401_EOIHandlerDispatch(void *priv) mpu401_log("EOI handler dispatch\n"); if (mpu->state.send_now) { mpu->state.eoi_scheduled = 1; - timer_advance_u64(&mpu->mpu401_eoi_callback, 60 * TIMER_USEC); /* Possibly a bit longer */ + timer_advance_u64(&mpu->mpu401_eoi_callback, 60LL * TIMER_USEC); /* Possibly a bit longer */ } else if (!mpu->state.eoi_scheduled) MPU401_EOIHandler(mpu); } @@ -715,12 +1048,28 @@ 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; @@ -731,24 +1080,34 @@ MPU401_ReadData(mpu_t *mpu) /* Shouldn't this check mpu->mode? */ if (mpu->mode == M_UART) { - if (mpu->state.irq_pending) { - picintc(1 << mpu->irq); - mpu->state.irq_pending = 0; - } - + MPU401_ReadRaiseIRQ(mpu); return ret; } - if (mpu->queue_used == 0) { - picintc(1 << mpu->irq); - mpu->state.irq_pending = 0; + if (mpu->state.rec_copy && !mpu->rec_queue_used) { + mpu->state.rec_copy = 0; + MPU401_EOIHandler(mpu); + return ret; } + /* 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.track = ret & 7; mpu->state.data_onoff = 0; mpu->state.cond_req = 0; + mpu->state.track_req = 1; } if (ret == MSG_MPU_COMMAND_REQ) { @@ -759,16 +1118,14 @@ MPU401_ReadData(mpu_t *mpu) 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; } @@ -805,8 +1162,10 @@ mpu401_read(uint16_t addr, void *priv) break; case 1: /* Read Status */ - if (mpu->state.cmd_pending) ret=STATUS_OUTPUT_NOT_READY; - if (!mpu->queue_used) ret=STATUS_INPUT_NOT_READY; + 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); @@ -822,8 +1181,8 @@ 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"); @@ -833,38 +1192,359 @@ MPU401_Event(void *priv) } 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 << i)) { - mpu->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) { + 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); next_event: - new_time = ((mpu->clock.tempo * mpu->clock.timebase * mpu->clock.tempo_rel) / 0x40); - if (new_time == 0) { - timer_disable(&mpu->mpu401_event_callback); + 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, chan, chrefnum; + + /* Abort if sysex transfer is in progress. */ + if (!mpu->state.sysex_in_finished) { + mpu401_log("SYSEX in progress\n"); return; - } else { - timer_advance_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / new_time) * 1000 * TIMER_USEC); - mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((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 */ + 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); } } @@ -901,7 +1581,8 @@ mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) void mpu401_device_add(void) { - if (!mpu401_standalone_enable) return; + if (!mpu401_standalone_enable) + return; if (machines[machine].flags & MACHINE_MCA) device_add(&mpu401_mca_device); @@ -976,8 +1657,12 @@ mpu401_standalone_init(const device_t *info) irq = device_get_config_int("irq"); } - mpu401_init(mpu, base, irq, M_INTELLIGENT); + input_msg = MPU401_InputMsg; + input_sysex = MPU401_InputSysex; + midi_in_p = mpu; + mpu401_init(mpu, base, irq, M_INTELLIGENT); + return(mpu); } diff --git a/src/sound/snd_mpu401.h b/src/sound/snd_mpu401.h index 0aa3f12ad..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.3 2018/09/11 + * Version: @(#)sound_mpu401.h 1.0.4 2018/09/31 * * Author: Sarah Walker, * DOSBox Team, @@ -22,10 +22,16 @@ #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 +/*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, @@ -43,6 +49,13 @@ typedef enum MpuDataType T_COMMAND } MpuDataType; +typedef enum RecState +{ + M_RECOFF, + M_RECSTB, + M_RECON +} RecState; + /* Messages sent to MPU-401 from host */ #define MSG_EOX 0xf7 #define MSG_OVERFLOW 0xf8 @@ -57,6 +70,7 @@ typedef enum MpuDataType typedef struct mpu_t { + int midi_thru; int uart_mode, intelligent, irq, queue_pos, queue_used; @@ -64,10 +78,13 @@ typedef struct mpu_t 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[8], sys_val, + uint8_t value[3], sys_val, vlength,length; MpuDataType type; } playbuf[8], condbuf; @@ -77,23 +94,50 @@ typedef struct mpu_t playing, reset, wsd, wsm, wsd_start, run_irq, irq_pending, + track_req, send_now, eoi_scheduled, - data_onoff; + data_onoff, clock_to_host, + sync_in, sysex_in_finished, + rec_copy; + RecState rec; uint8_t tmask, cmask, amask, - channel, old_chan; + last_rtcmd; uint16_t midi_mask, req_mask; - uint32_t command_byte, cmd_pending; + 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, cth_counter; - int clock_to_host,cth_active; + 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 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 { + 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; diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index f89a81a04..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; - sub_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; - sub_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; - 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) +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; - sub_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,93 +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, 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 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]); +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, 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 +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_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); + 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->timers[0][0], opl_timer_callback00, (void *)opl, 0); - timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); + 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 628d8b55f..aff429e77 100644 --- a/src/sound/snd_opl.h +++ b/src/sound/snd_opl.h @@ -3,30 +3,30 @@ */ typedef struct opl_t { - int chip_nr[2]; - - pc_timer_t timers[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 77% rename from src/sound/snd_dbopl.h rename to src/sound/snd_opl_backend.h index e95a2becd..24120d036 100644 --- a/src/sound/snd_dbopl.h +++ b/src/sound/snd_opl_backend.h @@ -8,8 +8,8 @@ extern "C" { 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_sb.c b/src/sound/snd_sb.c index b16078467..f86e85cd9 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -32,8 +32,8 @@ #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" @@ -203,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; @@ -231,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; @@ -1042,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() @@ -1068,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; } @@ -1091,6 +1101,11 @@ void *sb_mcv_init() 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() @@ -1138,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; } @@ -1171,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; } @@ -1203,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; } @@ -1228,6 +1255,10 @@ void *sb_pro_mcv_init() 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; } @@ -1262,6 +1293,11 @@ void *sb_16_init() } else sb->mpu = NULL; + + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; + return sb; } @@ -1306,6 +1342,10 @@ void *sb_awe32_init() sb->mpu = NULL; emu8k_init(&sb->emu8k, emu_addr, onboard_ram); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; + return sb; } diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index a5f36886e..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,53 +65,58 @@ 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]; @@ -131,1019 +141,1168 @@ sb_dsp_log(const char *fmt, ...) #endif -static inline double sinc(double x) +static __inline double +sinc(double x) { - return sin(M_PI * x) / (M_PI * x); + return sin(M_PI * x) / (M_PI * x); } -static void recalc_sb16_filter(int playback_freq) +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; + /* Cutoff frequency = playback / 2 */ + float fC = ((float)playback_freq / 2.0) / 48000.0; + float gain; + int n; + double w, h; - gain = 0.0; - for (n = 0; n < SB16_NCoef; n++) - gain += low_fir_sb16_coef[n]; + 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))); - /*Normalise filter, to produce unity gain*/ - for (n = 0; n < SB16_NCoef; n++) - low_fir_sb16_coef[n] /= gain; + /* Create windowed-sinc filter */ + low_fir_sb16_coef[n] = w * h; + } + + low_fir_sb16_coef[(SB16_NCoef - 1) / 2] = 1.0; + + gain = 0.0; + for (n = 0; n < SB16_NCoef; n++) + gain += low_fir_sb16_coef[n]; + + /* Normalise filter, to produce unity gain */ + for (n = 0; n < SB16_NCoef; n++) + low_fir_sb16_coef[n] /= gain; } -void sb_irq(sb_dsp_t *dsp, int irq8) +void +sb_irq(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); + 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_dsp_reset(sb_dsp_t *dsp) + +void +sb_irqc(sb_dsp_t *dsp, int irq8) { - timer_disable(&dsp->output_timer); - timer_disable(&dsp->input_timer); + if (irq8) + dsp->sb_irq8 = 0; + else + dsp->sb_irq16 = 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; - - 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; + picintc(1 << dsp->sb_irqnum); } -void sb_doreset(sb_dsp_t *dsp) + +void +sb_dsp_reset(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; + midi_clear_buffer(); + + timer_disable(&dsp->output_timer); + timer_disable(&dsp->input_timer); + + 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; + + 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_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_doreset(sb_dsp_t *dsp) +{ + int c; + + sb_dsp_reset(dsp); + + if (dsp->sb_type==SB16) + sb_commands[8] = 1; + else + sb_commands[8] = -1; + + for (c = 0; c < 256; c++) + dsp->sb_asp_regs[c] = 0; + + dsp->sb_asp_regs[5] = 0x01; + dsp->sb_asp_regs[9] = 0xf8; } -void sb_add_data(sb_dsp_t *dsp, uint8_t v) + +void +sb_dsp_speed_changed(sb_dsp_t *dsp) { - dsp->sb_read_data[dsp->sb_read_wp++] = v; - dsp->sb_read_wp &= 0xff; + 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))); } -#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_add_data(sb_dsp_t *dsp, uint8_t v) { - 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); - } + dsp->sb_read_data[dsp->sb_read_wp++] = v; + dsp->sb_read_wp &= 0xff; } -void sb_start_dma_i(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) { - 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)); + 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); + } } -int sb_8_read_dma(sb_dsp_t *dsp) + +void +sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) { - 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); + 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)); } -void sb_dsp_setirq(sb_dsp_t *dsp, int irq) + +int +sb_8_read_dma(sb_dsp_t *dsp) { - dsp->sb_irqnum = irq; + return dma_channel_read(dsp->sb_8_dmanum); } -void sb_dsp_setdma8(sb_dsp_t *dsp, int dma) + +void +sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) { - dsp->sb_8_dmanum = dma; + dma_channel_write(dsp->sb_8_dmanum, val); } -void sb_dsp_setdma16(sb_dsp_t *dsp, int dma) + +int +sb_16_read_dma(sb_dsp_t *dsp) { - dsp->sb_16_dmanum = dma; + return dma_channel_read(dsp->sb_16_dmanum); } -void sb_exec_command(sb_dsp_t *dsp) + + +int +sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) { - 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 (!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) break; - sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); - break; - case 0x30: - case 0x31: + int ret = dma_channel_write(dsp->sb_16_dmanum, val); + + return (ret == DMA_NODATA); +} + + +void +sb_dsp_setirq(sb_dsp_t *dsp, int irq) +{ + dsp->sb_irqnum = irq; +} + + +void +sb_dsp_setdma8(sb_dsp_t *dsp, int dma) +{ + dsp->sb_8_dmanum = dma; +} + + +void +sb_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; + 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); + } break; - case 0x41: /*Set output sampling rate*/ - case 0x42: /*Set input sampling rate*/ - if (dsp->sb_type < SB16) break; - 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); - 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); + 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) 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; + 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) 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_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; - switch (a & 0xf) - { - case 0xA: /*Read data*/ - if (mpu && dsp->uart_midi) - { - return MPU401_ReadData(mpu); + 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); } - 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 = timer_is_enabled(&dsp->wb_timer); - 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 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) { + 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; - mpu = NULL; - - sb_doreset(dsp); - - timer_add(&dsp->output_timer, pollsb, dsp, 0); - timer_add(&dsp->input_timer, sb_poll_i, dsp, 0); - timer_add(&dsp->wb_timer, sb_wb_clear, dsp, 0); - - /*Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when - a set frequency command is sent.*/ - recalc_sb16_filter(3200*2); -} - -void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) -{ - 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; - - 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) - { - 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 = 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) - { - 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 = 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"); - } - } + /* 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; - 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; - } + 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 2772e2254..9e60dfaac 100644 --- a/src/sound/snd_sb_dsp.h +++ b/src/sound/snd_sb_dsp.h @@ -9,14 +9,18 @@ typedef struct sb_dsp_t 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; @@ -72,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/sound.c b/src/sound/sound.c index 12875f4f1..d3de46351 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -107,7 +107,6 @@ static const SOUND_CARD sound_cards[] = { "[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 } }; @@ -442,6 +441,7 @@ sound_reset(void) sound_realloc_buffers(); midi_device_init(); + midi_in_device_init(); inital(); timer_add(&sound_poll_timer, sound_poll, NULL, 1); diff --git a/src/sst_flash.c b/src/sst_flash.c new file mode 100644 index 000000000..9826742f5 --- /dev/null +++ b/src/sst_flash.c @@ -0,0 +1,305 @@ +/* + * 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 an SST flash chip. + * + * Version: @(#)sst_flash.c 1.0.19 2019/06/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Melissa Goad, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2020 Melissa Goad. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "device.h" +#include "mem.h" +#include "machine/machine.h" +#include "timer.h" +#include "nvr.h" +#include "plat.h" + +typedef struct sst_t +{ + int command_state, id_mode, + erase, dirty; + + uint8_t *array; + + mem_mapping_t mapping[2], mapping_h[2]; +} sst_t; + + +static wchar_t flash_path[1024]; + + +#define SST_CHIP_ERASE 0x10 +#define SST_SECTOR_ERASE 0x30 +#define SST_ERASE 0x80 +#define SST_SET_ID_MODE 0x90 +#define SST_BYTE_PROGRAM 0xa0 +#define SST_CLEAR_ID_MODE 0xf0 + + +static void +sst_new_command(sst_t *dev, uint8_t val) +{ + switch (val) { + case SST_CHIP_ERASE: + if (dev->erase) + memset(dev->array, 0xff, 0x20000); + dev->command_state = 0; + dev->erase = 0; + break; + + case SST_ERASE: + dev->command_state = 0; + dev->erase = 1; + break; + + case SST_SET_ID_MODE: + if (!dev->id_mode) + dev->id_mode = 1; + dev->command_state = 0; + dev->erase = 0; + break; + + case SST_BYTE_PROGRAM: + dev->command_state = 3; + dev->erase = 0; + break; + + case SST_CLEAR_ID_MODE: + if (dev->id_mode) + dev->id_mode = 0; + dev->command_state = 0; + dev->erase = 0; + break; + + default: + dev->command_state = 0; + dev->erase = 0; + } +} + + +static void +sst_sector_erase(sst_t *dev, uint32_t addr) +{ + memset(&dev->array[addr & 0x1f000], 0xff, 4096); + dev->dirty = 1; +} + + +static uint8_t +sst_read_id(uint32_t addr, void *p) +{ + if ((addr & 0xffff) == 0) + return 0xbf; /* SST */ + else if ((addr & 0xffff) == 1) + return 0xb5; /* 39SF010 */ + else + return 0xff; +} + + +static void +sst_write(uint32_t addr, uint8_t val, void *p) +{ + sst_t *dev = (sst_t *) p; + + switch (dev->command_state) { + case 0: + if (val == 0xf0) { + if (dev->id_mode) + dev->id_mode = 0; + } else if ((addr & 0xffff) == 0x5555 && val == 0xaa) + dev->command_state = 1; + else + dev->command_state = 0; + break; + case 1: + if ((addr & 0xffff) == 0x2aaa && val == 0x55) + dev->command_state = 2; + else + dev->command_state = 0; + break; + case 2: + if ((addr & 0xffff) == 0x5555) + sst_new_command(dev, val); + else if ((val == SST_SECTOR_ERASE) && dev->erase) { + sst_sector_erase(dev, addr); + dev->command_state = 0; + } else + dev->command_state = 0; + break; + case 3: + dev->array[addr & 0x1ffff] = val; + dev->command_state = 0; + dev->dirty = 1; + break; + } +} + + +static uint8_t +sst_read(uint32_t addr, void *p) +{ + sst_t *dev = (sst_t *) p; + uint8_t ret = 0xff; + + addr &= 0x000fffff; + + if (dev->id_mode) + ret = sst_read_id(addr, p); + else { + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = dev->array[addr - biosaddr]; + } + + return ret; +} + + +static uint16_t +sst_readw(uint32_t addr, void *p) +{ + sst_t *dev = (sst_t *) p; + uint16_t ret = 0xffff; + + addr &= 0x000fffff; + + if (dev->id_mode) + ret = sst_read(addr, p) | (sst_read(addr + 1, p) << 8); + else { + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint16_t *)&dev->array[addr - biosaddr]; + } + + return ret; +} + + +static uint32_t +sst_readl(uint32_t addr, void *p) +{ + sst_t *dev = (sst_t *) p; + uint32_t ret = 0xffffffff; + + addr &= 0x000fffff; + + if (dev->id_mode) + ret = sst_readw(addr, p) | (sst_readw(addr + 2, p) << 16); + else { + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint32_t *)&dev->array[addr - biosaddr]; + } + + return ret; +} + + +static void +sst_add_mappings(sst_t *dev) +{ + int i = 0; + uint32_t base, fbase; + + for (i = 0; i < 2; i++) { + base = 0xe0000 + (i << 16); + fbase = base & biosmask; + + memcpy(&dev->array[fbase], &rom[base & biosmask], 0x10000); + + mem_mapping_add(&(dev->mapping[i]), base, 0x10000, + sst_read, sst_readw, sst_readl, + sst_write, NULL, NULL, + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); + mem_mapping_add(&(dev->mapping_h[i]), (base | 0xfff00000), 0x10000, + sst_read, sst_readw, sst_readl, + sst_write, NULL, NULL, + dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev); + } +} + + +static void * +sst_39sf010_init(const device_t *info) +{ + FILE *f; + sst_t *dev = malloc(sizeof(sst_t)); + memset(dev, 0, sizeof(sst_t)); + + size_t l = strlen(machine_get_internal_name_ex(machine))+1; + wchar_t *machine_name = (wchar_t *) malloc(l * sizeof(wchar_t)); + mbstowcs(machine_name, machine_get_internal_name_ex(machine), l); + l = wcslen(machine_name)+5; + wchar_t *flash_name = (wchar_t *)malloc(l*sizeof(wchar_t)); + swprintf(flash_name, l, L"%ls.bin", machine_name); + + if (wcslen(flash_name) <= 1024) + wcscpy(flash_path, flash_name); + else + wcsncpy(flash_path, flash_name, 1024); + + mem_mapping_disable(&bios_mapping); + mem_mapping_disable(&bios_high_mapping); + + dev->array = (uint8_t *) malloc(biosmask + 1); + memset(dev->array, 0xff, biosmask + 1); + + sst_add_mappings(dev); + + f = nvr_fopen(flash_path, L"rb"); + if (f) { + if (fread(&(dev->array[0x00000]), 1, 0x20000, f) != 0x20000) + fatal("Less than 131072 bytes read from the SST Flash ROM file\n"); + fclose(f); + } + + free(flash_name); + free(machine_name); + + return dev; +} + + +static void +sst_39sf010_close(void *p) +{ + FILE *f; + sst_t *dev = (sst_t *)p; + + f = nvr_fopen(flash_path, L"wb"); + fwrite(&(dev->array[0x00000]), 0x20000, 1, f); + fclose(f); + + free(dev->array); + dev->array = NULL; + + free(dev); +} + + +const device_t sst_flash_39sf010_device = +{ + "SST 39SF010 Flash BIOS", + 0, + 0, + sst_39sf010_init, + sst_39sf010_close, + NULL, + NULL, NULL, NULL, NULL +}; diff --git a/src/sst_flash.h b/src/sst_flash.h new file mode 100644 index 000000000..809fc0c44 --- /dev/null +++ b/src/sst_flash.h @@ -0,0 +1,17 @@ +/* + * 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 an SST flash chip. + * + * Version: @(#)sst_flash.h 1.0.3 2020/01/14 + * + * Author: Melissa Goad, + * Copyright 2020 Melissa Goad. + */ + +extern const device_t sst_flash_39sf010_device; diff --git a/src/via_vt82c586b.c b/src/via_vt82c586b.c new file mode 100644 index 000000000..a4eba54f4 --- /dev/null +++ b/src/via_vt82c586b.c @@ -0,0 +1,642 @@ +/* + * 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 VIA Apollo MVP3 southbridge + * + * Version: @(#)via_vt82c586b.c 1.0.1 2020/01/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * Melissa Goad, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2020 Melissa Goad. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.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 "timer.h" +#include "nvr.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 "via_vt82c586b.h" + + +#define ACPI_TIMER_FREQ 3579545 + +#define ACPI_IO_ENABLE (1 << 7) +#define ACPI_TIMER_32BIT (1 << 3) + + +typedef struct +{ + uint8_t pci_isa_regs[256]; + uint8_t ide_regs[256]; + uint8_t usb_regs[256]; + uint8_t power_regs[256]; + sff8038i_t * bm[2]; + nvr_t * nvr; + int nvr_enabled; + + struct + { + uint16_t io_base; + } usb; + + struct + { + uint16_t io_base; + } power; +} via_vt82c586b_t; + + +static void +via_vt82c586b_reset_hard(void *priv) +{ + int i; + + via_vt82c586b_t *via_vt82c586b = (via_vt82c586b_t *) priv; + uint16_t old_base = (via_vt82c586b->ide_regs[0x20] & 0xf0) | (via_vt82c586b->ide_regs[0x21] << 8); + + sff_bus_master_reset(via_vt82c586b->bm[0], old_base); + sff_bus_master_reset(via_vt82c586b->bm[1], old_base + 8); + + memset(via_vt82c586b->pci_isa_regs, 0, 256); + memset(via_vt82c586b->ide_regs, 0, 256); + memset(via_vt82c586b->usb_regs, 0, 256); + memset(via_vt82c586b->power_regs, 0, 256); + + via_vt82c586b->pci_isa_regs[0x00] = 0x06; via_vt82c586b->pci_isa_regs[0x01] = 0x11; /*VIA*/ + via_vt82c586b->pci_isa_regs[0x02] = 0x86; via_vt82c586b->pci_isa_regs[0x03] = 0x05; /*VT82C586B*/ + via_vt82c586b->pci_isa_regs[0x04] = 0x0f; + via_vt82c586b->pci_isa_regs[0x07] = 0x02; + via_vt82c586b->pci_isa_regs[0x0a] = 0x01; + via_vt82c586b->pci_isa_regs[0x0b] = 0x06; + via_vt82c586b->pci_isa_regs[0x0e] = 0x80; + + via_vt82c586b->pci_isa_regs[0x48] = 0x01; + via_vt82c586b->pci_isa_regs[0x4a] = 0x04; + via_vt82c586b->pci_isa_regs[0x4f] = 0x03; + + via_vt82c586b->pci_isa_regs[0x50] = 0x24; + via_vt82c586b->pci_isa_regs[0x59] = 0x04; + + dma_e = 0x00; + for (i = 0; i < 8; i++) { + dma[i].ab &= 0xffff000f; + dma[i].ac &= 0xffff000f; + } + + pic_set_shadow(0); + + /* IDE registers */ + via_vt82c586b->ide_regs[0x00] = 0x06; via_vt82c586b->ide_regs[0x01] = 0x11; /*VIA*/ + via_vt82c586b->ide_regs[0x02] = 0x71; via_vt82c586b->ide_regs[0x03] = 0x05; /*VT82C586B*/ + via_vt82c586b->ide_regs[0x04] = 0x80; + via_vt82c586b->ide_regs[0x06] = 0x80; via_vt82c586b->ide_regs[0x07] = 0x02; + via_vt82c586b->ide_regs[0x09] = 0x85; + via_vt82c586b->ide_regs[0x0a] = 0x01; + via_vt82c586b->ide_regs[0x0b] = 0x01; + + via_vt82c586b->ide_regs[0x10] = 0xf1; via_vt82c586b->ide_regs[0x11] = 0x01; + via_vt82c586b->ide_regs[0x14] = 0xf5; via_vt82c586b->ide_regs[0x15] = 0x03; + via_vt82c586b->ide_regs[0x18] = 0x71; via_vt82c586b->ide_regs[0x19] = 0x01; + via_vt82c586b->ide_regs[0x1c] = 0x75; via_vt82c586b->ide_regs[0x1d] = 0x03; + via_vt82c586b->ide_regs[0x20] = 0x01; via_vt82c586b->ide_regs[0x21] = 0xcc; + via_vt82c586b->ide_regs[0x3c] = 0x0e; + + via_vt82c586b->ide_regs[0x40] = 0x08; + via_vt82c586b->ide_regs[0x41] = 0x02; + via_vt82c586b->ide_regs[0x42] = 0x09; + via_vt82c586b->ide_regs[0x43] = 0x3a; + via_vt82c586b->ide_regs[0x44] = 0x68; + via_vt82c586b->ide_regs[0x46] = 0xc0; + via_vt82c586b->ide_regs[0x48] = 0xa8; via_vt82c586b->ide_regs[0x49] = 0xa8; + via_vt82c586b->ide_regs[0x4a] = 0xa8; via_vt82c586b->ide_regs[0x4b] = 0xa8; + via_vt82c586b->ide_regs[0x4c] = 0xff; + via_vt82c586b->ide_regs[0x4e] = 0xff; + via_vt82c586b->ide_regs[0x4f] = 0xff; + via_vt82c586b->ide_regs[0x50] = 0x03; via_vt82c586b->ide_regs[0x51] = 0x03; + via_vt82c586b->ide_regs[0x52] = 0x03; via_vt82c586b->ide_regs[0x53] = 0x03; + + via_vt82c586b->ide_regs[0x61] = 0x02; + via_vt82c586b->ide_regs[0x69] = 0x02; + + via_vt82c586b->usb_regs[0x00] = 0x06; via_vt82c586b->usb_regs[0x01] = 0x11; /*VIA*/ + via_vt82c586b->usb_regs[0x02] = 0x38; via_vt82c586b->usb_regs[0x03] = 0x30; + via_vt82c586b->usb_regs[0x04] = 0x00; via_vt82c586b->usb_regs[0x05] = 0x00; + via_vt82c586b->usb_regs[0x06] = 0x00; via_vt82c586b->usb_regs[0x07] = 0x02; + via_vt82c586b->usb_regs[0x0a] = 0x03; + via_vt82c586b->usb_regs[0x0b] = 0x0c; + via_vt82c586b->usb_regs[0x0d] = 0x16; + via_vt82c586b->usb_regs[0x20] = 0x01; + via_vt82c586b->usb_regs[0x21] = 0x03; + via_vt82c586b->usb_regs[0x3d] = 0x04; + + via_vt82c586b->usb_regs[0x60] = 0x10; + via_vt82c586b->usb_regs[0xc1] = 0x20; + + via_vt82c586b->power_regs[0x00] = 0x06; via_vt82c586b->power_regs[0x01] = 0x11; /*VIA*/ + via_vt82c586b->power_regs[0x02] = 0x40; via_vt82c586b->power_regs[0x03] = 0x30; + via_vt82c586b->power_regs[0x04] = 0x00; via_vt82c586b->power_regs[0x05] = 0x00; + via_vt82c586b->power_regs[0x06] = 0x80; via_vt82c586b->power_regs[0x07] = 0x02; + via_vt82c586b->power_regs[0x08] = 0x10; /*Production version (3041)*/ + via_vt82c586b->power_regs[0x48] = 0x01; + + 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); + + pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); + pci_set_mirq_routing(PCI_MIRQ2, PCI_IRQ_DISABLED); + + ide_pri_disable(); + ide_sec_disable(); +} + + +static void +via_vt82c586b_ide_handlers(via_vt82c586b_t *dev) +{ + uint16_t main, side; + + ide_pri_disable(); + ide_sec_disable(); + + if (dev->ide_regs[0x09] & 0x01) { + main = (dev->ide_regs[0x11] << 8) | (dev->ide_regs[0x10] & 0xf8); + side = ((dev->ide_regs[0x15] << 8) | (dev->ide_regs[0x14] & 0xfc)) + 2; + } else { + main = 0x1f0; + side = 0x3f6; + } + ide_set_base(0, main); + ide_set_side(0, side); + + if (dev->ide_regs[0x09] & 0x04) { + main = (dev->ide_regs[0x19] << 8) | (dev->ide_regs[0x18] & 0xf8); + side = ((dev->ide_regs[0x1d] << 8) | (dev->ide_regs[0x1c] & 0xfc)) + 2; + } else { + main = 0x170; + side = 0x376; + } + ide_set_base(1, main); + ide_set_side(1, side); + + if (dev->ide_regs[0x04] & PCI_COMMAND_IO) { + if (dev->ide_regs[0x40] & 0x02) + ide_pri_enable(); + if (dev->ide_regs[0x40] & 0x01) + ide_sec_enable(); + } +} + + +static void +via_vt82c586b_bus_master_handlers(via_vt82c586b_t *dev, uint16_t old_base) +{ + uint16_t base; + base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8); + + sff_bus_master_handlers(dev->bm[0], old_base, base, (dev->ide_regs[0x04] & 1)); + sff_bus_master_handlers(dev->bm[1], old_base + 8, base + 8, (dev->ide_regs[0x04] & 1)); +} + + +static uint8_t +via_vt82c586b_read(int func, int addr, void *priv) +{ + via_vt82c586b_t *dev = (via_vt82c586b_t *) priv; + + uint8_t ret = 0xff; + int c; + + switch(func) { + case 0: + if ((addr >= 0x60) && (addr <= 0x6f)) { + c = (addr & 0x0e) >> 1; + if (addr & 0x01) + ret = (dma[c].ab & 0x0000ff00) >> 8; + else { + ret = (dma[c].ab & 0x000000f0); + ret |= (!!(dma_e & (1 << c)) << 3); + } + } else + ret = dev->pci_isa_regs[addr]; + break; + case 1: + ret = dev->ide_regs[addr]; + break; + case 2: + ret = dev->usb_regs[addr]; + break; + case 3: + ret = dev->power_regs[addr]; + break; + } + + return ret; +} + + +static uint8_t +usb_reg_read(uint16_t addr, void *p) +{ + uint8_t ret = 0xff; + + switch (addr & 0x1f) { + case 0x10: case 0x11: case 0x12: case 0x13: + /* Port status */ + ret = 0x00; + break; + } + + return ret; +} + + +static void +usb_reg_write(uint16_t addr, uint8_t val, void *p) +{ +} + + +static void +nvr_update_io_mapping(via_vt82c586b_t *dev) +{ + if (dev->nvr_enabled) + nvr_at_handler(0, 0x0074, dev->nvr); + + if ((dev->pci_isa_regs[0x5b] & 0x02) && (dev->pci_isa_regs[0x48] & 0x08)) + nvr_at_handler(1, 0x0074, dev->nvr); +} + + +static void +usb_update_io_mapping(via_vt82c586b_t *dev) +{ + if (dev->usb.io_base != 0x0000) + io_removehandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev); + + dev->usb.io_base = (dev->usb_regs[0x20] & ~0x1f) | (dev->usb_regs[0x21] << 8); + + if ((dev->usb_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (dev->usb.io_base != 0x0000)) + io_sethandler(dev->usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, dev); +} + + +static uint8_t +power_reg_read(uint16_t addr, void *p) +{ + via_vt82c586b_t *dev = (via_vt82c586b_t *) p; + + uint32_t timer; + uint8_t ret = 0xff; + + switch (addr & 0xff) { + case 0x08: case 0x09: case 0x0a: case 0x0b: + /* ACPI timer */ + timer = (tsc * ACPI_TIMER_FREQ) / machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed; + if (!(dev->power_regs[0x41] & ACPI_TIMER_32BIT)) + timer &= 0x00ffffff; + ret = (timer >> (8 * (addr & 3))) & 0xff; + break; + } + + return ret; +} + + +static void +power_reg_write(uint16_t addr, uint8_t val, void *p) +{ +} + + +static void +power_update_io_mapping(via_vt82c586b_t *dev) +{ + if (dev->power.io_base != 0x0000) + io_removehandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev); + + dev->power.io_base = (dev->power_regs[0x49] << 8); + + if ((dev->power_regs[0x41] & ACPI_IO_ENABLE) && (dev->power.io_base != 0x0000)) + io_sethandler(dev->power.io_base, 0x100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, dev); +} + + +static void +via_vt82c586b_write(int func, int addr, uint8_t val, void *priv) +{ + via_vt82c586b_t *dev = (via_vt82c586b_t *) priv; + + uint16_t old_base, base; + int c; + + if (func > 3) + return; + + old_base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8); + + switch(func) { + case 0: /* PCI-ISA bridge */ + /* Read-only addresses */ + if ((addr < 4) || (addr == 5) || ((addr >= 8) && (addr < 0x40)) || + (addr == 0x49) || (addr == 0x4b) || ((addr >= 0x51) && (addr < 0x54)) || ((addr >= 0x5d) && (addr < 0x60)) || + ((addr >= 0x68) && (addr < 0x6a)) || (addr >= 0x73)) + return; + + switch (addr) { + case 0x04: + dev->pci_isa_regs[0x04] = (val & 8) | 7; + break; + case 0x06: + dev->pci_isa_regs[0x06] &= ~(val & 0xb0); + break; + + case 0x47: + if ((val & 0x81) == 0x81) + resetx86(); + pic_set_shadow(!!(val & 0x10)); + pci_elcr_set_enabled(!!(val & 0x20)); + dev->pci_isa_regs[0x47] = val & 0xfe; + break; + case 0x48: + dev->pci_isa_regs[0x48] = val; + nvr_update_io_mapping(dev); + break; + + case 0x54: + pci_set_irq_level(PCI_INTA, !(val & 8)); + pci_set_irq_level(PCI_INTB, !(val & 4)); + pci_set_irq_level(PCI_INTC, !(val & 2)); + pci_set_irq_level(PCI_INTD, !(val & 1)); + break; + case 0x55: + pci_set_irq_routing(PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); + pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); + dev->pci_isa_regs[0x55] = val; + break; + case 0x56: + pci_set_irq_routing(PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); + dev->pci_isa_regs[0x56] = val; + break; + case 0x57: + pci_set_irq_routing(PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED); + pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); + dev->pci_isa_regs[0x57] = val; + break; + case 0x58: + pci_set_mirq_routing(PCI_MIRQ2, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED); + dev->pci_isa_regs[0x58] = val; + break; + case 0x5b: + dev->pci_isa_regs[0x5b] = val; + nvr_update_io_mapping(dev); + break; + + case 0x60: case 0x62: case 0x64: case 0x66: + case 0x6a: case 0x6c: case 0x6e: + c = (addr & 0x0e) >> 1; + dma[c].ab = (dma[c].ab & 0xffffff0f) | (val & 0xf0); + dma[c].ac = (dma[c].ac & 0xffffff0f) | (val & 0xf0); + if (val & 0x08) + dma_e |= (1 << c); + else + dma_e &= ~(1 << c); + break; + case 0x61: case 0x63: case 0x65: case 0x67: + case 0x6b: case 0x6d: case 0x6f: + c = (addr & 0x0e) >> 1; + dma[c].ab = (dma[c].ab & 0xffff00ff) | (val << 8); + dma[c].ac = (dma[c].ac & 0xffff00ff) | (val << 8); + break; + + case 0x70: case 0x71: case 0x72: case 0x73: + dev->pci_isa_regs[(addr - 0x44)] = val; + break; + } + break; + + case 1: /* IDE regs */ + /* Read-only addresses */ + if ((addr < 4) || (addr == 5) || (addr == 8) || ((addr >= 0xa) && (addr < 0x0d)) || + ((addr >= 0x0e) && (addr < 0x10)) || ((addr >= 0x12) && (addr < 0x13)) || + ((addr >= 0x16) && (addr < 0x17)) || ((addr >= 0x1a) && (addr < 0x1b)) || + ((addr >= 0x1e) && (addr < 0x1f)) || ((addr >= 0x22) && (addr < 0x3c)) || + ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x54) && (addr < 0x60)) || + ((addr >= 0x52) && (addr < 0x68)) || (addr >= 0x62)) + return; + + switch (addr) { + case 0x04: + base = (dev->ide_regs[0x20] & 0xf0) | (dev->ide_regs[0x21] << 8); + dev->ide_regs[0x04] = val & 0x85; + via_vt82c586b_ide_handlers(dev); + via_vt82c586b_bus_master_handlers(dev, base); + break; + case 0x06: + dev->ide_regs[0x06] &= ~(val & 0xb0); + break; + + case 0x09: + dev->ide_regs[0x09] = (val & 0x05) | 0x8a; + via_vt82c586b_ide_handlers(dev); + break; + + case 0x10: + dev->ide_regs[0x10] = (val & 0xf8) | 1; + via_vt82c586b_ide_handlers(dev); + break; + case 0x11: + dev->ide_regs[0x11] = val; + via_vt82c586b_ide_handlers(dev); + break; + + case 0x14: + dev->ide_regs[0x14] = (val & 0xfc) | 1; + via_vt82c586b_ide_handlers(dev); + break; + case 0x15: + dev->ide_regs[0x15] = val; + via_vt82c586b_ide_handlers(dev); + break; + + case 0x18: + dev->ide_regs[0x18] = (val & 0xf8) | 1; + via_vt82c586b_ide_handlers(dev); + break; + case 0x19: + dev->ide_regs[0x19] = val; + via_vt82c586b_ide_handlers(dev); + break; + + case 0x1c: + dev->ide_regs[0x1c] = (val & 0xfc) | 1; + via_vt82c586b_ide_handlers(dev); + break; + case 0x1d: + dev->ide_regs[0x1d] = val; + via_vt82c586b_ide_handlers(dev); + break; + + case 0x20: + dev->ide_regs[0x20] = (val & 0xf0) | 1; + via_vt82c586b_bus_master_handlers(dev, old_base); + break; + case 0x21: + dev->ide_regs[0x21] = val; + via_vt82c586b_bus_master_handlers(dev, old_base); + break; + + case 0x3d: + sff_set_irq_mode(dev->bm[0], val); + sff_set_irq_mode(dev->bm[1], val); + break; + + case 0x40: + dev->ide_regs[0x40] = val; + via_vt82c586b_ide_handlers(dev); + break; + + default: + dev->ide_regs[addr] = val; + break; + } + break; + + case 2: + /* Read-only addresses */ + if ((addr < 4) || (addr == 5) || (addr == 6) || ((addr >= 8) && (addr < 0xd)) || + ((addr >= 0xe) && (addr < 0x20)) || ((addr >= 0x22) && (addr < 0x3c)) || + ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x42) && (addr < 0x44)) || + ((addr >= 0x46) && (addr < 0xc0)) || (addr >= 0xc2)) + return; + + switch (addr) { + case 0x04: + dev->usb_regs[0x04] = val & 0x97; + break; + case 0x07: + dev->usb_regs[0x07] = val & 0x7f; + break; + + case 0x20: + dev->usb_regs[0x20] = (val & ~0x1f) | 1; + usb_update_io_mapping(dev); + break; + case 0x21: + dev->usb_regs[0x21] = val; + usb_update_io_mapping(dev); + break; + + default: + dev->usb_regs[addr] = val; + break; + } + break; + + case 3: + /* Read-only addresses */ + if ((addr < 0xd) || ((addr >= 0xe) && (addr < 0x40)) || (addr == 0x43) || (addr == 0x48) || + ((addr >= 0x4a) && (addr < 0x50)) || (addr >= 0x54)) + return; + + switch (addr) { + case 0x41: case 0x49: + dev->power_regs[addr] = val; + power_update_io_mapping(dev); + break; + + default: + dev->power_regs[addr] = val; + break; + } + } +} + + +static void +*via_vt82c586b_init(const device_t *info) +{ + via_vt82c586b_t *dev = (via_vt82c586b_t *) malloc(sizeof(via_vt82c586b_t)); + memset(dev, 0, sizeof(via_vt82c586b_t)); + + pci_add_card(7, via_vt82c586b_read, via_vt82c586b_write, dev); + + dev->bm[0] = device_add_inst(&sff8038i_device, 1); + sff_set_slot(dev->bm[0], 7); + sff_set_irq_mode(dev->bm[0], 0); + sff_set_irq_pin(dev->bm[0], PCI_INTA); + + dev->bm[1] = device_add_inst(&sff8038i_device, 2); + sff_set_slot(dev->bm[1], 7); + sff_set_irq_mode(dev->bm[1], 0); + sff_set_irq_pin(dev->bm[1], PCI_INTA); + + dev->nvr = device_add(&via_nvr_device); + + via_vt82c586b_reset_hard(dev); + + device_add(&port_92_pci_device); + + dma_alias_set(); + + pci_enable_mirq(0); + pci_enable_mirq(1); + pci_enable_mirq(2); + + return dev; +} + +static void +via_vt82c586b_close(void *p) +{ + via_vt82c586b_t *via_vt82c586b = (via_vt82c586b_t *)p; + + free(via_vt82c586b); +} + +const device_t via_vt82c586b_device = +{ + "VIA VT82C586B", + DEVICE_PCI, + 0, + via_vt82c586b_init, + via_vt82c586b_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/via_vt82c586b.h b/src/via_vt82c586b.h new file mode 100644 index 000000000..c2fd06a57 --- /dev/null +++ b/src/via_vt82c586b.h @@ -0,0 +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 VIA Apollo MVP3 southbridge + * + * Version: @(#)via_vt82c586b.c 1.0.0 2020/01/14 + * + * Authors: Sarah Walker, + * Miran Grca, + * Melissa Goad, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2020 Melissa Goad. + */ + +extern const device_t via_vt82c586b_device; diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 648772c77..fa4b22044 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -86,6 +86,7 @@ static void ati18800_out(uint16_t addr, uint8_t val, void *p) { case 0xb0: svga_recalctimings(svga); + break; case 0xb2: case 0xbe: if (ati18800->regs[0xbe] & 8) /*Read/write bank mode*/ diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index a0c883c33..28081efe9 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -190,8 +190,7 @@ ati28800_out(uint16_t addr, uint8_t val, void *p) 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)) + if ((ati28800->regs[0xb4] & 0x40) && ((svga->crtcreg <= 0x06) && (svga->crtc[0x07] & 0x10) != 0x10)) return; old = svga->crtc[svga->crtcreg]; diff --git a/src/video/vid_ati_eeprom.c b/src/video/vid_ati_eeprom.c index 3a01bfedd..c7debfcf2 100644 --- a/src/video/vid_ati_eeprom.c +++ b/src/video/vid_ati_eeprom.c @@ -58,15 +58,20 @@ enum void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type) { FILE *f; + int size; eeprom->type = type; - wcscpy(eeprom->fn, fn); + if (wcslen(fn) <= 256) + wcscpy(eeprom->fn, fn); + else + wcsncpy(eeprom->fn, fn, 256); f = nvr_fopen(eeprom->fn, L"rb"); - if (!f) - { - memset(eeprom->data, 0, eeprom->type ? 512 : 128); + size = eeprom->type ? 512 : 128; + if (!f) { + memset(eeprom->data, 0, size); return; } - fread(eeprom->data, 1, eeprom->type ? 512 : 128, f); + if (fread(eeprom->data, 1, size, f) != size) + memset(eeprom->data, 0, size); fclose(f); } diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index d8fe8b8ef..a27621dde 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -668,6 +668,7 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val case 0x118: case 0x119: case 0x11a: case 0x11b: case 0x11e: case 0x11f: WRITE8(addr, mach64->dst_height_width, val); + /*FALLTHROUGH*/ case 0x113: if (((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f || (addr & 0x3ff) == 0x113) && !(val & 0x80)) @@ -788,6 +789,7 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val break; case 0x2a4: case 0x2a5: addr += 2; + /*FALLTHROUGH*/ case 0x2aa: case 0x2ab: WRITE8(addr, mach64->sc_left_right, val); break; @@ -797,6 +799,7 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val break; case 0x2b0: case 0x2b1: addr += 2; + /*FALLTHROUGH*/ case 0x2b6: case 0x2b7: WRITE8(addr, mach64->sc_top_bottom, val); break; @@ -1886,6 +1889,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) break; case 0x110: case 0x111: addr += 2; + /*FALLTHROUGH*/ case 0x114: case 0x115: case 0x118: case 0x119: case 0x11a: case 0x11b: case 0x11e: case 0x11f: @@ -1993,6 +1997,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) break; case 0x2a4: case 0x2a5: addr += 2; + /*FALLTHROUGH*/ case 0x2aa: case 0x2ab: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->sc_left_right); @@ -2004,6 +2009,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) break; case 0x2b0: case 0x2b1: addr += 2; + /*FALLTHROUGH*/ case 0x2b6: case 0x2b7: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->sc_top_bottom); @@ -2798,14 +2804,14 @@ void mach64_hwcursor_draw(svga_t *svga, int displine) 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)) 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; + 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)) 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; + 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)) 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; + 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; } diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 615e3cf5b..1ba5b7a38 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,13 +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.31 2019/12/03 + * Version: @(#)vid_cl_54xx.c 1.0.32 2020/01/11 * * Authors: TheCollector1995, * Miran Grca, * - * Copyright 2016-2019 TheCollector1995. - * Copyright 2016-2019 Miran Grca. + * Copyright 2016-2020 TheCollector1995. + * Copyright 2016-2020 Miran Grca. */ #include #include @@ -334,7 +334,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) if (val == 0x12) svga->seqregs[6] = 0x12; else - svga->seqregs[6] = (svga->crtc[0x27] >= CIRRUS_ID_CLGD5446) ? 0xff : 0x0f; + svga->seqregs[6] = 0x0f; if (svga->crtc[0x27] < CIRRUS_ID_CLGD5429) gd54xx->unlocked = (svga->seqregs[6] == 0x12); break; @@ -1845,9 +1845,6 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) case 3: return; } - - if (svga->fast) - sub_cycles(video_timing_write_l); } else { switch(ap) { case 0: diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 66250d248..c941d85fd 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -257,7 +257,7 @@ void et4000w32p_out(uint16_t addr, uint8_t val, void *p) if (et4000->pci) { et4000->linearbase &= 0xc0000000; - et4000->linearbase = (val & 0xfc) << 22; + et4000->linearbase |= (val & 0xfc) << 22; } else { @@ -1247,9 +1247,9 @@ void et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) case 0x13: et4000->linearbase &= 0x00c00000; - et4000->linearbase = (et4000->pci_regs[0x13] << 24); + et4000->linearbase |= (et4000->pci_regs[0x13] << 24); svga->crtc[0x30] &= 3; - svga->crtc[0x30] = ((et4000->linearbase & 0x3f000000) >> 22); + svga->crtc[0x30] |= ((et4000->linearbase & 0x3f000000) >> 22); et4000w32p_recalcmapping(et4000); break; diff --git a/src/video/vid_im1024.c b/src/video/vid_im1024.c index 0a8ca6e6c..00954e2d6 100644 --- a/src/video/vid_im1024.c +++ b/src/video/vid_im1024.c @@ -523,11 +523,21 @@ hndl_poly(pgc_t *pgc) #ifdef ENABLE_IM1024_LOG im1024_log("IM1024: POLY: out of memory\n"); #endif + if (x) + free(x); + if (y) + free(y); return; } while (parsing) { - if (! pgc_param_byte(pgc, &count)) return; + if (! pgc_param_byte(pgc, &count)) { + if (x) + free(x); + if (y) + free(y); + return; + } if (count + realcount >= as) { nx = (int32_t *)realloc(x, 2 * as * sizeof(int32_t)); @@ -544,8 +554,20 @@ hndl_poly(pgc_t *pgc) } for (n = 0; n < count; n++) { - if (! pgc_param_word(pgc, &xw)) return; - if (! pgc_param_word(pgc, &yw)) return; + if (! pgc_param_word(pgc, &xw)) { + if (x) + free(x); + if (y) + free(y); + return; + } + if (! pgc_param_word(pgc, &yw)) { + if (x) + free(x); + if (y) + free(y); + return; + } /* Skip degenerate line segments. */ if (realcount > 0 && diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c new file mode 100644 index 000000000..5df1a693b --- /dev/null +++ b/src/video/vid_mga.c @@ -0,0 +1,4657 @@ +/* + * 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. + * + * Matrox MGA graphics card emulation. + * + * Version: @(#)vid_mga.c 1.0.1 2020/01/18 + * + * Author: Sarah Walker, + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../timer.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_mga.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +#define ROM_MYSTIQUE L"roms/video/matrox/MYSTIQUE.VBI" +#define ROM_MYSTIQUE_220 L"roms/video/matrox/Myst220_66-99mhz.vbi" + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) +#define FIFO_THRESHOLD 0xe000 + +#define WAKE_DELAY (100 * TIMER_USEC) /* 100us */ + +#define FIFO_ENTRIES (mystique->fifo_write_idx - mystique->fifo_read_idx) +#define FIFO_FULL ((mystique->fifo_write_idx - mystique->fifo_read_idx) >= (FIFO_SIZE-1)) +#define FIFO_EMPTY (mystique->fifo_read_idx == mystique->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +#define DMA_POLL_TIME_US 100 /*100us*/ +#define DMA_MAX_WORDS 256 /*256 quad words per 100us poll*/ + +/*These registers are also mirrored into 0x1dxx, with the mirrored versions starting + the blitter*/ +#define REG_DWGCTL 0x1c00 +#define REG_MACCESS 0x1c04 +#define REG_MCTLWTST 0x1c08 +#define REG_ZORG 0x1c0c +#define REG_PAT0 0x1c10 +#define REG_PAT1 0x1c14 +#define REG_PLNWT 0x1c1c +#define REG_BCOL 0x1c20 +#define REG_FCOL 0x1c24 +#define REG_SRC0 0x1c30 +#define REG_SRC1 0x1c34 +#define REG_SRC2 0x1c38 +#define REG_SRC3 0x1c3c +#define REG_XYSTRT 0x1c40 +#define REG_XYEND 0x1c44 +#define REG_SHIFT 0x1c50 +#define REG_DMAPAD 0x1c54 +#define REG_SGN 0x1c58 +#define REG_LEN 0x1c5c +#define REG_AR0 0x1c60 +#define REG_AR1 0x1c64 +#define REG_AR2 0x1c68 +#define REG_AR3 0x1c6c +#define REG_AR4 0x1c70 +#define REG_AR5 0x1c74 +#define REG_AR6 0x1c78 +#define REG_CXBNDRY 0x1c80 +#define REG_FXBNDRY 0x1c84 +#define REG_YDSTLEN 0x1c88 +#define REG_PITCH 0x1c8c +#define REG_YDST 0x1c90 +#define REG_YDSTORG 0x1c94 +#define REG_YTOP 0x1c98 +#define REG_YBOT 0x1c9c +#define REG_CXLEFT 0x1ca0 +#define REG_CXRIGHT 0x1ca4 +#define REG_FXLEFT 0x1ca8 +#define REG_FXRIGHT 0x1cac +#define REG_XDST 0x1cb0 +#define REG_DR0 0x1cc0 +#define REG_DR2 0x1cc8 +#define REG_DR3 0x1ccc +#define REG_DR4 0x1cd0 +#define REG_DR6 0x1cd8 +#define REG_DR7 0x1cdc +#define REG_DR8 0x1ce0 +#define REG_DR10 0x1ce8 +#define REG_DR11 0x1cec +#define REG_DR12 0x1cf0 +#define REG_DR14 0x1cf8 +#define REG_DR15 0x1cfc + +#define REG_FIFOSTATUS 0x1e10 +#define REG_STATUS 0x1e14 +#define REG_ICLEAR 0x1e18 +#define REG_IEN 0x1e1c +#define REG_VCOUNT 0x1e20 +#define REG_DMAMAP 0x1e30 +#define REG_RST 0x1e40 +#define REG_OPMODE 0x1e54 +#define REG_PRIMADDRESS 0x1e58 +#define REG_PRIMEND 0x1e5c +#define REG_DWG_INDIR_WT 0x1e80 + +#define REG_INSTS0 0x1fc2 +#define REG_MISC 0x1fc2 +#define REG_SEQ_IDX 0x1fc4 +#define REG_SEQ_DATA 0x1fc5 +#define REG_MISCREAD 0x1fcc +#define REG_CRTC_IDX 0x1fd4 +#define REG_CRTC_DATA 0x1fd5 +#define REG_INSTS1 0x1fda +#define REG_CRTCEXT_IDX 0x1fde +#define REG_CRTCEXT_DATA 0x1fdf +#define REG_CACHEFLUSH 0x1fff + +#define REG_TMR0 0x2c00 +#define REG_TMR1 0x2c04 +#define REG_TMR2 0x2c08 +#define REG_TMR3 0x2c0c +#define REG_TMR4 0x2c10 +#define REG_TMR5 0x2c14 +#define REG_TMR6 0x2c18 +#define REG_TMR7 0x2c1c +#define REG_TMR8 0x2c20 +#define REG_TEXORG 0x2c24 +#define REG_TEXWIDTH 0x2c28 +#define REG_TEXHEIGHT 0x2c2c +#define REG_TEXCTL 0x2c30 +#define REG_TEXTRANS 0x2c34 +#define REG_SECADDRESS 0x2c40 +#define REG_SECEND 0x2c44 +#define REG_SOFTRAP 0x2c48 + +#define REG_PALWTADD 0x3c00 +#define REG_PALDATA 0x3c01 +#define REG_PIXRDMSK 0x3c02 +#define REG_PALRDADD 0x3c03 +#define REG_X_DATAREG 0x3c0a +#define REG_CURPOSX 0x3c0c +#define REG_CURPOSY 0x3c0e + +#define REG_STATUS_VSYNCSTS (1 << 3) + +#define CRTCX_R0_STARTADD_MASK (0xf << 0) +#define CRTCX_R0_OFFSET_MASK (3 << 4) + +#define CRTCX_R1_HTOTAL8 (1 << 0) + +#define CRTCX_R2_VTOTAL10 (1 << 0) +#define CRTCX_R2_VTOTAL11 (1 << 1) +#define CRTCX_R2_VDISPEND10 (1 << 2) +#define CRTCX_R2_VBLKSTR10 (1 << 3) +#define CRTCX_R2_VBLKSTR11 (1 << 4) +#define CRTCX_R2_VSYNCSTR10 (1 << 5) +#define CRTCX_R2_VSYNCSTR11 (1 << 6) +#define CRTCX_R2_LINECOMP10 (1 << 7) + +#define CRTCX_R3_MGAMODE (1 << 7) + +#define XREG_XCURADDL 0x04 +#define XREG_XCURADDH 0x05 +#define XREG_XCURCTRL 0x06 + +#define XREG_XCURCOL0R 0x08 +#define XREG_XCURCOL0G 0x09 +#define XREG_XCURCOL0B 0x0a + +#define XREG_XCURCOL1R 0x0c +#define XREG_XCURCOL1G 0x0d +#define XREG_XCURCOL1B 0x0e + +#define XREG_XCURCOL2R 0x10 +#define XREG_XCURCOL2G 0x11 +#define XREG_XCURCOL2B 0x12 + +#define XREG_XVREFCTRL 0x18 +#define XREG_XMULCTRL 0x19 +#define XREG_XPIXCLKCTRL 0x1a +#define XREG_XGENCTRL 0x1d +#define XREG_XMISCCTRL 0x1e + +#define XREG_XGENIOCTRL 0x2a +#define XREG_XGENIODATA 0x2b + +#define XREG_XSYSPLLM 0x2c +#define XREG_XSYSPLLN 0x2d +#define XREG_XSYSPLLP 0x2e +#define XREG_XSYSPLLSTAT 0x2f + +#define XREG_XZOOMCTRL 0x38 + +#define XREG_XPIXPLLCM 0x4c +#define XREG_XPIXPLLCN 0x4d +#define XREG_XPIXPLLCP 0x4e +#define XREG_XPIXPLLSTAT 0x4f + +#define XMISCCTRL_VGA8DAC (1 << 3) + +#define XMULCTRL_DEPTH_MASK (7 << 0) +#define XMULCTRL_DEPTH_8 (0 << 0) +#define XMULCTRL_DEPTH_15 (1 << 0) +#define XMULCTRL_DEPTH_16 (2 << 0) +#define XMULCTRL_DEPTH_24 (3 << 0) +#define XMULCTRL_DEPTH_32_OVERLAYED (4 << 0) +#define XMULCTRL_DEPTH_2G8V16 (5 << 0) +#define XMULCTRL_DEPTH_G16V16 (6 << 0) +#define XMULCTRL_DEPTH_32 (7 << 0) + +#define XSYSPLLSTAT_SYSLOCK (1 << 6) + +#define XPIXPLLSTAT_SYSLOCK (1 << 6) + +#define DWGCTRL_OPCODE_MASK (0xf << 0) +#define DWGCTRL_OPCODE_LINE_OPEN (0x0 << 0) +#define DWGCTRL_OPCODE_AUTOLINE_OPEN (0x1 << 0) +#define DWGCTRL_OPCODE_AUTOLINE_CLOSE (0x3 << 0) +#define DWGCTRL_OPCODE_TRAP (0x4 << 0) +#define DWGCTRL_OPCODE_TEXTURE_TRAP (0x6 << 0) +#define DWGCTRL_OPCODE_ILOAD_HIGH (0x7 << 0) +#define DWGCTRL_OPCODE_BITBLT (0x8 << 0) +#define DWGCTRL_OPCODE_ILOAD (0x9 << 0) +#define DWGCTRL_OPCODE_IDUMP (0xa << 0) +#define DWGCTRL_OPCODE_ILOAD_SCALE (0xd << 0) +#define DWGCTRL_OPCODE_ILOAD_HIGHV (0xe << 0) +#define DWGCTRL_OPCODE_ILOAD_FILTER (0xf << 0) /* Not implemented. */ +#define DWGCTRL_ATYPE_MASK (7 << 4) +#define DWGCTRL_ATYPE_RPL (0 << 4) +#define DWGCTRL_ATYPE_RSTR (1 << 4) +#define DWGCTRL_ATYPE_ZI (3 << 4) +#define DWGCTRL_ATYPE_BLK (4 << 4) +#define DWGCTRL_ATYPE_I (7 << 4) +#define DWGCTRL_LINEAR (1 << 7) +#define DWGCTRL_ZMODE_MASK (7 << 8) +#define DWGCTRL_ZMODE_NOZCMP (0 << 8) +#define DWGCTRL_ZMODE_ZE (2 << 8) +#define DWGCTRL_ZMODE_ZNE (3 << 8) +#define DWGCTRL_ZMODE_ZLT (4 << 8) +#define DWGCTRL_ZMODE_ZLTE (5 << 8) +#define DWGCTRL_ZMODE_ZGT (6 << 8) +#define DWGCTRL_ZMODE_ZGTE (7 << 8) +#define DWGCTRL_SOLID (1 << 11) +#define DWGCTRL_ARZERO (1 << 12) +#define DWGCTRL_SGNZERO (1 << 13) +#define DWGCTRL_SHTZERO (1 << 14) +#define DWGCTRL_BOP_MASK (0xf << 16) +#define DWGCTRL_TRANS_SHIFT (20) +#define DWGCTRL_TRANS_MASK (0xf << DWGCTRL_TRANS_SHIFT) +#define DWGCTRL_BLTMOD_MASK (0xf << 25) +#define DWGCTRL_BLTMOD_BMONOLEF (0x0 << 25) +#define DWGCTRL_BLTMOD_BFCOL (0x2 << 25) +#define DWGCTRL_BLTMOD_BMONOWF (0x4 << 25) +#define DWGCTRL_BLTMOD_BU32RGB (0x7 << 25) +#define DWGCTRL_BLTMOD_BUYUV (0xe << 25) +#define DWGCTRL_BLTMOD_BU24RGB (0xf << 25) +#define DWGCTRL_PATTERN (1 << 29) +#define DWGCTRL_TRANSC (1 << 30) +#define BOP(x) ((x) << 16) + +#define MACCESS_PWIDTH_MASK (3 << 0) +#define MACCESS_PWIDTH_8 (0 << 0) +#define MACCESS_PWIDTH_16 (1 << 0) +#define MACCESS_PWIDTH_32 (2 << 0) +#define MACCESS_PWIDTH_24 (3 << 0) +#define MACCESS_TLUTLOAD (1 << 29) +#define MACCESS_NODITHER (1 << 30) +#define MACCESS_DIT555 (1 << 31) + +#define PITCH_MASK 0x7e0 +#define PITCH_YLIN (1 << 15) + +#define SGN_SDYDXL (1 << 0) +#define SGN_SCANLEFT (1 << 0) +#define SGN_SDXL (1 << 1) +#define SGN_SDY (1 << 2) +#define SGN_SDXR (1 << 5) + +#define DMA_ADDR_MASK 0xfffffffc +#define DMA_MODE_MASK 3 + +#define DMA_MODE_REG 0 +#define DMA_MODE_BLIT 1 +#define DMA_MODE_VECTOR 2 + +#define STATUS_SOFTRAPEN (1 << 0) +#define STATUS_VLINEPEN (1 << 5) +#define STATUS_DWGENGSTS (1 << 16) +#define STATUS_ENDPRDMASTS (1 << 17) + +#define ICLEAR_SOFTRAPICLR (1 << 0) +#define ICLEAR_VLINEICLR (1 << 5) + +#define IEN_SOFTRAPEN (1 << 0) + +#define TEXCTL_TEXFORMAT_MASK (7 << 0) +#define TEXCTL_TEXFORMAT_TW4 (0 << 0) +#define TEXCTL_TEXFORMAT_TW8 (1 << 0) +#define TEXCTL_TEXFORMAT_TW15 (2 << 0) +#define TEXCTL_TEXFORMAT_TW16 (3 << 0) +#define TEXCTL_TEXFORMAT_TW12 (4 << 0) +#define TEXCTL_PALSEL_MASK (0xf << 4) +#define TEXCTL_TPITCH_SHIFT (16) +#define TEXCTL_TPITCH_MASK (7 << TEXCTL_TPITCH_SHIFT) +#define TEXCTL_NPCEN (1 << 21) +#define TEXCTL_DECALCKEY (1 << 24) +#define TEXCTL_TAKEY (1 << 25) +#define TEXCTL_TAMASK (1 << 26) +#define TEXCTL_CLAMPV (1 << 27) +#define TEXCTL_CLAMPU (1 << 28) +#define TEXCTL_TMODULATE (1 << 29) +#define TEXCTL_STRANS (1 << 30) +#define TEXCTL_ITRANS (1 << 31) + +#define TEXHEIGHT_TH_MASK (0x3f << 0) +#define TEXHEIGHT_THMASK_SHIFT (18) +#define TEXHEIGHT_THMASK_MASK (0x7ff << TEXHEIGHT_THMASK_SHIFT) + +#define TEXWIDTH_TW_MASK (0x3f << 0) +#define TEXWIDTH_TWMASK_SHIFT (18) +#define TEXWIDTH_TWMASK_MASK (0x7ff << TEXWIDTH_TWMASK_SHIFT) + +#define TEXTRANS_TCKEY_MASK (0xffff) +#define TEXTRANS_TKMASK_SHIFT (16) +#define TEXTRANS_TKMASK_MASK (0xffff << TEXTRANS_TKMASK_SHIFT) + +#define DITHER_565 0 +#define DITHER_NONE_565 1 +#define DITHER_555 2 +#define DITHER_NONE_555 3 + + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_CTRL_BYTE = (0x01 << 24), + FIFO_WRITE_CTRL_LONG = (0x02 << 24), + FIFO_WRITE_ILOAD_LONG = (0x03 << 24) +}; + +enum +{ + DMA_STATE_IDLE = 0, + DMA_STATE_PRI, + DMA_STATE_SEC +}; + + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct mystique_t +{ + svga_t svga; + + rom_t bios_rom; + + mem_mapping_t lfb_mapping, ctrl_mapping, + iload_mapping; + + uint8_t int_line, xcurctrl, + xsyspllm, xsysplln, xsyspllp, + xgenioctrl, xgeniodata, + xmulctrl, xgenctrl, + xmiscctrl, xpixclkctrl, + xvrefctrl, ien, dmamod, + dmadatasiz, dirdatasiz; + + uint8_t pci_regs[256], crtcext_regs[6], + xreg_regs[256], dmamap[16]; + + int card, vram_size, crtcext_idx, xreg_idx, + xzoomctrl, + pixel_count, trap_count; + + volatile int busy, blitter_submit_refcount, + blitter_submit_dma_refcount, blitter_complete_refcount, + endprdmasts_pending, softrap_pending, + fifo_read_idx, fifo_write_idx; + + uint32_t vram_mask, vram_mask_w, vram_mask_l, + lfb_base, ctrl_base, iload_base, + ma_latch_old, maccess, mctlwtst, maccess_running, + status, softrap_pending_val; + + uint64_t blitter_time, status_time; + + pc_timer_t softrap_pending_timer, wake_timer; + + fifo_entry_t fifo[FIFO_SIZE]; + + thread_t *fifo_thread; + + event_t *wake_fifo_thread, *fifo_not_full_event; + + struct + { + int m, n, p, s; + } xpixpll[3]; + + struct + { + uint8_t funcnt, stylelen, + dmamod; + + int16_t fxleft, fxright, + xdst; + + uint16_t cxleft, cxright, + length; + + int xoff, yoff, selline, ydst, + length_cur, iload_rem_count, idump_end_of_line, words, + ta_key, ta_mask, lastpix_r, lastpix_g, + lastpix_b, highv_line, beta, dither; + + int pattern[8][8]; + + uint32_t dwgctrl, dwgctrl_running, bcol, fcol, + pitch, plnwt, ybot, ydstorg, + ytop, texorg, texwidth, texheight, + texctl, textrans, zorg, ydst_lin, + src_addr, z_base, iload_rem_data, highv_data; + + uint32_t src[4], ar[7], + dr[16], tmr[9]; + + struct + { + int sdydxl, scanleft, sdxl, sdy, + sdxr; + } sgn; + } dwgreg; + + struct + { + uint8_t r, g, b; + } lut[256]; + + struct + { + uint16_t pos_x, pos_y, + addr; + uint32_t col[3]; + } cursor; + + struct + { + int pri_pos, sec_pos, iload_pos, + pri_state, sec_state, iload_state, state; + + uint32_t primaddress, primend, secaddress, secend, + pri_header, sec_header, + iload_header; + + mutex_t *lock; + } dma; +} mystique_t; + + +static const uint8_t trans_masks[16][16] = +{ + { + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1 + }, + { + 1, 0, 1, 0, + 0, 1, 0, 1, + 1, 0, 1, 0, + 0, 1, 0, 1 + }, + { + 0, 1, 0, 1, + 1, 0, 1, 0, + 0, 1, 0, 1, + 1, 0, 1, 0 + }, + { + 1, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 1, 0, + 0, 0, 0, 0 + }, + { + 0, 1, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 1, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 1, 0 + }, + { + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 1 + }, + { + 1, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 0 + }, + { + 0, 1, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 0 + }, + { + 0, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + } +}; + + +static int8_t dither5[256][2][2]; +static int8_t dither6[256][2][2]; + +static video_timings_t timing_matrox_mystique = {VIDEO_BUS, 4, 4, 4, 10, 10, 10}; + + +static void mystique_start_blit(mystique_t *mystique); +static void mystique_update_irqs(mystique_t *mystique); + +static void wake_fifo_thread(mystique_t *mystique); +static void wait_fifo_idle(mystique_t *mystique); +static void mystique_queue(mystique_t *mystique, uint32_t addr, uint32_t val, uint32_t type); + +static void mystique_recalc_mapping(mystique_t *mystique); +static int mystique_line_compare(svga_t *svga); + +static uint8_t mystique_iload_read_b(uint32_t addr, void *p); +static uint32_t mystique_iload_read_l(uint32_t addr, void *p); +static void mystique_iload_write_b(uint32_t addr, uint8_t val, void *p); +static void mystique_iload_write_l(uint32_t addr, uint32_t val, void *p); + +static uint32_t blit_idump_read(mystique_t *mystique); +static void blit_iload_write(mystique_t *mystique, uint32_t data, int size); + + +void +mystique_out(uint16_t addr, uint8_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + svga_t *svga = &mystique->svga; + uint8_t old; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c8: + mystique->xreg_idx = val; + break; + + case 0x3cf: + if ((svga->gdcaddr & 15) == 6 && svga->gdcreg[6] != val) { + svga->gdcreg[svga->gdcaddr & 15] = val; + mystique_recalc_mapping(mystique); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (((svga->crtcreg & 31) < 7) && (svga->crtc[0x11] & 0x80)) + return; + if (((svga->crtcreg & 31) == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg & 0x3f]; + svga->crtc[svga->crtcreg & 31] = val; + if (old != val) { + if ((svga->crtcreg & 31) < 0xE || (svga->crtcreg & 31) > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x3de: + mystique->crtcext_idx = val; + break; + case 0x3df: + if (mystique->crtcext_idx < 6) + mystique->crtcext_regs[mystique->crtcext_idx] = val; + if (mystique->crtcext_idx < 4) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + if (mystique->crtcext_idx == 3) { + if (val & CRTCX_R3_MGAMODE) + svga->fb_only = 1; + else + svga->fb_only = 0; + svga_recalctimings(svga); + } + if (mystique->crtcext_idx == 4) { + if (svga->gdcreg[6] & 0xc) { + /*64k banks*/ + svga->read_bank = (val & 0x7f) << 16; + svga->write_bank = (val & 0x7f) << 16; + } else { + /*128k banks*/ + svga->read_bank = (val & 0x7e) << 16; + svga->write_bank = (val & 0x7e) << 16; + } + } + break; + } + + svga_out(addr, val, svga); +} + + +uint8_t +mystique_in(uint16_t addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + svga_t *svga = &mystique->svga; + uint8_t temp = 0xff; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg & 0x3f]; + break; + + case 0x3df: + if (mystique->crtcext_idx < 6) + temp = mystique->crtcext_regs[mystique->crtcext_idx]; + break; + + default: + temp = svga_in(addr, svga); + break; + } + + return temp; +} + + +static int +mystique_line_compare(svga_t *svga) +{ + mystique_t *mystique = (mystique_t *)svga->p; + + mystique->status |= STATUS_VLINEPEN; + mystique_update_irqs(mystique); + + return 0; +} + + +void +mystique_recalctimings(svga_t *svga) +{ + mystique_t *mystique = (mystique_t *)svga->p; + int clk_sel = (svga->miscout >> 2) & 3; + + if (clk_sel & 2) { + int m = mystique->xpixpll[2].m; + int n = mystique->xpixpll[2].n; + int p = mystique->xpixpll[2].p; + + double fvco = 14318181.0 * (n + 1) / (m + 1); + double fo = fvco / (p + 1); + + svga->clock = (cpuclock * (float)(1ull << 32)) / fo; + } + + if (mystique->crtcext_regs[1] & CRTCX_R1_HTOTAL8) + svga->htotal += 0x100; + if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL10) + svga->vtotal += 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL11) + svga->vtotal += 0x800; + if (mystique->crtcext_regs[2] & CRTCX_R2_VDISPEND10) + svga->dispend += 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VBLKSTR10) + svga->vblankstart += 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VBLKSTR11) + svga->vblankstart += 0x800; + if (mystique->crtcext_regs[2] & CRTCX_R2_VSYNCSTR10) + svga->vsyncstart += 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VSYNCSTR11) + svga->vsyncstart += 0x800; + if (mystique->crtcext_regs[2] & CRTCX_R2_LINECOMP10) + svga->split += 0x400; + + svga->interlace = !!(mystique->crtcext_regs[0] & 0x80); + + if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) { + int row_offset = svga->crtc[0x13] | ((mystique->crtcext_regs[0] & CRTCX_R0_OFFSET_MASK) << 4); + + svga->lowres = 0; + if (svga->interlace) + svga->rowoffset = row_offset; + else + svga->rowoffset = row_offset * 2; + svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 17) | + (svga->crtc[0xc] << 9) | (svga->crtc[0xd] << 1); + + /*Mystique, unlike most SVGA cards, allows display start to take + effect mid-screen*/ + if (svga->ma_latch != mystique->ma_latch_old) { + if (svga->interlace && svga->oddeven) + svga->ma = svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + (svga->ma_latch << 2) + (svga->rowoffset << 1); + else + svga->ma = svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + (svga->ma_latch << 2); + mystique->ma_latch_old = svga->ma_latch; + } + + switch (mystique->xmulctrl & XMULCTRL_DEPTH_MASK) { + case XMULCTRL_DEPTH_8: + case XMULCTRL_DEPTH_2G8V16: + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + break; + case XMULCTRL_DEPTH_15: + case XMULCTRL_DEPTH_G16V16: + svga->render = svga_render_15bpp_highres; + svga->bpp = 15; + break; + case XMULCTRL_DEPTH_16: + svga->render = svga_render_16bpp_highres; + svga->bpp = 16; + break; + case XMULCTRL_DEPTH_24: + svga->render = svga_render_24bpp_highres; + svga->bpp = 24; + break; + case XMULCTRL_DEPTH_32: + case XMULCTRL_DEPTH_32_OVERLAYED: + svga->render = svga_render_32bpp_highres; + svga->bpp = 32; + break; + } + + svga->line_compare = mystique_line_compare; + } else { + svga->line_compare = NULL; + svga->bpp = 8; + } +} + + +static +void mystique_recalc_mapping(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + + io_removehandler(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); + if ((mystique->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (mystique->pci_regs[0x41] & 1)) + io_sethandler(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); + + if (!(mystique->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&mystique->ctrl_mapping); + mem_mapping_disable(&mystique->lfb_mapping); + mem_mapping_disable(&mystique->iload_mapping); + return; + } + + if (mystique->ctrl_base) + mem_mapping_set_addr(&mystique->ctrl_mapping, mystique->ctrl_base, 0x4000); + else + mem_mapping_disable(&mystique->ctrl_mapping); + + if (mystique->lfb_base) + mem_mapping_set_addr(&mystique->lfb_mapping, mystique->lfb_base, 0x800000); + else + mem_mapping_disable(&mystique->lfb_mapping); + + if (mystique->iload_base) + mem_mapping_set_addr(&mystique->iload_mapping, mystique->iload_base, 0x800000); + else + mem_mapping_disable(&mystique->iload_mapping); + + if (mystique->pci_regs[0x41] & 1) { + switch (svga->gdcreg[6] & 0x0C) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0x1ffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + if (svga->gdcreg[6] & 0xc) { + /*64k banks*/ + svga->read_bank = (mystique->crtcext_regs[4] & 0x7f) << 16; + svga->write_bank = (mystique->crtcext_regs[4] & 0x7f) << 16; + } else { + /*128k banks*/ + svga->read_bank = (mystique->crtcext_regs[4] & 0x7e) << 16; + svga->write_bank = (mystique->crtcext_regs[4] & 0x7e) << 16; + } + } else + mem_mapping_disable(&svga->mapping); +} + + +static void +mystique_update_irqs(mystique_t *mystique) +{ + int irq = 0; + + if ((mystique->status & mystique->ien) & STATUS_SOFTRAPEN) + irq = 1; + + if (irq) + pci_set_irq(mystique->card, PCI_INTA); + else + pci_clear_irq(mystique->card, PCI_INTA); +} + + +#define READ8(addr, var) switch ((addr) & 3) { \ + case 0: ret = (var) & 0xff; break; \ + case 1: ret = ((var) >> 8) & 0xff; break; \ + case 2: ret = ((var) >> 16) & 0xff; break; \ + case 3: ret = ((var) >> 24) & 0xff; break; \ + } + +#define WRITE8(addr, var, val) switch ((addr) & 3) { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + + +static uint8_t +mystique_read_xreg(mystique_t *mystique, int reg) +{ + uint8_t ret = 0xff; + + switch (reg) { + case XREG_XCURADDL: + ret = mystique->cursor.addr & 0xff; + break; + case XREG_XCURADDH: + ret = mystique->cursor.addr >> 8; + break; + case XREG_XCURCTRL: + ret = mystique->xcurctrl; + break; + + case XREG_XCURCOL0R: case XREG_XCURCOL0G: case XREG_XCURCOL0B: + READ8(reg, mystique->cursor.col[0]); + break; + case XREG_XCURCOL1R: case XREG_XCURCOL1G: case XREG_XCURCOL1B: + READ8(reg, mystique->cursor.col[1]); + break; + case XREG_XCURCOL2R: case XREG_XCURCOL2G: case XREG_XCURCOL2B: + READ8(reg, mystique->cursor.col[2]); + break; + + case XREG_XMULCTRL: + ret = mystique->xmulctrl; + break; + + case XREG_XMISCCTRL: + ret = mystique->xmiscctrl; + break; + + case XREG_XGENCTRL: + ret = mystique->xgenctrl; + break; + + case XREG_XGENIOCTRL: + ret = mystique->xgenioctrl; + break; + case XREG_XGENIODATA: + ret = mystique->xgeniodata; + break; + + case XREG_XSYSPLLM: + ret = mystique->xsyspllm; + break; + case XREG_XSYSPLLN: + ret = mystique->xsysplln; + break; + case XREG_XSYSPLLP: + ret = mystique->xsyspllp; + break; + + case XREG_XZOOMCTRL: + ret = mystique->xzoomctrl; + break; + + case XREG_XPIXCLKCTRL: + ret = mystique->xpixclkctrl; + break; + + case XREG_XSYSPLLSTAT: + ret = XSYSPLLSTAT_SYSLOCK; + break; + + case XREG_XPIXPLLSTAT: + ret = XPIXPLLSTAT_SYSLOCK; + break; + + case XREG_XPIXPLLCM: + ret = mystique->xpixpll[2].m; + break; + case XREG_XPIXPLLCN: + ret = mystique->xpixpll[2].n; + break; + case XREG_XPIXPLLCP: + ret = mystique->xpixpll[2].p | (mystique->xpixpll[2].s << 3); + break; + + case 0x00: case 0x20: case 0x3f: + ret = 0xff; + break; + + default: + if (reg >= 0x50) + ret = 0xff; + break; + } + + return ret; +} + + +static void +mystique_write_xreg(mystique_t *mystique, int reg, uint8_t val) +{ + svga_t *svga = &mystique->svga; + + switch (reg) { + case XREG_XCURADDL: + mystique->cursor.addr = (mystique->cursor.addr & 0x1f00) | val; + svga->hwcursor.addr = mystique->cursor.addr << 10; + break; + case XREG_XCURADDH: + mystique->cursor.addr = (mystique->cursor.addr & 0x00ff) | ((val & 0x1f) << 8); + svga->hwcursor.addr = mystique->cursor.addr << 10; + break; + + case XREG_XCURCTRL: + mystique->xcurctrl = val; + svga->hwcursor.ena = (val & 3) ? 1 : 0; + break; + + case XREG_XCURCOL0R: case XREG_XCURCOL0G: case XREG_XCURCOL0B: + WRITE8(reg, mystique->cursor.col[0], val); + break; + case XREG_XCURCOL1R: case XREG_XCURCOL1G: case XREG_XCURCOL1B: + WRITE8(reg, mystique->cursor.col[1], val); + break; + case XREG_XCURCOL2R: case XREG_XCURCOL2G: case XREG_XCURCOL2B: + WRITE8(reg, mystique->cursor.col[2], val); + break; + + case XREG_XMULCTRL: + mystique->xmulctrl = val; + break; + + case XREG_XMISCCTRL: + mystique->xmiscctrl = val; + svga_set_ramdac_type(svga, (val & XMISCCTRL_VGA8DAC) ? RAMDAC_8BIT : RAMDAC_6BIT); + break; + + case XREG_XGENCTRL: + mystique->xgenctrl = val; + break; + + case XREG_XVREFCTRL: + mystique->xvrefctrl = val; + break; + + case XREG_XGENIOCTRL: + mystique->xgenioctrl = val; + break; + case XREG_XGENIODATA: + mystique->xgeniodata = val; + break; + + case XREG_XSYSPLLM: + mystique->xsyspllm = val; + break; + case XREG_XSYSPLLN: + mystique->xsysplln = val; + break; + case XREG_XSYSPLLP: + mystique->xsyspllp = val; + break; + + case XREG_XZOOMCTRL: + mystique->xzoomctrl = val & 3; + break; + + case XREG_XPIXCLKCTRL: + mystique->xpixclkctrl = val; + break; + + case XREG_XPIXPLLCM: + mystique->xpixpll[2].m = val; + break; + case XREG_XPIXPLLCN: + mystique->xpixpll[2].n = val; + break; + case XREG_XPIXPLLCP: + mystique->xpixpll[2].p = val & 7; + mystique->xpixpll[2].s = (val >> 3) & 3; + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x07: case 0x0b: case 0x0f: + case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1b: case 0x1c: case 0x20: case 0x39: case 0x3b: case 0x3f: + case 0x47: case 0x4b: + break; + + default: + break; + } +} + + +static uint8_t +mystique_ctrl_read_b(uint32_t addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + svga_t *svga = &mystique->svga; + uint8_t ret = 0xff; + int fifocount; + + switch (addr & 0x3fff) { + case REG_FIFOSTATUS: + fifocount = FIFO_SIZE - FIFO_ENTRIES; + if (fifocount > 64) + fifocount = 64; + ret = fifocount; + break; + case REG_FIFOSTATUS+1: + if (FIFO_EMPTY) + ret |= 2; + else if (FIFO_ENTRIES >= 64) + ret |= 1; + break; + case REG_FIFOSTATUS+2: case REG_FIFOSTATUS+3: + ret = 0; + break; + + case REG_STATUS: + ret = mystique->status & 0xff; + if (svga->cgastat & 8) + ret |= REG_STATUS_VSYNCSTS; + break; + case REG_STATUS+1: + ret = (mystique->status >> 8) & 0xff; + break; + case REG_STATUS+2: + ret = (mystique->status >> 16) & 0xff; + if (mystique->busy || + ((mystique->blitter_submit_refcount + mystique->blitter_submit_dma_refcount) != mystique->blitter_complete_refcount) || + !FIFO_EMPTY) + ret |= (STATUS_DWGENGSTS >> 16); + break; + case REG_STATUS+3: + ret = (mystique->status >> 24) & 0xff; + break; + + case REG_IEN: + ret = mystique->ien & 0x64; + break; + case REG_IEN+1: case REG_IEN+2: case REG_IEN+3: + ret = 0; + break; + + case REG_OPMODE: + ret = mystique->dmamod << 2; + break; + case REG_OPMODE+1: + ret = mystique->dmadatasiz; + break; + case REG_OPMODE+2: + ret = mystique->dirdatasiz; + break; + case REG_OPMODE+3: + break; + + case REG_PRIMADDRESS: case REG_PRIMADDRESS+1: case REG_PRIMADDRESS+2: case REG_PRIMADDRESS+3: + READ8(addr, mystique->dma.primaddress); + break; + case REG_PRIMEND: case REG_PRIMEND+1: case REG_PRIMEND+2: case REG_PRIMEND+3: + READ8(addr, mystique->dma.primend); + break; + + case REG_SECADDRESS: case REG_SECADDRESS+1: case REG_SECADDRESS+2: case REG_SECADDRESS+3: + READ8(addr, mystique->dma.secaddress); + break; + + case REG_VCOUNT: case REG_VCOUNT+1: case REG_VCOUNT+2: case REG_VCOUNT+3: + READ8(addr, svga->vc); + break; + + case REG_INSTS0: + ret = svga_in(0x3c2, svga); + break; + + case REG_SEQ_IDX: + ret = svga_in(0x3c4, svga); + break; + case REG_SEQ_DATA: + ret = svga_in(0x3c5, svga); + break; + + case REG_MISCREAD: + ret = svga_in(0x3cc, svga); + break; + + case REG_CRTC_IDX: + ret = mystique_in(0x3d4, mystique); + break; + case REG_CRTC_DATA: + ret = mystique_in(0x3d5, mystique); + break; + + case REG_INSTS1: + ret = mystique_in(0x3da, mystique); + break; + + case REG_CRTCEXT_IDX: + ret = mystique_in(0x3de, mystique); + break; + case REG_CRTCEXT_DATA: + ret = mystique_in(0x3df, mystique); + break; + + case REG_PALWTADD: + ret = svga_in(0x3c8, svga); + break; + case REG_PALDATA: + ret = svga_in(0x3c9, svga); + break; + case REG_PIXRDMSK: + ret = svga_in(0x3c6, svga); + break; + case REG_PALRDADD: + ret = svga_in(0x3c7, svga); + break; + + case REG_X_DATAREG: + ret = mystique_read_xreg(mystique, mystique->xreg_idx); + break; + + case REG_ICLEAR: case REG_ICLEAR+1: case REG_ICLEAR+2: case REG_ICLEAR+3: + case 0x2c30: case 0x2c31: case 0x2c32: case 0x2c33: + case 0x3e08: + break; + + default: + if ((addr & 0x3fff) >= 0x2c00 && (addr & 0x3fff) < 0x2c40) + break; + break; + } + + return ret; +} + + +static void +mystique_accel_ctrl_write_b(uint32_t addr, uint8_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + int start_blit = 0; + int x; + + if ((addr & 0x300) == 0x100) { + addr &= ~0x100; + start_blit = 1; + } + + switch (addr & 0x3fff) { + case REG_MACCESS: case REG_MACCESS+1: case REG_MACCESS+2: case REG_MACCESS+3: + WRITE8(addr, mystique->maccess, val); + mystique->dwgreg.dither = mystique->maccess >> 30; + break; + + case REG_MCTLWTST: case REG_MCTLWTST+1: case REG_MCTLWTST+2: case REG_MCTLWTST+3: + WRITE8(addr, mystique->mctlwtst, val); + break; + + case REG_PAT0: case REG_PAT0+1: case REG_PAT0+2: case REG_PAT0+3: + case REG_PAT1: case REG_PAT1+1: case REG_PAT1+2: case REG_PAT1+3: + for (x = 0; x < 8; x++) + mystique->dwgreg.pattern[addr & 7][x] = val & (1 << (7-x)); + break; + + case REG_XYSTRT: case REG_XYSTRT+1: + WRITE8(addr&1, mystique->dwgreg.ar[5], val); + if (mystique->dwgreg.ar[5] & 0x8000) + mystique->dwgreg.ar[5] |= 0xffff8000; + else + mystique->dwgreg.ar[5] &= ~0xffff8000; + WRITE8(addr&1, mystique->dwgreg.xdst, val); + break; + case REG_XYSTRT+2: case REG_XYSTRT+3: + WRITE8(addr & 1, mystique->dwgreg.ar[6], val); + if (mystique->dwgreg.ar[6] & 0x8000) + mystique->dwgreg.ar[6] |= 0xffff8000; + else + mystique->dwgreg.ar[6] &= ~0xffff8000; + WRITE8(addr & 1, mystique->dwgreg.ydst, val); + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + break; + + case REG_XYEND: case REG_XYEND+1: + WRITE8(addr&1, mystique->dwgreg.ar[0], val); + if (mystique->dwgreg.ar[0] & 0x8000) + mystique->dwgreg.ar[0] |= 0xffff8000; + else + mystique->dwgreg.ar[0] &= ~0xffff8000; + break; + case REG_XYEND+2: case REG_XYEND+3: + WRITE8(addr & 1, mystique->dwgreg.ar[2], val); + if (mystique->dwgreg.ar[2] & 0x8000) + mystique->dwgreg.ar[2] |= 0xffff8000; + else + mystique->dwgreg.ar[2] &= ~0xffff8000; + break; + + case REG_SGN: + mystique->dwgreg.sgn.sdydxl = val & SGN_SDYDXL; + mystique->dwgreg.sgn.scanleft = val & SGN_SCANLEFT; + mystique->dwgreg.sgn.sdxl = val & SGN_SDXL; + mystique->dwgreg.sgn.sdy = val & SGN_SDY; + mystique->dwgreg.sgn.sdxr = val & SGN_SDXR; + break; + case REG_SGN+1: case REG_SGN+2: case REG_SGN+3: + break; + + case REG_LEN: case REG_LEN+1: + WRITE8(addr, mystique->dwgreg.length, val); + break; + case REG_LEN+2: + break; + case REG_LEN+3: + mystique->dwgreg.beta = val >> 4; + if (!mystique->dwgreg.beta) + mystique->dwgreg.beta = 16; + break; + + case REG_CXBNDRY: case REG_CXBNDRY+1: + WRITE8(addr, mystique->dwgreg.cxleft, val); + break; + case REG_CXBNDRY+2: case REG_CXBNDRY+3: + WRITE8(addr & 1, mystique->dwgreg.cxright, val); + break; + case REG_FXBNDRY: case REG_FXBNDRY+1: + WRITE8(addr, mystique->dwgreg.fxleft, val); + break; + case REG_FXBNDRY+2: case REG_FXBNDRY+3: + WRITE8(addr & 1, mystique->dwgreg.fxright, val); + break; + + case REG_YDSTLEN: case REG_YDSTLEN+1: + WRITE8(addr, mystique->dwgreg.length, val); + /* pclog("Write YDSTLEN+%i %i\n", addr&1, mystique->dwgreg.length); */ + break; + case REG_YDSTLEN+2: + mystique->dwgreg.ydst = (mystique->dwgreg.ydst & ~0xff) | val; + if (mystique->dwgreg.pitch & PITCH_YLIN) + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + else { + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + mystique->dwgreg.selline = val & 7; + } + break; + case REG_YDSTLEN+3: + mystique->dwgreg.ydst = (mystique->dwgreg.ydst & 0xff) | (((int32_t)(int8_t)val) << 8); + if (mystique->dwgreg.pitch & PITCH_YLIN) + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + else + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + break; + + case REG_XDST: case REG_XDST+1: + WRITE8(addr & 1, mystique->dwgreg.xdst, val); + break; + case REG_XDST+2: case REG_XDST+3: + break; + + case REG_YDSTORG: case REG_YDSTORG+1: case REG_YDSTORG+2: case REG_YDSTORG+3: + WRITE8(addr, mystique->dwgreg.ydstorg, val); + mystique->dwgreg.z_base = mystique->dwgreg.ydstorg*2 + mystique->dwgreg.zorg; + break; + case REG_YTOP: case REG_YTOP+1: case REG_YTOP+2: case REG_YTOP+3: + WRITE8(addr, mystique->dwgreg.ytop, val); + break; + case REG_YBOT: case REG_YBOT+1: case REG_YBOT+2: case REG_YBOT+3: + WRITE8(addr, mystique->dwgreg.ybot, val); + break; + + case REG_CXLEFT: case REG_CXLEFT+1: + WRITE8(addr, mystique->dwgreg.cxleft, val); + break; + case REG_CXLEFT+2: case REG_CXLEFT+3: + break; + case REG_CXRIGHT: case REG_CXRIGHT+1: + WRITE8(addr, mystique->dwgreg.cxright, val); + break; + case REG_CXRIGHT+2: case REG_CXRIGHT+3: + break; + + case REG_FXLEFT: case REG_FXLEFT+1: + WRITE8(addr, mystique->dwgreg.fxleft, val); + break; + case REG_FXLEFT+2: case REG_FXLEFT+3: + break; + case REG_FXRIGHT: case REG_FXRIGHT+1: + WRITE8(addr, mystique->dwgreg.fxright, val); + break; + case REG_FXRIGHT+2: case REG_FXRIGHT+3: + break; + + case REG_SECADDRESS: case REG_SECADDRESS+1: case REG_SECADDRESS+2: case REG_SECADDRESS+3: + WRITE8(addr, mystique->dma.secaddress, val); + mystique->dma.sec_state = 0; + break; + + case REG_TMR0: case REG_TMR0+1: case REG_TMR0+2: case REG_TMR0+3: + WRITE8(addr, mystique->dwgreg.tmr[0], val); + break; + case REG_TMR1: case REG_TMR1+1: case REG_TMR1+2: case REG_TMR1+3: + WRITE8(addr, mystique->dwgreg.tmr[1], val); + break; + case REG_TMR2: case REG_TMR2+1: case REG_TMR2+2: case REG_TMR2+3: + WRITE8(addr, mystique->dwgreg.tmr[2], val); + break; + case REG_TMR3: case REG_TMR3+1: case REG_TMR3+2: case REG_TMR3+3: + WRITE8(addr, mystique->dwgreg.tmr[3], val); + break; + case REG_TMR4: case REG_TMR4+1: case REG_TMR4+2: case REG_TMR4+3: + WRITE8(addr, mystique->dwgreg.tmr[4], val); + break; + case REG_TMR5: case REG_TMR5+1: case REG_TMR5+2: case REG_TMR5+3: + WRITE8(addr, mystique->dwgreg.tmr[5], val); + break; + case REG_TMR6: case REG_TMR6+1: case REG_TMR6+2: case REG_TMR6+3: + WRITE8(addr, mystique->dwgreg.tmr[6], val); + break; + case REG_TMR7: case REG_TMR7+1: case REG_TMR7+2: case REG_TMR7+3: + WRITE8(addr, mystique->dwgreg.tmr[7], val); + break; + case REG_TMR8: case REG_TMR8+1: case REG_TMR8+2: case REG_TMR8+3: + WRITE8(addr, mystique->dwgreg.tmr[8], val); + break; + + case REG_TEXORG: case REG_TEXORG+1: case REG_TEXORG+2: case REG_TEXORG+3: + WRITE8(addr, mystique->dwgreg.texorg, val); + break; + case REG_TEXWIDTH: case REG_TEXWIDTH+1: case REG_TEXWIDTH+2: case REG_TEXWIDTH+3: + WRITE8(addr, mystique->dwgreg.texwidth, val); + break; + case REG_TEXHEIGHT: case REG_TEXHEIGHT+1: case REG_TEXHEIGHT+2: case REG_TEXHEIGHT+3: + WRITE8(addr, mystique->dwgreg.texheight, val); + break; + case REG_TEXCTL: case REG_TEXCTL+1: case REG_TEXCTL+2: case REG_TEXCTL+3: + WRITE8(addr, mystique->dwgreg.texctl, val); + mystique->dwgreg.ta_key = (mystique->dwgreg.texctl & TEXCTL_TAKEY) ? 1 : 0; + mystique->dwgreg.ta_mask = (mystique->dwgreg.texctl & TEXCTL_TAMASK) ? 1 : 0; + break; + case REG_TEXTRANS: case REG_TEXTRANS+1: case REG_TEXTRANS+2: case REG_TEXTRANS+3: + WRITE8(addr, mystique->dwgreg.textrans, val); + break; + + case 0x1c28: case 0x1c29: case 0x1c2a: case 0x1c2b: + case 0x1c2c: case 0x1c2d: case 0x1c2e: case 0x1c2f: + case 0x1cc4: case 0x1cc5: case 0x1cc6: case 0x1cc7: + case 0x1cd4: case 0x1cd5: case 0x1cd6: case 0x1cd7: + case 0x1ce4: case 0x1ce5: case 0x1ce6: case 0x1ce7: + case 0x1cf4: case 0x1cf5: case 0x1cf6: case 0x1cf7: + break; + + case REG_OPMODE: + mystique->dwgreg.dmamod = (val >> 2) & 3; + mystique->dma.iload_state = 0; + break; + + default: + if ((addr & 0x3fff) >= 0x2c4c && (addr & 0x3fff) <= 0x2cff) + break; + break; + } + + if (start_blit) + mystique_start_blit(mystique); +} + + +static void +mystique_ctrl_write_b(uint32_t addr, uint8_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + svga_t *svga = &mystique->svga; + + if ((addr & 0x3fff) < 0x1c00) { + mystique_iload_write_b(addr, val, p); + return; + } + if ((addr & 0x3e00) == 0x1c00 || (addr & 0x3e00) == 0x2c00) { + if ((addr & 0x300) == 0x100) + mystique->blitter_submit_refcount++; + mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_BYTE); + return; + } + + switch (addr & 0x3fff) { + case REG_ICLEAR: + if (val & ICLEAR_SOFTRAPICLR) { + mystique->status &= ~STATUS_SOFTRAPEN; + mystique_update_irqs(mystique); + } + if (val & ICLEAR_VLINEICLR) { + mystique->status &= ~STATUS_VLINEPEN; + mystique_update_irqs(mystique); + } + break; + case REG_ICLEAR+1: case REG_ICLEAR+2: case REG_ICLEAR+3: + break; + + case REG_IEN: + mystique->ien = val & 0x65; + break; + case REG_IEN+1: case REG_IEN+2: case REG_IEN+3: + break; + + case REG_OPMODE: + mystique->dmamod = (val >> 2) & 3; + mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_BYTE); + break; + case REG_OPMODE+1: + mystique->dmadatasiz = val & 3; + break; + case REG_OPMODE+2: + mystique->dirdatasiz = val & 3; + break; + case REG_OPMODE+3: + break; + + case REG_PRIMADDRESS: case REG_PRIMADDRESS+1: case REG_PRIMADDRESS+2: case REG_PRIMADDRESS+3: + thread_wait_mutex(mystique->dma.lock); + WRITE8(addr, mystique->dma.primaddress, val); + mystique->dma.pri_state = 0; + thread_release_mutex(mystique->dma.lock); + break; + + case REG_DMAMAP: case REG_DMAMAP+0x1: case REG_DMAMAP+0x2: case REG_DMAMAP+0x3: + case REG_DMAMAP+0x4: case REG_DMAMAP+0x5: case REG_DMAMAP+0x6: case REG_DMAMAP+0x7: + case REG_DMAMAP+0x8: case REG_DMAMAP+0x9: case REG_DMAMAP+0xa: case REG_DMAMAP+0xb: + case REG_DMAMAP+0xc: case REG_DMAMAP+0xd: case REG_DMAMAP+0xe: case REG_DMAMAP+0xf: + mystique->dmamap[addr & 0xf] = val; + break; + + case REG_RST: case REG_RST+1: case REG_RST+2: case REG_RST+3: + wait_fifo_idle(mystique); + mystique->busy = 0; + mystique->blitter_submit_refcount = 0; + mystique->blitter_submit_dma_refcount = 0; + mystique->blitter_complete_refcount = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->status = STATUS_ENDPRDMASTS; + break; + + case REG_MISC: + svga_out(0x3c2, val, svga); + break; + + case REG_SEQ_IDX: + svga_out(0x3c4, val, svga); + break; + case REG_SEQ_DATA: + svga_out(0x3c5, val, svga); + break; + + case REG_CRTC_IDX: + mystique_out(0x3d4, val, mystique); + break; + case REG_CRTC_DATA: + mystique_out(0x3d5, val, mystique); + break; + + case REG_CRTCEXT_IDX: + mystique_out(0x3de, val, mystique); + break; + case REG_CRTCEXT_DATA: + mystique_out(0x3df, val, mystique); + break; + + case REG_CACHEFLUSH: + break; + + case REG_PALWTADD: + svga_out(0x3c8, val, svga); + mystique->xreg_idx = val; + break; + case REG_PALDATA: + svga_out(0x3c9, val, svga); + break; + case REG_PIXRDMSK: + svga_out(0x3c6, val, svga); + break; + case REG_PALRDADD: + svga_out(0x3c7, val, svga); + break; + + case REG_X_DATAREG: + mystique_write_xreg(mystique, mystique->xreg_idx, val); + break; + + case REG_CURPOSX: case REG_CURPOSX+1: + WRITE8(addr, mystique->cursor.pos_x, val); + svga->hwcursor.x = mystique->cursor.pos_x - 64; + break; + case REG_CURPOSY: case REG_CURPOSY+1: + WRITE8(addr & 1, mystique->cursor.pos_y, val); + svga->hwcursor.y = mystique->cursor.pos_y - 64; + break; + + case 0x1e50: case 0x1e51: case 0x1e52: case 0x1e53: + case 0x3c0b: case 0x3e02: case 0x3e08: + break; + + default: + if ((addr & 0x3fff) >= 0x2c4c && (addr & 0x3fff) <= 0x2cff) + break; + break; + } +} + + +static uint32_t +mystique_ctrl_read_l(uint32_t addr, void *p) +{ + uint32_t ret; + + if ((addr & 0x3fff) < 0x1c00) + return mystique_iload_read_l(addr, p); + + ret = mystique_ctrl_read_b(addr, p); + ret |= mystique_ctrl_read_b(addr+1, p) << 8; + ret |= mystique_ctrl_read_b(addr+2, p) << 16; + ret |= mystique_ctrl_read_b(addr+3, p) << 24; + + return ret; +} + + +static void +mystique_accel_ctrl_write_l(uint32_t addr, uint32_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + int start_blit = 0; + + if ((addr & 0x300) == 0x100) { + addr &= ~0x100; + start_blit = 1; + } + + switch (addr & 0x3ffc) { + case REG_DWGCTL: + mystique->dwgreg.dwgctrl = val; + break; + + case REG_ZORG: + mystique->dwgreg.zorg = val; + mystique->dwgreg.z_base = mystique->dwgreg.ydstorg*2 + mystique->dwgreg.zorg; + break; + + case REG_PLNWT: + mystique->dwgreg.plnwt = val; + break; + + case REG_SHIFT: + mystique->dwgreg.funcnt = val & 0xff; + mystique->dwgreg.xoff = val & 7; + mystique->dwgreg.yoff = (val >> 4) & 7; + mystique->dwgreg.stylelen = (val >> 16) & 0xff; + break; + + case REG_PITCH: + mystique->dwgreg.pitch = val & 0xffff; + if (mystique->dwgreg.pitch & PITCH_YLIN) + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + else + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + break; + + case REG_YDST: + mystique->dwgreg.ydst = val & 0x3fffff; + if (mystique->dwgreg.pitch & PITCH_YLIN) { + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + mystique->dwgreg.selline = val >> 29; + } else { + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + mystique->dwgreg.selline = val & 7; + } + break; + case REG_BCOL: + mystique->dwgreg.bcol = val; + break; + case REG_FCOL: + mystique->dwgreg.fcol = val; + break; + + case REG_SRC0: + mystique->dwgreg.src[0] = val; + if ((mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[0], 32); + break; + case REG_SRC1: + mystique->dwgreg.src[1] = val; + if ((mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[1], 32); + break; + case REG_SRC2: + mystique->dwgreg.src[2] = val; + if ((mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[2], 32); + break; + case REG_SRC3: + mystique->dwgreg.src[3] = val; + if ((mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[3], 32); + break; + + case REG_DMAPAD: + break; + + case REG_AR0: + mystique->dwgreg.ar[0] = val; + break; + case REG_AR1: + mystique->dwgreg.ar[1] = val; + break; + case REG_AR2: + mystique->dwgreg.ar[2] = val; + break; + case REG_AR3: + mystique->dwgreg.ar[3] = val; + break; + case REG_AR4: + mystique->dwgreg.ar[4] = val; + break; + case REG_AR5: + mystique->dwgreg.ar[5] = val; + break; + case REG_AR6: + mystique->dwgreg.ar[6] = val; + break; + + case REG_DR0: + mystique->dwgreg.dr[0] = val; + break; + case REG_DR2: + mystique->dwgreg.dr[2] = val; + break; + case REG_DR3: + mystique->dwgreg.dr[3] = val; + break; + case REG_DR4: + mystique->dwgreg.dr[4] = val; + break; + case REG_DR6: + mystique->dwgreg.dr[6] = val; + break; + case REG_DR7: + mystique->dwgreg.dr[7] = val; + break; + case REG_DR8: + mystique->dwgreg.dr[8] = val; + break; + case REG_DR10: + mystique->dwgreg.dr[10] = val; + break; + case REG_DR11: + mystique->dwgreg.dr[11] = val; + break; + case REG_DR12: + mystique->dwgreg.dr[12] = val; + break; + case REG_DR14: + mystique->dwgreg.dr[14] = val; + break; + case REG_DR15: + mystique->dwgreg.dr[15] = val; + break; + + case REG_SECEND: + mystique->dma.secend = val; + if (mystique->dma.state != DMA_STATE_SEC && (mystique->dma.secaddress & DMA_ADDR_MASK) != (mystique->dma.secend & DMA_ADDR_MASK)) + mystique->dma.state = DMA_STATE_SEC; + break; + + case REG_SOFTRAP: + mystique->dma.state = DMA_STATE_IDLE; + mystique->endprdmasts_pending = 1; + mystique->softrap_pending_val = val; + mystique->softrap_pending = 1; + break; + + default: + mystique_accel_ctrl_write_b(addr, val & 0xff, p); + mystique_accel_ctrl_write_b(addr+1, (val >> 8) & 0xff, p); + mystique_accel_ctrl_write_b(addr+2, (val >> 16) & 0xff, p); + mystique_accel_ctrl_write_b(addr+3, (val >> 24) & 0xff, p); + break; + } + + if (start_blit) + mystique_start_blit(mystique); +} + + +static void +mystique_ctrl_write_l(uint32_t addr, uint32_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + uint32_t reg_addr; + + if ((addr & 0x3fff) < 0x1c00) { + mystique_iload_write_l(addr, val, p); + return; + } + + if ((addr & 0x3e00) == 0x1c00 || (addr & 0x3e00) == 0x2c00) { + if ((addr & 0x300) == 0x100) + mystique->blitter_submit_refcount++; + mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_LONG); + return; + } + + switch (addr & 0x3ffc) { + case REG_PRIMEND: + thread_wait_mutex(mystique->dma.lock); + mystique->dma.primend = val; + if (mystique->dma.state == DMA_STATE_IDLE && (mystique->dma.primaddress & DMA_ADDR_MASK) != (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 0; + mystique->status &= ~STATUS_ENDPRDMASTS; + + mystique->dma.state = DMA_STATE_PRI; + mystique->dma.pri_state = 0; + wake_fifo_thread(mystique); + } + thread_release_mutex(mystique->dma.lock); + break; + + case REG_DWG_INDIR_WT: case REG_DWG_INDIR_WT+0x04: case REG_DWG_INDIR_WT+0x08: case REG_DWG_INDIR_WT+0x0c: + case REG_DWG_INDIR_WT+0x10: case REG_DWG_INDIR_WT+0x14: case REG_DWG_INDIR_WT+0x18: case REG_DWG_INDIR_WT+0x1c: + case REG_DWG_INDIR_WT+0x20: case REG_DWG_INDIR_WT+0x24: case REG_DWG_INDIR_WT+0x28: case REG_DWG_INDIR_WT+0x2c: + case REG_DWG_INDIR_WT+0x30: case REG_DWG_INDIR_WT+0x34: case REG_DWG_INDIR_WT+0x38: case REG_DWG_INDIR_WT+0x3c: + reg_addr = (mystique->dmamap[(addr >> 2) & 0xf] & 0x7f) << 2; + if (mystique->dmamap[(addr >> 2) & 0xf] & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_refcount++; + + mystique_queue(mystique, reg_addr, val, FIFO_WRITE_CTRL_LONG); + break; + + default: + mystique_ctrl_write_b(addr, val & 0xff, p); + mystique_ctrl_write_b(addr+1, (val >> 8) & 0xff, p); + mystique_ctrl_write_b(addr+2, (val >> 16) & 0xff, p); + mystique_ctrl_write_b(addr+3, (val >> 24) & 0xff, p); + break; + } +} + + +static uint8_t +mystique_iload_read_b(uint32_t addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + wait_fifo_idle(mystique); + + if (!mystique->busy) + return 0xff; + + return blit_idump_read(mystique); +} + + +static uint32_t +mystique_iload_read_l(uint32_t addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + wait_fifo_idle(mystique); + + if (!mystique->busy) + return 0xffffffff; + + mystique->dwgreg.words++; + return blit_idump_read(mystique); +} + + +static void +mystique_iload_write_b(uint32_t addr, uint8_t val, void *p) +{ + +} + + +static void +mystique_iload_write_l(uint32_t addr, uint32_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + mystique_queue(mystique, 0, val, FIFO_WRITE_ILOAD_LONG); +} + +static void +mystique_accel_iload_write_l(uint32_t addr, uint32_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + switch (mystique->dwgreg.dmamod) { + case DMA_MODE_REG: + if (mystique->dma.iload_state == 0) { + mystique->dma.iload_header = val; + mystique->dma.iload_state = 1; + } else { + uint32_t reg_addr = (mystique->dma.iload_header & 0x7f) << 2; + if (mystique->dma.iload_header & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_dma_refcount++; + mystique_accel_ctrl_write_l(reg_addr, val, mystique); + + mystique->dma.iload_header >>= 8; + mystique->dma.iload_state = (mystique->dma.iload_state == 4) ? 0 : (mystique->dma.iload_state+1); + } + break; + + case DMA_MODE_BLIT: + if (!mystique->busy) + fatal("mystique_iload_write_l: !busy\n"); + blit_iload_write(mystique, val, 32); + break; + + /* default: + pclog("ILOAD write DMAMOD %i\n", mystique->dwgreg.dmamod); */ + } +} + + +static void +run_dma(mystique_t *mystique) +{ + int words_transferred = 0; + + thread_wait_mutex(mystique->dma.lock); + + if (mystique->dma.state == DMA_STATE_IDLE) { + thread_release_mutex(mystique->dma.lock); + return; + } + + while (words_transferred < DMA_MAX_WORDS && mystique->dma.state != DMA_STATE_IDLE) { + switch (mystique->dma.state) { + case DMA_STATE_PRI: + switch (mystique->dma.primaddress & DMA_MODE_MASK) { + case DMA_MODE_REG: + if (mystique->dma.pri_state == 0) { + mystique->dma.pri_header = *(uint32_t *)&ram[mystique->dma.primaddress & DMA_ADDR_MASK]; + mystique->dma.primaddress += 4; + } + + if ((mystique->dma.pri_header & 0xff) != 0x15) { + uint32_t val = *(uint32_t *)&ram[mystique->dma.primaddress & DMA_ADDR_MASK]; + uint32_t reg_addr; + + mystique->dma.primaddress += 4; + + reg_addr = (mystique->dma.pri_header & 0x7f) << 2; + if (mystique->dma.pri_header & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_dma_refcount++; + + mystique_accel_ctrl_write_l(reg_addr, val, mystique); + } + + mystique->dma.pri_header >>= 8; + mystique->dma.pri_state = (mystique->dma.pri_state + 1) & 3; + + words_transferred++; + if (mystique->dma.state == DMA_STATE_SEC) + mystique->dma.pri_state = 0; + else if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + } + break; + + default: + fatal("DMA_STATE_PRI: mode %i\n", mystique->dma.primaddress & DMA_MODE_MASK); + } + break; + + case DMA_STATE_SEC: + switch (mystique->dma.secaddress & DMA_MODE_MASK) { + case DMA_MODE_REG: + if (mystique->dma.sec_state == 0) { + mystique->dma.sec_header = *(uint32_t *)&ram[mystique->dma.secaddress & DMA_ADDR_MASK]; + mystique->dma.secaddress += 4; + } + + uint32_t val = *(uint32_t *)&ram[mystique->dma.secaddress & DMA_ADDR_MASK]; + uint32_t reg_addr; + + mystique->dma.secaddress += 4; + + reg_addr = (mystique->dma.sec_header & 0x7f) << 2; + if (mystique->dma.sec_header & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_dma_refcount++; + + mystique_accel_ctrl_write_l(reg_addr, val, mystique); + + mystique->dma.sec_header >>= 8; + mystique->dma.sec_state = (mystique->dma.sec_state + 1) & 3; + + words_transferred++; + if ((mystique->dma.secaddress & DMA_ADDR_MASK) == (mystique->dma.secend & DMA_ADDR_MASK)) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + } else + mystique->dma.state = DMA_STATE_PRI; + } + break; + + case DMA_MODE_BLIT: { + uint32_t val = *(uint32_t *)&ram[mystique->dma.secaddress & DMA_ADDR_MASK]; + mystique->dma.secaddress += 4; + + if (!mystique->busy) + fatal("mystique_iload_write_l: !busy\n"); + + blit_iload_write(mystique, val, 32); + + words_transferred++; + if ((mystique->dma.secaddress & DMA_ADDR_MASK) == (mystique->dma.secend & DMA_ADDR_MASK)) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + } else + mystique->dma.state = DMA_STATE_PRI; + } + } break; + + default: + fatal("DMA_STATE_SEC: mode %i\n", mystique->dma.secaddress & DMA_MODE_MASK); + } + break; + } + } + + thread_release_mutex(mystique->dma.lock); +} + + +static void +fifo_thread(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + while (1) { + thread_set_event(mystique->fifo_not_full_event); + thread_wait_event(mystique->wake_fifo_thread, -1); + thread_reset_event(mystique->wake_fifo_thread); + + while (!FIFO_EMPTY || mystique->dma.state != DMA_STATE_IDLE) { + int words_transferred = 0; + + while (!FIFO_EMPTY && words_transferred < 100) { + fifo_entry_t *fifo = &mystique->fifo[mystique->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) { + case FIFO_WRITE_CTRL_BYTE: + mystique_accel_ctrl_write_b(fifo->addr_type & FIFO_ADDR, fifo->val, mystique); + break; + case FIFO_WRITE_CTRL_LONG: + mystique_accel_ctrl_write_l(fifo->addr_type & FIFO_ADDR, fifo->val, mystique); + break; + case FIFO_WRITE_ILOAD_LONG: + mystique_accel_iload_write_l(fifo->addr_type & FIFO_ADDR, fifo->val, mystique); + break; + } + + fifo->addr_type = FIFO_INVALID; + mystique->fifo_read_idx++; + + if (FIFO_ENTRIES > FIFO_THRESHOLD) + thread_set_event(mystique->fifo_not_full_event); + + words_transferred++; + } + + /*Only run DMA once the FIFO is empty. Required by + Screamer 2 / Rally which will incorrectly clip an ILOAD + if DMA runs ahead*/ + if (!words_transferred) + run_dma(mystique); + } + } +} + + +static void +wake_fifo_thread(mystique_t *mystique) +{ + if (!timer_is_enabled(&mystique->wake_timer)) { + /* Don't wake FIFO thread immediately - if we do that it will probably + process one word and go back to sleep, requiring it to be woken on + almost every write. Instead, wait a short while so that the CPU + emulation writes more data so we have more batched-up work. */ + timer_set_delay_u64(&mystique->wake_timer, WAKE_DELAY); + } +} + + +static void +wake_fifo_thread_now(mystique_t *mystique) +{ + thread_set_event(mystique->wake_fifo_thread); +} + + +static void +mystique_wake_timer(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + thread_set_event(mystique->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + + +static void +wait_fifo_idle(mystique_t *mystique) +{ + while (!FIFO_EMPTY) { + wake_fifo_thread_now(mystique); + thread_wait_event(mystique->fifo_not_full_event, 1); + } +} + + +/*IRQ code (PCI & PIC) is not currently thread safe. SOFTRAP IRQ requests must + therefore be submitted from the main emulation thread, in this case via a timer + callback. End-of-DMA status is also deferred here to prevent races between + SOFTRAP IRQs and code reading the status register. Croc will get into an IRQ + loop and triple fault if the ENDPRDMASTS flag is seen before the IRQ is taken*/ +static void mystique_softrap_pending_timer(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + timer_advance_u64(&mystique->softrap_pending_timer, TIMER_USEC * 100); + + if (mystique->endprdmasts_pending) { + mystique->endprdmasts_pending = 0; + mystique->status |= STATUS_ENDPRDMASTS; + } + if (mystique->softrap_pending) { + mystique->softrap_pending = 0; + + mystique->dma.secaddress = mystique->softrap_pending_val; + mystique->status |= STATUS_SOFTRAPEN; + mystique_update_irqs(mystique); + } +} + + +static +void mystique_queue(mystique_t *mystique, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &mystique->fifo[mystique->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) { + thread_reset_event(mystique->fifo_not_full_event); + if (FIFO_FULL) + thread_wait_event(mystique->fifo_not_full_event, -1); /* Wait for room in ringbuffer */ + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + mystique->fifo_write_idx++; + + if (FIFO_ENTRIES > FIFO_THRESHOLD || FIFO_ENTRIES < 8) + wake_fifo_thread(mystique); +} + + +static uint32_t +bitop(uint32_t src, uint32_t dst, uint32_t dwgctrl) +{ + switch (dwgctrl & DWGCTRL_BOP_MASK) { + case BOP(0x0): return 0; + case BOP(0x1): return ~(dst | src); + case BOP(0x2): return dst & ~src; + case BOP(0x3): return ~src; + case BOP(0x4): return ~dst & src; + case BOP(0x5): return ~dst; + case BOP(0x6): return dst ^ src; + case BOP(0x7): return ~(dst & src); + case BOP(0x8): return dst & src; + case BOP(0x9): return ~(dst ^ src); + case BOP(0xa): return dst; + case BOP(0xb): return dst | ~src; + case BOP(0xc): return src; + case BOP(0xd): return ~dst | src; + case BOP(0xe): return dst | src; + case BOP(0xf): return ~0; + } + + return 0; +} + + +static uint16_t +dither(mystique_t *mystique, int r, int g, int b, int x, int y) +{ + switch (mystique->dwgreg.dither) { + case DITHER_NONE_555: + return (b >> 3) | ((g >> 3) << 5) | ((r >> 3) << 10); + + case DITHER_NONE_565: + return (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11); + + case DITHER_555: + return dither5[b][y][x] | (dither5[g][y][x] << 5) | (dither5[r][y][x] << 10); + + case DITHER_565: + default: + return dither5[b][y][x] | (dither6[g][y][x] << 5) | (dither5[r][y][x] << 11); + } +} + + +static uint32_t +blit_idump_idump(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint64_t val64 = 0; + uint32_t val = 0; + int count = 0; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BU32RGB: + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + while (count < 32) { + val |= (svga->vram[mystique->dwgreg.src_addr & mystique->vram_mask] << count); + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + + count += 8; + } + break; + + case MACCESS_PWIDTH_16: + while (count < 32) { + val |= (((uint16_t *)svga->vram)[mystique->dwgreg.src_addr & mystique->vram_mask_w] << count); + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + + count += 16; + } + break; + + case MACCESS_PWIDTH_24: + if (mystique->dwgreg.idump_end_of_line) { + mystique->dwgreg.idump_end_of_line = 0; + val = mystique->dwgreg.iload_rem_data; + mystique->dwgreg.iload_rem_count = 0; + mystique->dwgreg.iload_rem_data = 0; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + } + break; + } + + count += mystique->dwgreg.iload_rem_count; + val64 = mystique->dwgreg.iload_rem_data; + + while ((count < 32) && !mystique->dwgreg.idump_end_of_line) { + val64 |= (uint64_t)((*(uint32_t *)&svga->vram[(mystique->dwgreg.src_addr * 3) & mystique->vram_mask]) & 0xffffff) << count; + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + if (count > 8) + mystique->dwgreg.idump_end_of_line = 1; + else { + count = 32; + mystique->busy = 0; + mystique->blitter_complete_refcount++; + } + break; + } + if (!(mystique->dwgreg.dwgctrl_running & DWGCTRL_LINEAR)) { + if (count > 8) + mystique->dwgreg.idump_end_of_line = 1; + else { + count = 32; + break; + } + } + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + + count += 24; + } + if (count > 32) + mystique->dwgreg.iload_rem_count = count - 32; + else + mystique->dwgreg.iload_rem_count = 0; + mystique->dwgreg.iload_rem_data = (uint32_t)(val64 >> 32); + val = val64 & 0xffffffff; + break; + + case MACCESS_PWIDTH_32: + val = (((uint32_t *)svga->vram)[mystique->dwgreg.src_addr & mystique->vram_mask_l] << count); + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + break; + + default: + fatal("IDUMP DWGCTRL_BLTMOD_BU32RGB %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->maccess_running); + } + break; + + default: + fatal("IDUMP DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown IDUMP atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + return val; +} + + +static uint32_t +blit_idump_read(mystique_t *mystique) +{ + uint32_t ret = 0xffffffff; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) { + case DWGCTRL_OPCODE_IDUMP: + ret = blit_idump_idump(mystique); + break; + + default: + /* pclog("blit_idump_read: bad opcode %08x\n", mystique->dwgreg.dwgctrl_running); */ + break; + } + + return ret; +} + + +static void +blit_iload_iload(mystique_t *mystique, uint32_t data, int size) +{ + svga_t *svga = &mystique->svga; + uint32_t src, dst; + uint64_t data64; + int min_size = 8; + uint32_t bltckey = mystique->dwgreg.fcol, bltcmsk = mystique->dwgreg.bcol; + const int transc = mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + bltckey &= 0xff; + bltcmsk &= 0xff; + break; + case MACCESS_PWIDTH_16: + bltckey &= 0xffff; + bltcmsk &= 0xffff; + break; + } + + mystique->dwgreg.words++; + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + if (mystique->maccess_running & MACCESS_TLUTLOAD) { + while ((mystique->dwgreg.length_cur > 0) && (size >= 16)) { + uint16_t src = data & 0xffff; + + mystique->lut[mystique->dwgreg.ydst & 0xff].r = (src >> 11) << 3; + mystique->lut[mystique->dwgreg.ydst & 0xff].g = ((src >> 5) & 0x3f) << 2; + mystique->lut[mystique->dwgreg.ydst & 0xff].b = (src & 0x1f) << 3; + mystique->dwgreg.ydst++; + mystique->dwgreg.length_cur--; + data >>= 16; + size -= 16; + } + + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + } + break; + } + case DWGCTRL_ATYPE_RSTR: + case DWGCTRL_ATYPE_BLK: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BFCOL: + size += mystique->dwgreg.iload_rem_count; + data64 = mystique->dwgreg.iload_rem_data | ((uint64_t)data << mystique->dwgreg.iload_rem_count); + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + min_size = 8; + break; + case MACCESS_PWIDTH_16: + min_size = 16; + break; + case MACCESS_PWIDTH_24: + min_size = 24; + break; + case MACCESS_PWIDTH_32: + min_size = 32; + break; + } + + while (size >= min_size) { + int draw = (!transc || (data & bltcmsk) != bltckey) && trans[mystique->dwgreg.xdst & 3]; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) { + dst = svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]; + + dst = bitop(data & 0xff, dst, mystique->dwgreg.dwgctrl_running); + svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount; + } + + data >>= 8; + size -= 8; + break; + + case MACCESS_PWIDTH_16: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) { + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + + dst = bitop(data & 0xffff, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + } + + data >>= 16; + size -= 16; + break; + + case MACCESS_PWIDTH_24: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint32_t old_dst = *((uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]); + + dst = bitop(data64, old_dst, mystique->dwgreg.dwgctrl_running); + *((uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]) = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask) >> 12] = changeframecount; + } + + data64 >>= 24; + size -= 24; + break; + + case MACCESS_PWIDTH_32: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) { + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + + dst = bitop(data, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + } + + size = 0; + break; + + default: + fatal("ILOAD RSTR/RPL BFCOL pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + data64 = 0; + size = 0; + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + mystique->dwgreg.iload_rem_count = size; + mystique->dwgreg.iload_rem_data = data64; + break; + + case DWGCTRL_BLTMOD_BMONOWF: + data = (data >> 24) | ((data & 0x00ff0000) >> 8) | ((data & 0x0000ff00) << 8) | (data << 24); + while (size) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + ((data & 0x80000000) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && + trans[mystique->dwgreg.xdst & 3]) { + uint32_t old_dst; + + src = (data & 0x80000000) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); + + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD RSTR/RPL BMONOWF pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + if (!(mystique->dwgreg.dwgctrl_running & DWGCTRL_LINEAR)) + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + data <<= 1; + size--; + } + break; + + case DWGCTRL_BLTMOD_BU24RGB: + size += mystique->dwgreg.iload_rem_count; + data64 = mystique->dwgreg.iload_rem_data | ((uint64_t)data << mystique->dwgreg.iload_rem_count); + + while (size >= 24) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_32: + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + + dst = bitop(data64 & 0xffffff, dst, mystique->dwgreg.dwgctrl_running); + + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD RSTR/RPL BU24RGB pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + data64 >>= 24; + size -= 24; + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + data64 = 0; + size = 0; + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + + mystique->dwgreg.iload_rem_count = size; + mystique->dwgreg.iload_rem_data = data64; + break; + + default: + fatal("ILOAD DWGCTRL_ATYPE_RPL\n"); + break; + } + break; + + default: + fatal("Unknown ILOAD iload atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + + +#define CLAMP(x) do { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } while (0) + + +static void +blit_iload_iload_scale(mystique_t *mystique, uint32_t data, int size) +{ + svga_t *svga = &mystique->svga; + uint64_t data64 = 0; + int y0, y1; + int u, v; + int dR, dG, dB; + int r0, g0, b0; + int r1, g1, b1; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + y0 = (298 * ((int)(data & 0xff) - 16)) >> 8; + u = ((data >> 8) & 0xff) - 0x80; + y1 = (298 * ((int)((data >> 16) & 0xff) - 16)) >> 8; + v = ((data >> 24) & 0xff) - 0x80; + + dR = (309*v) >> 8; + dG = (100*u + 208*v) >> 8; + dB = (516*u) >> 8; + + r0 = y0 + dR; + CLAMP(r0); + g0 = y0 - dG; + CLAMP(g0); + b0 = y0 + dB; + CLAMP(b0); + r1 = y1 + dR; + CLAMP(r1); + g1 = y1 - dG; + CLAMP(g1); + b1 = y1 + dB; + CLAMP(b1); + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_16: + data = (b0 >> 3) | ((g0 >> 2) << 5) | ((r0 >> 3) << 11); + data |= (((b1 >> 3) | ((g1 >> 2) << 5) | ((r1 >> 3) << 11)) << 16); + size = 32; + break; + case MACCESS_PWIDTH_32: + data64 = b0 | (g0 << 8) | (r0 << 16); + data64 |= ((uint64_t)b0 << 32) | ((uint64_t)g0 << 40) | ((uint64_t)r0 << 48); + size = 64; + break; + + default: + fatal("blit_iload_iload_scale BUYUV pwidth %i\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + break; + + default: + fatal("blit_iload_iload_scale bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_16: + while (size >= 16) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint16_t dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + dst = bitop(data & 0xffff, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + } + + mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2]; + if ((int32_t)mystique->dwgreg.ar[6] >= 0) { + mystique->dwgreg.ar[6] -= (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + data >>= 16; + size -= 16; + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + break; + + case MACCESS_PWIDTH_32: + while (size >= 32) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint32_t dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + dst = bitop(data64, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + } + + mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2]; + if ((int32_t)mystique->dwgreg.ar[6] >= 0) { + mystique->dwgreg.ar[6] -= (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + data64 >>= 32; + size -= 32; + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + break; + + default: + fatal("ILOAD_SCALE pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } +} + + +static void +blit_iload_iload_high(mystique_t *mystique, uint32_t data, int size) +{ + svga_t *svga = &mystique->svga; + uint32_t out_data; + int y0, y1, u, v; + int dR, dG, dB; + int r = 0, g = 0, b = 0; + int next_r = 0, next_g = 0, next_b = 0; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + y0 = (298 * ((int)(data & 0xff) - 16)) >> 8; + u = ((data >> 8) & 0xff) - 0x80; + y1 = (298 * ((int)((data >> 16) & 0xff) - 16)) >> 8; + v = ((data >> 24) & 0xff) - 0x80; + + dR = (309*v) >> 8; + dG = (100*u + 208*v) >> 8; + dB = (516*u) >> 8; + + r = y0 + dR; + CLAMP(r); + g = y0 - dG; + CLAMP(g); + b = y0 + dB; + CLAMP(b); + + next_r = y1 + dR; + CLAMP(next_r); + next_g = y1 - dG; + CLAMP(next_g); + next_b = y1 + dB; + CLAMP(next_b); + + size = 32; + break; + + default: + fatal("blit_iload_iload_high bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } + + while (size >= 16) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint32_t dst; + int f1 = (mystique->dwgreg.ar[6] >> 12) & 0xf; + int f0 = 0x10 - f1; + int out_r = ((mystique->dwgreg.lastpix_r * f0) + (r * f1)) >> 4; + int out_g = ((mystique->dwgreg.lastpix_g * f0) + (g * f1)) >> 4; + int out_b = ((mystique->dwgreg.lastpix_b * f0) + (b * f1)) >> 4; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_16: + out_data = (out_b >> 3) | ((out_g >> 2) << 5) | ((out_r >> 3) << 11); + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + dst = bitop(out_data, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + case MACCESS_PWIDTH_32: + out_data = out_b | (out_g << 8) | (out_r << 16); + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + dst = bitop(out_data, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD_SCALE_HIGH RSTR/RPL BUYUV pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2]; + if ((int32_t)mystique->dwgreg.ar[6] >= 0) { + mystique->dwgreg.ar[6] -= 65536; + size -= 16; + + mystique->dwgreg.lastpix_r = r; + mystique->dwgreg.lastpix_g = g; + mystique->dwgreg.lastpix_b = b; + r = next_r; + g = next_g; + b = next_b; + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + mystique->dwgreg.lastpix_r = 0; + mystique->dwgreg.lastpix_g = 0; + mystique->dwgreg.lastpix_b = 0; + + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } +} + + +static void +blit_iload_iload_highv(mystique_t *mystique, uint32_t data, int size) +{ + uint8_t *src0, *src1; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + if (!mystique->dwgreg.highv_line) { + mystique->dwgreg.highv_data = data; + mystique->dwgreg.highv_line = 1; + return; + } + mystique->dwgreg.highv_line = 0; + + src0 = (uint8_t *)&mystique->dwgreg.highv_data; + src1 = (uint8_t *)&data; + + src1[0] = ((src0[0] * mystique->dwgreg.beta) + (src1[0] * (16 - mystique->dwgreg.beta))) >> 4; + src1[1] = ((src0[1] * mystique->dwgreg.beta) + (src1[1] * (16 - mystique->dwgreg.beta))) >> 4; + src1[2] = ((src0[2] * mystique->dwgreg.beta) + (src1[2] * (16 - mystique->dwgreg.beta))) >> 4; + src1[3] = ((src0[3] * mystique->dwgreg.beta) + (src1[3] * (16 - mystique->dwgreg.beta))) >> 4; + blit_iload_iload_high(mystique, data, 32); + break; + + default: + fatal("blit_iload_iload_highv bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } +} + + +static void +blit_iload_write(mystique_t *mystique, uint32_t data, int size) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) { + case DWGCTRL_OPCODE_ILOAD: + blit_iload_iload(mystique, data, size); + break; + + case DWGCTRL_OPCODE_ILOAD_SCALE: + blit_iload_iload_scale(mystique, data, size); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGH: + blit_iload_iload_high(mystique, data, size); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGHV: + blit_iload_iload_highv(mystique, data, size); + break; + + default: + fatal("blit_iload_write: bad opcode %08x\n", mystique->dwgreg.dwgctrl_running); + } +} + + +static int +z_check(uint16_t z, uint16_t old_z, uint32_t z_mode)//mystique->dwgreg.dwgctrl & DWGCTRL_ZMODE_MASK) +{ + switch (z_mode) { + case DWGCTRL_ZMODE_ZE: + return (z == old_z); + case DWGCTRL_ZMODE_ZNE: + return (z != old_z); + case DWGCTRL_ZMODE_ZLT: + return (z < old_z); + case DWGCTRL_ZMODE_ZLTE: + return (z <= old_z); + case DWGCTRL_ZMODE_ZGT: + return (z > old_z); + case DWGCTRL_ZMODE_ZGTE: + return (z >= old_z); + + case DWGCTRL_ZMODE_NOZCMP: + default: + return 1; + } +} + + +static void +blit_line(mystique_t *mystique, int closed) +{ + svga_t *svga = &mystique->svga; + uint32_t src, dst, old_dst; + int x; + int z_write; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RSTR: + case DWGCTRL_ATYPE_RPL: + x = mystique->dwgreg.xdst; + while (mystique->dwgreg.length > 0) { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + src = mystique->dwgreg.fcol; + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + src = mystique->dwgreg.fcol; + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + src = mystique->dwgreg.fcol; + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + src = mystique->dwgreg.fcol; + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("LINE RSTR/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (mystique->dwgreg.sgn.sdydxl) + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + + if ((int32_t)mystique->dwgreg.ar[1] >= 0) { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + if (mystique->dwgreg.sgn.sdydxl) + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + else + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } else + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + + mystique->dwgreg.length--; + } + break; + + case DWGCTRL_ATYPE_I: + case DWGCTRL_ATYPE_ZI: + z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI); + x = mystique->dwgreg.xdst; + while (mystique->dwgreg.length > 0) { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint16_t z = ((int32_t)mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + uint16_t *z_p = (uint16_t *)&svga->vram[(mystique->dwgreg.ydst_lin*2 + mystique->dwgreg.zorg) & mystique->vram_mask]; + uint16_t old_z = z_p[x]; + + if (z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK)) { + int r = 0, g = 0, b = 0; + + if (z_write) + z_p[x] = z; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_16: + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + r = (mystique->dwgreg.dr[4] >> 18) & 0x1f; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + g = (mystique->dwgreg.dr[8] >> 17) & 0x3f; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + b = (mystique->dwgreg.dr[12] >> 18) & 0x1f; + dst = (r << 11) | (g << 5) | b; + + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + default: + fatal("LINE I/ZI PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + } + + if (mystique->dwgreg.sgn.sdydxl) + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14]; + + if ((int32_t)mystique->dwgreg.ar[1] >= 0) { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + if (mystique->dwgreg.sgn.sdydxl) + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + else + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[3]; + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[7]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[11]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[15]; + } else + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + + mystique->dwgreg.length--; + } + break; + + default: + fatal("Unknown atype %03x %08x LINE\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + mystique->blitter_complete_refcount++; +} + + +static void +blit_autoline(mystique_t *mystique, int closed) +{ + int start_x = (int32_t)mystique->dwgreg.ar[5]; + int start_y = (int32_t)mystique->dwgreg.ar[6]; + int end_x = (int32_t)mystique->dwgreg.ar[0]; + int end_y = (int32_t)mystique->dwgreg.ar[2]; + int dx = end_x - start_x; + int dy = end_y - start_y; + + if (ABS(dx) > ABS(dy)) { + mystique->dwgreg.sgn.sdydxl = 1; + mystique->dwgreg.ar[0] = 2*ABS(dy); + mystique->dwgreg.ar[1] = 2*ABS(dy) - ABS(dx) - ((start_y > end_y) ? 1 : 0); + mystique->dwgreg.ar[2] = 2*ABS(dy) - 2*ABS(dx); + mystique->dwgreg.length = ABS(end_x - start_x); + } else { + mystique->dwgreg.sgn.sdydxl = 0; + mystique->dwgreg.ar[0] = 2*ABS(dx); + mystique->dwgreg.ar[1] = 2*ABS(dx) - ABS(dy) - ((start_y > end_y) ? 1 : 0); + mystique->dwgreg.ar[2] = 2*ABS(dx) - 2*ABS(dy); + mystique->dwgreg.length = ABS(end_y - start_y); + } + mystique->dwgreg.sgn.sdxl = (start_x > end_x) ? 1 : 0; + mystique->dwgreg.sgn.sdy = (start_y > end_y) ? 1 : 0; + + blit_line(mystique, closed); + + mystique->dwgreg.ar[5] = end_x; + mystique->dwgreg.xdst = end_x; + mystique->dwgreg.ar[6] = end_y; + mystique->dwgreg.ydst = end_y; + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; +} + + +static void +blit_trap(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint32_t z_back, r_back, g_back, b_back; + int z_write; + int y; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + + mystique->trap_count++; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_BLK: + case DWGCTRL_ATYPE_RPL: + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int x_l = mystique->dwgreg.fxleft & 0xffff; + int x_r = mystique->dwgreg.fxright & 0xffff; + int yoff = (mystique->dwgreg.yoff + mystique->dwgreg.ydst) & 7; + + while (x_l != x_r) { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x_l & 3]) { + int xoff = (mystique->dwgreg.xoff + x_l) & 7; + int pattern = mystique->dwgreg.pattern[yoff][xoff]; + uint32_t dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = + (pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xff; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = + (pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffff; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + dst = *(uint32_t *)(&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) & 0xff000000; + *(uint32_t *)(&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) = + ((pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffffff) | dst; + svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = + pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("TRAP BLK/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + x_l = (x_l + 1) & 0xffff; + mystique->pixel_count++; + } + + if ((int32_t)mystique->dwgreg.ar[1] < 0) { + while ((int32_t)mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + } else + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + if ((int32_t)mystique->dwgreg.ar[4] < 0) { + while ((int32_t)mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + } else + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + case DWGCTRL_ATYPE_RSTR: + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int x_l = mystique->dwgreg.fxleft & 0xffff; + int x_r = mystique->dwgreg.fxright & 0xffff; + int yoff = (mystique->dwgreg.yoff + mystique->dwgreg.ydst) & 7; + + while (x_l != x_r) { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x_l & 3]) { + int xoff = (mystique->dwgreg.xoff + x_l) & 7; + int pattern = mystique->dwgreg.pattern[yoff][xoff]; + uint32_t src = pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + uint32_t dst, old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("TRAP RSTR PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + x_l = (x_l + 1) & 0xffff; + mystique->pixel_count++; + } + + if ((int32_t)mystique->dwgreg.ar[1] < 0) { + while ((int32_t)mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + } else + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + if ((int32_t)mystique->dwgreg.ar[4] < 0) { + while ((int32_t)mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + } else + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + case DWGCTRL_ATYPE_I: + case DWGCTRL_ATYPE_ZI: + z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI); + + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint16_t *z_p = (uint16_t *)&svga->vram[(mystique->dwgreg.ydst_lin*2 + mystique->dwgreg.zorg) & mystique->vram_mask]; + int x_l = mystique->dwgreg.fxleft & 0xffff; + int x_r = mystique->dwgreg.fxright & 0xffff; + int old_x_l = x_l; + int dx; + + z_back = mystique->dwgreg.dr[0]; + r_back = mystique->dwgreg.dr[4]; + g_back = mystique->dwgreg.dr[8]; + b_back = mystique->dwgreg.dr[12]; + + while (x_l != x_r) { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x_l & 3]) { + uint16_t z = ((int32_t)mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + uint16_t old_z = z_p[x_l]; + + if (z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK)) { + uint32_t dst = 0, old_dst; + int r = 0, g = 0, b = 0; + + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + r = (mystique->dwgreg.dr[4] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + g = (mystique->dwgreg.dr[8] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + b = (mystique->dwgreg.dr[12] >> 15) & 0xff; + + if (z_write) + z_p[x_l] = z; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = dither(mystique, r, g, b, x_l & 1, mystique->dwgreg.selline & 1); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)(&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) & 0xff000000; + *(uint32_t *)(&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) = old_dst | dst; + svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = b | (g << 8) | (r << 16); + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("TRAP BLK/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + } + + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14]; + + x_l = (x_l + 1) & 0xffff; + mystique->pixel_count++; + } + + mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3]; + mystique->dwgreg.dr[4] = r_back + mystique->dwgreg.dr[7]; + mystique->dwgreg.dr[8] = g_back + mystique->dwgreg.dr[11]; + mystique->dwgreg.dr[12] = b_back + mystique->dwgreg.dr[15]; + + while ((int32_t)mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + while ((int32_t)mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + dx = (int16_t)((mystique->dwgreg.fxleft - old_x_l) & 0xffff); + mystique->dwgreg.dr[0] += dx*mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += dx*mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += dx*mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += dx*mystique->dwgreg.dr[14]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + default: + fatal("Unknown atype %03x %08x TRAP\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + mystique->blitter_complete_refcount++; +} + + +static int texture_read(mystique_t *mystique, int *tex_r, int *tex_g, int *tex_b, int *atransp) +{ + svga_t *svga = &mystique->svga; + + const int tex_shift = 3 + ((mystique->dwgreg.texctl & TEXCTL_TPITCH_MASK) >> TEXCTL_TPITCH_SHIFT); + const unsigned int palsel = mystique->dwgreg.texctl & TEXCTL_PALSEL_MASK; + const uint16_t tckey = mystique->dwgreg.textrans & TEXTRANS_TCKEY_MASK; + const uint16_t tkmask = (mystique->dwgreg.textrans & TEXTRANS_TKMASK_MASK) >> TEXTRANS_TKMASK_SHIFT; + const unsigned int w_mask = (mystique->dwgreg.texwidth & TEXWIDTH_TWMASK_MASK) >> TEXWIDTH_TWMASK_SHIFT; + const unsigned int h_mask = (mystique->dwgreg.texheight & TEXHEIGHT_THMASK_MASK) >> TEXHEIGHT_THMASK_SHIFT; + uint16_t src = 0; + int s, t; + + if (mystique->dwgreg.texctl & TEXCTL_NPCEN) { + const int s_shift = 20 - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK); + const int t_shift = 20 - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK); + + s = (int32_t)mystique->dwgreg.tmr[6] >> s_shift; + t = (int32_t)mystique->dwgreg.tmr[7] >> t_shift; + } else { + const int s_shift = (20 + 16) - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK); + const int t_shift = (20 + 16) - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK); + int64_t q = mystique->dwgreg.tmr[8] ? ((0x100000000ll / (int64_t)(int32_t)mystique->dwgreg.tmr[8]) /*>> 16*/) : 0; + + s = (((int64_t)(int32_t)mystique->dwgreg.tmr[6] * q) /*<< 8*/) >> s_shift;/*((16+20)-12);*/ + t = (((int64_t)(int32_t)mystique->dwgreg.tmr[7] * q) /*<< 8*/) >> t_shift;/*((16+20)-9);*/ + } + + if (mystique->dwgreg.texctl & TEXCTL_CLAMPU) { + if (s < 0) + s = 0; + else if (s > w_mask) + s = w_mask; + } else + s &= w_mask; + + if (mystique->dwgreg.texctl & TEXCTL_CLAMPV) { + if (t < 0) + t = 0; + else if (t > h_mask) + t = h_mask; + } else + t &= h_mask; + + switch (mystique->dwgreg.texctl & TEXCTL_TEXFORMAT_MASK) { + case TEXCTL_TEXFORMAT_TW4: + src = svga->vram[(mystique->dwgreg.texorg + (((t << tex_shift) + s) >> 1)) & mystique->vram_mask]; + if (s & 1) + src >>= 4; + else + src &= 0xf; + *tex_r = mystique->lut[src | palsel].r; + *tex_g = mystique->lut[src | palsel].g; + *tex_b = mystique->lut[src | palsel].b; + *atransp = 0; + break; + case TEXCTL_TEXFORMAT_TW8: + src = svga->vram[(mystique->dwgreg.texorg + (t << tex_shift) + s) & mystique->vram_mask]; + *tex_r = mystique->lut[src].r; + *tex_g = mystique->lut[src].g; + *tex_b = mystique->lut[src].b; + *atransp = 0; + break; + case TEXCTL_TEXFORMAT_TW15: + src = ((uint16_t *)svga->vram)[((mystique->dwgreg.texorg >> 1) + (t << tex_shift) + s) & mystique->vram_mask_w]; + *tex_r = ((src >> 10) & 0x1f) << 3; + *tex_g = ((src >> 5) & 0x1f) << 3; + *tex_b = (src & 0x1f) << 3; + if (((src >> 15) & mystique->dwgreg.ta_mask) == mystique->dwgreg.ta_key) + *atransp = 1; + else + *atransp = 0; + break; + case TEXCTL_TEXFORMAT_TW16: + src = ((uint16_t *)svga->vram)[((mystique->dwgreg.texorg >> 1) + (t << tex_shift) + s) & mystique->vram_mask_w]; + *tex_r = (src >> 11) << 3; + *tex_g = ((src >> 5) & 0x3f) << 2; + *tex_b = (src & 0x1f) << 3; + *atransp = 0; + break; + default: + fatal("Unknown texture format %i\n", mystique->dwgreg.texctl & TEXCTL_TEXFORMAT_MASK); + break; + } + + return ((src & tkmask) == tckey); +} + + +static void +blit_texture_trap(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + int y; + int z_write; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + const int dest32 = ((mystique->maccess_running & MACCESS_PWIDTH_MASK) == MACCESS_PWIDTH_32); + + mystique->trap_count++; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_I: + case DWGCTRL_ATYPE_ZI: + z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI); + + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint16_t *z_p = (uint16_t *)&svga->vram[(mystique->dwgreg.ydst_lin*2 + mystique->dwgreg.zorg) & mystique->vram_mask]; + int x_l = mystique->dwgreg.fxleft & 0xffff; + int x_r = mystique->dwgreg.fxright & 0xffff; + int old_x_l = x_l; + int dx; + + uint32_t z_back = mystique->dwgreg.dr[0]; + uint32_t r_back = mystique->dwgreg.dr[4]; + uint32_t g_back = mystique->dwgreg.dr[8]; + uint32_t b_back = mystique->dwgreg.dr[12]; + uint32_t s_back = mystique->dwgreg.tmr[6]; + uint32_t t_back = mystique->dwgreg.tmr[7]; + uint32_t q_back = mystique->dwgreg.tmr[8]; + + while (x_l != x_r) { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x_l & 3]) { + uint16_t z = ((int32_t)mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + uint16_t old_z = z_p[x_l]; + + if (z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK)) { + int tex_r = 0, tex_g = 0, tex_b = 0; + int ctransp, atransp = 0; + int i_r = 0, i_g = 0, i_b = 0; + + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + i_r = (mystique->dwgreg.dr[4] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + i_g = (mystique->dwgreg.dr[8] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + i_b = (mystique->dwgreg.dr[12] >> 15) & 0xff; + + ctransp = texture_read(mystique, &tex_r, &tex_g, &tex_b, &atransp); + + switch (mystique->dwgreg.texctl & (TEXCTL_TMODULATE | TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY)) { + case 0: + if (ctransp) + goto skip_pixel; + if (atransp) { + tex_r = i_r; + tex_g = i_g; + tex_b = i_b; + } + break; + + case TEXCTL_DECALCKEY: + if (ctransp) { + tex_r = i_r; + tex_g = i_g; + tex_b = i_b; + } + break; + + case (TEXCTL_STRANS | TEXCTL_DECALCKEY): + if (ctransp) + goto skip_pixel; + break; + + case TEXCTL_TMODULATE: + if (ctransp) + goto skip_pixel; + if (mystique->dwgreg.texctl & TEXCTL_TMODULATE) { + tex_r = (tex_r * i_r) >> 8; + tex_g = (tex_g * i_g) >> 8; + tex_b = (tex_b * i_b) >> 8; + } + break; + + case (TEXCTL_TMODULATE | TEXCTL_STRANS): + if (ctransp || atransp) + goto skip_pixel; + if (mystique->dwgreg.texctl & TEXCTL_TMODULATE) { + tex_r = (tex_r * i_r) >> 8; + tex_g = (tex_g * i_g) >> 8; + tex_b = (tex_b * i_b) >> 8; + } + break; + + default: + fatal("Bad TEXCTL %08x %08x\n", mystique->dwgreg.texctl, mystique->dwgreg.texctl & (TEXCTL_TMODULATE | TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY)); + } + + if (dest32) { + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = tex_b | (tex_g << 8) | (tex_r << 16); + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + } else { + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dither(mystique, tex_r, tex_g, tex_b, x_l & 1, mystique->dwgreg.selline & 1); + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + } + if (z_write) + z_p[x_l] = z; + } + } +skip_pixel: + x_l = (x_l + 1) & 0xffff; + mystique->pixel_count++; + + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14]; + mystique->dwgreg.tmr[6] += mystique->dwgreg.tmr[0]; + mystique->dwgreg.tmr[7] += mystique->dwgreg.tmr[2]; + mystique->dwgreg.tmr[8] += mystique->dwgreg.tmr[4]; + } + + mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3]; + mystique->dwgreg.dr[4] = r_back + mystique->dwgreg.dr[7]; + mystique->dwgreg.dr[8] = g_back + mystique->dwgreg.dr[11]; + mystique->dwgreg.dr[12] = b_back + mystique->dwgreg.dr[15]; + mystique->dwgreg.tmr[6] = s_back + mystique->dwgreg.tmr[1]; + mystique->dwgreg.tmr[7] = t_back + mystique->dwgreg.tmr[3]; + mystique->dwgreg.tmr[8] = q_back + mystique->dwgreg.tmr[5]; + + while ((int32_t)mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + while ((int32_t)mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + dx = (int16_t)((mystique->dwgreg.fxleft - old_x_l) & 0xffff); + mystique->dwgreg.dr[0] += dx*mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += dx*mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += dx*mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += dx*mystique->dwgreg.dr[14]; + mystique->dwgreg.tmr[6] += dx*mystique->dwgreg.tmr[0]; + mystique->dwgreg.tmr[7] += dx*mystique->dwgreg.tmr[2]; + mystique->dwgreg.tmr[8] += dx*mystique->dwgreg.tmr[4]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + default: + fatal("Unknown atype %03x %08x TEXTURE_TRAP\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + mystique->blitter_complete_refcount++; +} + + +static void +blit_bitblt(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint32_t src_addr; + int y; + int x_dir = mystique->dwgreg.sgn.scanleft ? -1 : 1; + int x_start = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxright : mystique->dwgreg.fxleft; + int x_end = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxleft : mystique->dwgreg.fxright; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_BLK: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BMONOLEF: + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) { + int x = x_start; + + while (1) { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint32_t byte_addr = (src_addr >> 3) & mystique->vram_mask; + int bit_offset = src_addr & 7; + uint32_t old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) { + if (svga->vram[byte_addr] & (1 << bit_offset)) + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = mystique->dwgreg.fcol; + } else + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = + (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) { + if (svga->vram[byte_addr] & (1 << bit_offset)) + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = mystique->dwgreg.fcol; + } else + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = + (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) { + if (svga->vram[byte_addr] & (1 << bit_offset)) + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = + (old_dst & 0xff000000) | (mystique->dwgreg.fcol & 0xffffff); + } else + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = + (old_dst & 0xff000000) | (((svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffffff); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) { + if (svga->vram[byte_addr] & (1 << bit_offset)) + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = mystique->dwgreg.fcol; + } else + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = + (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 11] = changeframecount; + break; + + default: + fatal("BITBLT DWGCTRL_ATYPE_BLK unknown MACCESS %i\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + if (src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } else + src_addr += x_dir; + + if (x != x_end) + x = (x + x_dir) & 0xffff; + else + break; + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + + default: + fatal("BITBLT BLK %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } + break; + + case DWGCTRL_ATYPE_RPL: + if (mystique->maccess_running & MACCESS_TLUTLOAD) { + src_addr = mystique->dwgreg.ar[3]; + + y = mystique->dwgreg.ydst; + + while (mystique->dwgreg.length) { + uint16_t src = ((uint16_t *)svga->vram)[src_addr & mystique->vram_mask_w]; + + mystique->lut[y & 0xff].r = (src >> 11) << 3; + mystique->lut[y & 0xff].g = ((src >> 5) & 0x3f) << 2; + mystique->lut[y & 0xff].b = (src & 0x1f) << 3; + src_addr++; + y++; + mystique->dwgreg.length--; + } + break; + } + case DWGCTRL_ATYPE_RSTR: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BMONOLEF: + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) + fatal("BITBLT RPL/RSTR BMONOLEF with pattern\n"); + + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int x = x_start; + + while (1) { + uint32_t byte_addr = (src_addr >> 3) & mystique->vram_mask; + int bit_offset = src_addr & 7; + + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + ((svga->vram[byte_addr] & (1 << bit_offset)) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && + trans[x & 3]) { + uint32_t src = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + uint32_t dst, old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running);// & DWGCTRL_BOP_MASK + + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + default: + fatal("BITBLT RPL BMONOLEF PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } else + src_addr += x_dir; + + if (x != x_end) + x = (x + x_dir) & 0xffff; + else + break; + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + + case DWGCTRL_BLTMOD_BFCOL: + case DWGCTRL_BLTMOD_BU32RGB: + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint32_t old_src_addr = src_addr; + int x = x_start; + + while (1) { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x & 3]) { + uint32_t src, dst, old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + src = svga->vram[src_addr & mystique->vram_mask]; + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + src = ((uint16_t *)svga->vram)[src_addr & mystique->vram_mask_w]; + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + src = *(uint32_t *)&svga->vram[(src_addr * 3) & mystique->vram_mask]; + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); + + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + src = ((uint32_t *)svga->vram)[src_addr & mystique->vram_mask_l]; + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("BITBLT RPL BFCOL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) + src_addr = ((src_addr + x_dir) & 7) | (src_addr & ~7); + else if (src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } else + src_addr += x_dir; + + if (x != x_end) + x = (x + x_dir) & 0xffff; + else + break; + } + + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) { + src_addr = old_src_addr; + if (mystique->dwgreg.sgn.sdy) + src_addr = ((src_addr - 32) & 0xe0) | (src_addr & ~0xe0); + else + src_addr = ((src_addr + 32) & 0xe0) | (src_addr & ~0xe0); + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + + default: + fatal("BITBLT DWGCTRL_ATYPE_RPL unknown BLTMOD %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + } + break; + + default: + fatal("Unknown BITBLT atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + mystique->blitter_complete_refcount++; +} + + +static void +blit_iload(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + case DWGCTRL_ATYPE_RSTR: + case DWGCTRL_ATYPE_BLK: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BFCOL: + case DWGCTRL_BLTMOD_BMONOWF: + case DWGCTRL_BLTMOD_BU24RGB: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + break; + + default: + fatal("ILOAD DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + + +static void +blit_idump(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + mystique->dwgreg.words = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.idump_end_of_line = 0; + mystique->busy = 1; + break; + + default: + fatal("Unknown IDUMP atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + + +static void +blit_iload_scale(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + break; + + default: + fatal("ILOAD_SCALE DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD_SCALE atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + + +static void +blit_iload_high(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + break; + + default: + fatal("ILOAD_HIGH DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD_HIGH atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + + +static +void blit_iload_highv(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + mystique->dwgreg.highv_line = 0; + mystique->dwgreg.lastpix_r = 0; + mystique->dwgreg.lastpix_g = 0; + mystique->dwgreg.lastpix_b = 0; + break; + + default: + fatal("ILOAD_HIGHV DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD_HIGHV atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + + +static void +mystique_start_blit(mystique_t *mystique) +{ + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + + mystique->dwgreg.dwgctrl_running = mystique->dwgreg.dwgctrl; + mystique->maccess_running = mystique->maccess; + if (mystique->busy) + fatal("Mystique still busy!\n"); + + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_SOLID) { + int x, y; + + for (y = 0; y < 8; y++) { + for (x = 0; x < 8; x++) + mystique->dwgreg.pattern[y][x] = 1; + } + mystique->dwgreg.src[0] = 0xffffffff; + mystique->dwgreg.src[1] = 0xffffffff; + mystique->dwgreg.src[2] = 0xffffffff; + mystique->dwgreg.src[3] = 0xffffffff; + } + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_ARZERO) { + mystique->dwgreg.ar[0] = 0; + mystique->dwgreg.ar[1] = 0; + mystique->dwgreg.ar[2] = 0; + mystique->dwgreg.ar[4] = 0; + mystique->dwgreg.ar[5] = 0; + mystique->dwgreg.ar[6] = 0; + } + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_SGNZERO) { + mystique->dwgreg.sgn.sdydxl = 0; + mystique->dwgreg.sgn.scanleft = 0; + mystique->dwgreg.sgn.sdxl = 0; + mystique->dwgreg.sgn.sdy = 0; + mystique->dwgreg.sgn.sdxr = 0; + } + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_SHTZERO) { + mystique->dwgreg.funcnt = 0; + mystique->dwgreg.stylelen = 0; + mystique->dwgreg.xoff = 0; + mystique->dwgreg.yoff = 0; + } + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) { + case DWGCTRL_OPCODE_LINE_OPEN: + blit_line(mystique, 0); + break; + + case DWGCTRL_OPCODE_AUTOLINE_OPEN: + blit_autoline(mystique, 0); + break; + + case DWGCTRL_OPCODE_AUTOLINE_CLOSE: + blit_autoline(mystique, 1); + break; + + case DWGCTRL_OPCODE_TRAP: + blit_trap(mystique); + break; + + case DWGCTRL_OPCODE_TEXTURE_TRAP: + blit_texture_trap(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGH: + blit_iload_high(mystique); + break; + + case DWGCTRL_OPCODE_BITBLT: + blit_bitblt(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD: + blit_iload(mystique); + break; + + case DWGCTRL_OPCODE_IDUMP: + blit_idump(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_SCALE: + blit_iload_scale(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGHV: + blit_iload_highv(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_FILTER: + /* TODO: Actually implement this. */ + break; + + default: + fatal("mystique_start_blit: unknown blit %08x\n", mystique->dwgreg.dwgctrl_running); + } + + end_time = plat_timer_read(); + mystique->blitter_time += end_time - start_time; +} + + +static void +mystique_hwcursor_draw(svga_t *svga, int displine) +{ + int x; + uint64_t dat[2]; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; + + dat[0] = *(uint64_t *)(&svga->vram[svga->hwcursor_latch.addr]); + dat[1] = *(uint64_t *)(&svga->vram[svga->hwcursor_latch.addr + 8]); + svga->hwcursor_latch.addr += 16; + for (x = 0; x < 64; x ++) { + if (!(dat[1] & (1ull << 63))) + buffer32->line[displine][offset + svga->x_add] = (dat[0] & (1ull << 63)) ? 0xffffff : 0; + else if (dat[0] & (1ull << 63)) + buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + + +static +uint8_t mystique_pci_read(int func, int addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + switch (addr) { + case 0x00: return 0x2b; /*Matrox*/ + case 0x01: return 0x10; + + case 0x02: return 0x1a; /*MGA-1064SG*/ + case 0x03: return 0x05; + + case PCI_REG_COMMAND: + return mystique->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 0 << 1; /*Fast DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Control aperture*/ + case 0x11: return (mystique->ctrl_base >> 8) & 0xc0; + case 0x12: return mystique->ctrl_base >> 16; + case 0x13: return mystique->ctrl_base >> 24; + + case 0x14: return 0x00; /*Linear frame buffer*/ + case 0x16: return (mystique->lfb_base >> 16) & 0x80; + case 0x17: return mystique->lfb_base >> 24; + + case 0x18: return 0x00; /*Pseudo-DMA (ILOAD)*/ + case 0x1a: return (mystique->iload_base >> 16) & 0x80; + case 0x1b: return mystique->iload_base >> 24; + + case 0x30: return mystique->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return mystique->pci_regs[0x32]; + case 0x33: return mystique->pci_regs[0x33]; + + case 0x3c: return mystique->int_line; + case 0x3d: return PCI_INTA; + + case 0x40: return mystique->pci_regs[0x40]; + case 0x41: return mystique->pci_regs[0x41]; + case 0x42: return mystique->pci_regs[0x42]; + case 0x43: return mystique->pci_regs[0x43]; + + case 0x44: return mystique->pci_regs[0x44]; + case 0x45: return mystique->pci_regs[0x45]; + + case 0x48: case 0x49: case 0x4a: case 0x4b: + addr = (mystique->pci_regs[0x44] & 0xfc) | ((mystique->pci_regs[0x45] & 0x3f) << 8) | + (addr & 3); + return mystique_ctrl_read_b(addr, mystique); + } + + return 0; +} + + +static void +mystique_pci_write(int func, int addr, uint8_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + switch (addr) { + case PCI_REG_COMMAND: + mystique->pci_regs[PCI_REG_COMMAND] = val & 0x23; + mystique_recalc_mapping(mystique); + break; + + case 0x11: + mystique->ctrl_base = (mystique->ctrl_base & 0xffff0000) | ((val & 0xc0) << 8); + mystique_recalc_mapping(mystique); + break; + case 0x12: + mystique->ctrl_base = (mystique->ctrl_base & 0xff00c000) | (val << 16); + mystique_recalc_mapping(mystique); + break; + case 0x13: + mystique->ctrl_base = (mystique->ctrl_base & 0x00ffc000) | (val << 24); + mystique_recalc_mapping(mystique); + break; + + case 0x16: + mystique->lfb_base = (mystique->lfb_base & 0xff000000) | ((val & 0x80) << 16); + mystique_recalc_mapping(mystique); + break; + case 0x17: + mystique->lfb_base = (mystique->lfb_base & 0x00800000) | (val << 24); + mystique_recalc_mapping(mystique); + break; + + case 0x1a: + mystique->iload_base = (mystique->iload_base & 0xff000000) | ((val & 0x80) << 16); + mystique_recalc_mapping(mystique); + break; + case 0x1b: + mystique->iload_base = (mystique->iload_base & 0x00800000) | (val << 24); + mystique_recalc_mapping(mystique); + break; + + case 0x30: case 0x32: case 0x33: + mystique->pci_regs[addr] = val; + if (mystique->pci_regs[0x30] & 0x01) { + uint32_t addr = (mystique->pci_regs[0x32] << 16) | (mystique->pci_regs[0x33] << 24); + mem_mapping_set_addr(&mystique->bios_rom.mapping, addr, 0x8000); + } else + mem_mapping_disable(&mystique->bios_rom.mapping); + return; + + case 0x3c: + mystique->int_line = val; + return; + + case 0x40: case 0x41: case 0x42: case 0x43: + mystique->pci_regs[addr] = val; + break; + + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + mystique->pci_regs[addr-0x20] = val; + break; + + case 0x44: case 0x45: + mystique->pci_regs[addr] = val; + break; + + case 0x48: case 0x49: case 0x4a: case 0x4b: + addr = (mystique->pci_regs[0x44] & 0xfc) | ((mystique->pci_regs[0x45] & 0x3f) << 8) | + (addr & 3); + mystique_ctrl_write_b(addr, val, mystique); + break; + } +} + + +static void * +mystique_init(const device_t *info) +{ + int c; + mystique_t *mystique = malloc(sizeof(mystique_t)); + wchar_t *romfn; + + memset(mystique, 0, sizeof(mystique_t)); + + if (info->local == 1) + romfn = ROM_MYSTIQUE_220; + else + romfn = ROM_MYSTIQUE; + + rom_init(&mystique->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + mystique->vram_size = device_get_config_int("memory"); + mystique->vram_mask = (mystique->vram_size << 20) - 1; + mystique->vram_mask_w = mystique->vram_mask >> 1; + mystique->vram_mask_l = mystique->vram_mask >> 2; + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique); + + svga_init(&mystique->svga, mystique, mystique->vram_size << 20, + mystique_recalctimings, + mystique_in, mystique_out, + mystique_hwcursor_draw, + NULL); + + io_sethandler(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); + mem_mapping_add(&mystique->ctrl_mapping, 0, 0, + mystique_ctrl_read_b, NULL, mystique_ctrl_read_l, + mystique_ctrl_write_b, NULL, mystique_ctrl_write_l, + NULL, 0, mystique); + mem_mapping_add(&mystique->lfb_mapping, 0, 0, + svga_read_linear, svga_readw_linear, svga_readl_linear, + svga_write_linear, svga_writew_linear, svga_writel_linear, + NULL, 0, mystique); + mem_mapping_add(&mystique->iload_mapping, 0, 0, + mystique_iload_read_b, NULL, mystique_iload_read_l, + mystique_iload_write_b, NULL, mystique_iload_write_l, + NULL, 0, mystique); + + mystique->card = pci_add_card(PCI_ADD_VIDEO, mystique_pci_read, mystique_pci_write, mystique); + mystique->pci_regs[0x2c] = mystique->bios_rom.rom[0x7ff8]; + mystique->pci_regs[0x2d] = mystique->bios_rom.rom[0x7ff8]; + mystique->pci_regs[0x2e] = mystique->bios_rom.rom[0x7ff8]; + mystique->pci_regs[0x2f] = mystique->bios_rom.rom[0x7ff8]; + + mystique->svga.miscout = 1; + mystique->pci_regs[0x41] = 0x01; /* vgaboot = 1 */ + + for (c = 0; c < 256; c++) { + dither5[c][0][0] = c >> 3; + dither5[c][1][1] = (c + 2) >> 3; + dither5[c][1][0] = (c + 4) >> 3; + dither5[c][0][1] = (c + 6) >> 3; + + if (dither5[c][1][1] > 31) + dither5[c][1][1] = 31; + if (dither5[c][1][0] > 31) + dither5[c][1][0] = 31; + if (dither5[c][0][1] > 31) + dither5[c][0][1] = 31; + + dither6[c][0][0] = c >> 2; + dither6[c][1][1] = (c + 1) >> 2; + dither6[c][1][0] = (c + 2) >> 2; + dither6[c][0][1] = (c + 3) >> 2; + + if (dither6[c][1][1] > 63) + dither6[c][1][1] = 63; + if (dither6[c][1][0] > 63) + dither6[c][1][0] = 63; + if (dither6[c][0][1] > 63) + dither6[c][0][1] = 63; + } + + mystique->wake_fifo_thread = thread_create_event(); + mystique->fifo_not_full_event = thread_create_event(); + mystique->fifo_thread = thread_create(fifo_thread, mystique); + mystique->dma.lock = thread_create_mutex(L"86Box.MGAMutex"); + + timer_add(&mystique->wake_timer, mystique_wake_timer, (void *)mystique, 0); + timer_add(&mystique->softrap_pending_timer, mystique_softrap_pending_timer, (void *)mystique, 1); + + mystique->status = STATUS_ENDPRDMASTS; + + return mystique; +} + + +static void +mystique_close(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + thread_kill(mystique->fifo_thread); + thread_destroy_event(mystique->wake_fifo_thread); + thread_destroy_event(mystique->fifo_not_full_event); + thread_close_mutex(mystique->dma.lock); + + svga_close(&mystique->svga); + + free(mystique); +} + + +static int +mystique_available(void) +{ + return rom_present(L"roms/video/matrox/MYSTIQUE.VBI"); +} + + +static void +mystique_speed_changed(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + svga_recalctimings(&mystique->svga); +} + + +static void +mystique_force_redraw(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + mystique->svga.fullchange = changeframecount; +} + + +static const device_config_t mystique_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + }, + .default_int = 8 + }, + { + .type = -1 + } +}; + + +const device_t mystique_device = +{ + "Matrox Mystique", + DEVICE_PCI, + 0, + mystique_init, + mystique_close, + NULL, + mystique_available, + mystique_speed_changed, + mystique_force_redraw, + mystique_config +}; + + +const device_t mystique_220_device = +{ + "Matrox Mystique 220", + DEVICE_PCI, + 1, + mystique_init, + mystique_close, + NULL, + mystique_available, + mystique_speed_changed, + mystique_force_redraw, + mystique_config +}; diff --git a/src/video/vid_mga.h b/src/video/vid_mga.h new file mode 100644 index 000000000..5291c81e4 --- /dev/null +++ b/src/video/vid_mga.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. + * + * Matrox MGA graphics card emulation. + * + * Version: @(#)vid_mga.h 1.0.1 2020/01/18 + * + * Author: Sarah Walker, + * Copyright 2008-2020 Sarah Walker. + */ + +extern const device_t mystique_device; +extern const device_t mystique_220_device; diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index 467d2a67c..2addd8b32 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -372,8 +372,10 @@ oti_init(const device_t *info) break; } - rom_init(&oti->bios_rom, romfn, - 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (romfn != NULL) { + rom_init(&oti->bios_rom, romfn, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + } oti->vram_mask = (oti->vram_size << 10) - 1; diff --git a/src/video/vid_pgc.c b/src/video/vid_pgc.c index e8ccbee4b..0dbaa9595 100644 --- a/src/video/vid_pgc.c +++ b/src/video/vid_pgc.c @@ -112,7 +112,8 @@ static const char *pgc_err_msgs[] = { "Stack \r", "Too long\r", "Area \r", - "Missing \r" + "Missing \r", + "Unknown \r" }; @@ -862,12 +863,27 @@ pgc_fill_polygon(pgc_t *dev, unsigned corners, int32_t *x, int32_t *y) pgc_log("PGC: fill_polygon(%i corners)\n", corners); - if (corners < 2) return; /* Degenerate polygon */ + if (!x || !y || (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; + if (!nodex || !dx || !dy) { + if (nodex) { + free(nodex); + nodex = NULL; + } + if (dx) { + free(dx); + dx = NULL; + } + if (dy) { + free(dy); + dy = NULL; + } + return; + } ymin = ymax = y[0] / 65536.0; for (n = 0; n < corners; n++) { @@ -1664,7 +1680,6 @@ pgc_wake(pgc_t *dev) 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, @@ -1674,7 +1689,6 @@ pgc_sleep(pgc_t *dev) if (dev->stopped) { dev->waiting_input_fifo = 0; dev->waiting_output_fifo = 0; - *n = 0; return; } @@ -2019,7 +2033,10 @@ pgc_parse_words(pgc_t *dev, pgc_cl_t *cl, int count) } for (n = 0; n < count; n++) { - if (! pgc_param_word(dev, ¶m[n])) return 0; + if (! pgc_param_word(dev, ¶m[n])) { + free(param); + return 0; + } if (!pgc_cl_append(cl, param[n] & 0xff) || !pgc_cl_append(cl, param[n] >> 8)) { @@ -2047,8 +2064,12 @@ pgc_parse_coords(pgc_t *dev, pgc_cl_t *cl, int count) return 0; } - for (n = 0; n < count; n++) - if (! pgc_param_coord(dev, ¶m[n])) return 0; + for (n = 0; n < count; n++) { + if (! pgc_param_coord(dev, ¶m[n])) { + free(param); + return 0; + } + } /* Here is how the real PGC serializes coords: * diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 7915e5544..9da5c1ea7 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -2076,15 +2076,9 @@ uint8_t s3_accel_in(uint16_t port, void *p) 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); - } + 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); - } + s3_accel_start(2, 1, 0xffffffff, 0xffffffff, s3); return temp; case 0xe14a: case 0xe2ea: if (!s3_cpu_dest(s3)) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 5de05c59e..8978135f9 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,7 +11,7 @@ * 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.39 2019/12/03 + * Version: @(#)vid_svga.c 1.0.40 2019/12/28 * * Authors: Sarah Walker, * Miran Grca, @@ -570,6 +570,7 @@ svga_poll(void *p) uint32_t x, blink_delay; int wx, wy; int skip = (svga->crtc[8] >> 5) & 0x03; + int ret; if (!svga->linepos) { if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { @@ -701,11 +702,18 @@ svga_poll(void *p) svga->vc &= 2047; if (svga->vc == svga->split) { - svga->ma = svga->maback = 0; - svga->sc = 0; - if (svga->attrregs[0x10] & 0x20) { - svga->scrollcache = 0; - svga->x_add = (overscan_x >> 1); + ret = 1; + + if (svga->line_compare) + ret = svga->line_compare(svga); + + if (ret) { + svga->ma = svga->maback = 0; + svga->sc = 0; + if (svga->attrregs[0x10] & 0x20) { + svga->scrollcache = 0; + svga->x_add = (overscan_x >> 1); + } } } if (svga->vc == svga->dispend) { @@ -1119,31 +1127,21 @@ 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; + if (latch_addr >= svga->vram_max) { + for (i = 0; i < count; i++) + svga->latch.b[i] = 0xff; + } else { + latch_addr &= svga->vram_mask; for (i = 0; i < count; i++) - svga->latch.b[i] = svga->vram[addr | i]; - } else { - if (latch_addr >= svga->vram_max) { - for (i = 0; i < count; i++) - svga->latch.b[i] = 0xff; - } else { - 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; + 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; diff --git a/src/video/vid_svga.h b/src/video/vid_svga.h index 589039d3d..895313a29 100644 --- a/src/video/vid_svga.h +++ b/src/video/vid_svga.h @@ -109,6 +109,11 @@ typedef struct svga_t void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr); float (*getclock)(int clock, void *p); + /*Called when VC=R18 and friends. If this returns zero then MA resetting + is skipped. Matrox Mystique in Power mode reuses this counter for + vertical line interrupt*/ + int (*line_compare)(struct svga_t *svga); + /*If set then another device is driving the monitor output and the SVGA card should not attempt to display anything */ int override; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index d86e61686..b72a71e08 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -8,13 +8,13 @@ * * Define all known video cards. * - * Version: @(#)vid_table.c 1.0.44 2019/10/01 + * Version: @(#)vid_table.c 1.0.46 2020/01/18 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2019 Miran Grca. - * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. */ #include #include @@ -49,6 +49,7 @@ #include "vid_incolor.h" #include "vid_colorplus.h" #include "vid_mda.h" +#include "vid_mga.h" #include "vid_oak_oti.h" #include "vid_paradise.h" #include "vid_pgc.h" @@ -148,6 +149,8 @@ video_cards[] = { { "[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] Matrox Mystique", "mystique", &mystique_device }, + { "[PCI] Matrox Mystique 220", "mystique_220", &mystique_220_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 }, diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index c366fae12..a80ea293f 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -308,6 +308,7 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) } return; } + /*FALLTHROUGH*/ case 0x3C7: case 0x3C8: case 0x3C9: if (tgui->type == TGUI_9400CXI) { diff --git a/src/video/video.c b/src/video/video.c index 7d87c5382..e7504f4b5 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -910,7 +910,7 @@ void loadfont(wchar_t *s, int format) { FILE *f; - int c,d; + int c, d; f = rom_fopen(s, L"rb"); if (f == NULL) @@ -920,24 +920,28 @@ loadfont(wchar_t *s, int format) case 0: /* MDA */ for (c=0; c<256; c++) for (d=0; d<8; d++) - fontdatm[c][d] = fgetc(f); + fontdatm[c][d] = fgetc(f) & 0xff; for (c=0; c<256; c++) for (d=0; d<8; d++) - fontdatm[c][d+8] = fgetc(f); + fontdatm[c][d+8] = fgetc(f) & 0xff; (void)fseek(f, 4096+2048, SEEK_SET); for (c=0; c<256; c++) for (d=0; d<8; d++) - fontdat[c][d] = fgetc(f); + fontdat[c][d] = fgetc(f) & 0xff; break; case 1: /* PC200 */ for (d = 0; d < 4; d++) { /* There are 4 fonts in the ROM */ - for (c = 0; c < 256; c++) /* 8x14 MDA in 8x16 cell */ - fread(&fontdatm[256*d + c][0], 1, 16, f); + for (c = 0; c < 256; c++) { /* 8x14 MDA in 8x16 cell */ + if (fread(&fontdatm[256*d + c][0], 1, 16, f) != 16) + fatal("loadfont(): Error reading 8x16 font in PC200 mode, c = %i\n", c); + } 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); + if (fread(&fontdat[256*d + c][0], 1, 8, f) != 8) + fatal("loadfont(): Error reading 8x8 font in PC200 mode, c = %i\n", c); + if (fseek(f, 8, SEEK_CUR) == -1) + fatal("loadfont(): Error seeking in PC200 mode, c = %i\n", c); } } break; @@ -946,19 +950,19 @@ loadfont(wchar_t *s, int format) case 2: /* CGA */ for (c=0; c<256; c++) for (d=0; d<8; d++) - fontdat[c][d] = fgetc(f); + fontdat[c][d] = fgetc(f) & 0xff; break; case 3: /* Wyse 700 */ for (c=0; c<512; c++) for (d=0; d<32; d++) - fontdatw[c][d] = fgetc(f); + fontdatw[c][d] = fgetc(f) & 0xff; break; case 4: /* MDSI Genius */ for (c=0; c<256; c++) for (d=0; d<16; d++) - fontdat8x12[c][d] = fgetc(f); + fontdat8x12[c][d] = fgetc(f) & 0xff; break; case 5: /* Toshiba 3100e */ @@ -1002,7 +1006,7 @@ loadfont(wchar_t *s, int format) for (c = 0; c < 16384; c++) { for (d = 0; d < 32; d++) - fontdatksc5601[c].chr[d]=getc(f); + fontdatksc5601[c].chr[d]=fgetc(f) & 0xff; } break; @@ -1013,14 +1017,16 @@ loadfont(wchar_t *s, int format) 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); + for (c = 0; c < 256; c++) { + if (fread(&fontdatm[c][0], 1, 16, f) != 16) + fatal("loadfont(): Error reading 8x16 font in Sigma Color 400 mode, c = %i\n", c); + } 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); + fontdat[c][d] = fgetc(f) & 0xff; break; case 9: /* Image Manager 1024 native font */ diff --git a/src/video/video.h b/src/video/video.h index 427b0e5c9..a82993cfd 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -65,7 +65,7 @@ typedef struct { typedef struct { int w, h; uint32_t *dat; - uint32_t *line[2048]; + uint32_t *line[2112]; } bitmap_t; typedef struct { diff --git a/src/win/86Box.rc b/src/win/86Box.rc index d9f73af4b..851b7d287 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -8,7 +8,7 @@ * * Application resource script for Windows. * - * Version: @(#)86Box.rc 1.0.55 2019/12/05 + * Version: @(#)86Box.rc 1.0.56 2019/12/21 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -366,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 @@ -380,37 +380,41 @@ 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 @@ -420,15 +424,15 @@ 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 @@ -449,12 +453,12 @@ 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,48,10 + 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,222,7,38,12 - LTEXT "HD Controller:",IDT_1717,7,26,48,10 + 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,222,25,38,12 @@ -903,7 +907,6 @@ BEGIN 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?" - IDS_2123 "Unable to initialize Ghostscript, gsdll32.dll is required for automatic convertion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript files (.ps)." END STRINGTABLE DISCARDABLE diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index a01fd5e40..cd46ec67d 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.139 2019/12/05 +# Version: @(#)Makefile.mingw 1.0.141 2020/01/14 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -530,7 +530,7 @@ 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 + -fno-strict-aliasing # Add freetyp2 references through pkgconfig CFLAGS := $(CFLAGS) `pkg-config.exe --cflags freetype2` @@ -541,9 +541,9 @@ CXXFLAGS := $(CFLAGS) ######################################################################### # Create the (final) list of objects to build. # ######################################################################### -MAINOBJ := pc.o config.o random.o timer.o io.o apm.o dma.o nmi.o \ +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) + rom.o device.o nvr.o nvr_at.o nvr_ps2.o sst_flash.o via_vt82c586b.o $(VNCOBJ) $(RDPOBJ) INTELOBJ := intel_flash.o \ intel_sio.o intel_piix.o @@ -557,7 +557,7 @@ CPUOBJ := cpu.o cpu_table.o \ 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 + via_mvp3.o wd76c10.o MCHOBJ := machine.o machine_table.o \ m_xt.o m_xt_compaq.o \ @@ -604,7 +604,7 @@ HDDOBJ := hdd.o \ hdc_ide_sff8038i.o CDROMOBJ := cdrom.o \ - cdrom_dosbox.o cdrom_image.o + cdrom_image_backend.o cdrom_image.o ZIPOBJ := zip.o @@ -633,8 +633,8 @@ PRINTOBJ := png.o prt_cpmap.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 \ @@ -678,6 +678,7 @@ VIDOBJ := video.o \ vid_et4000.o vid_sc1502x_ramdac.o \ vid_et4000w32.o vid_stg_ramdac.o \ vid_ht216.o \ + vid_mga.o \ vid_oak_oti.o \ vid_paradise.o \ vid_ti_cf62011.o \ @@ -691,12 +692,8 @@ VIDOBJ := video.o \ PLATOBJ := win.o \ win_dynld.o win_thread.o \ win_cdrom.o win_keyboard.o \ - win_midi.o -ifeq ($(DINPUT), y) - PLATOBJ += win_mouse.o win_joystick.o -else - PLATOBJ += win_mouse_rawinput.o win_joystick.o -endif + win_midi.o \ + win_mouse.o win_joystick.o OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) \ $(DEVOBJ) $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ diff --git a/src/win/Makefile_ndr.mingw b/src/win/Makefile_ndr.mingw index ad11c5d30..51bab0847 100644 --- a/src/win/Makefile_ndr.mingw +++ b/src/win/Makefile_ndr.mingw @@ -8,7 +8,7 @@ # # Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.139 2019/12/05 +# Version: @(#)Makefile.mingw 1.0.141 2020/01/14 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -536,7 +536,7 @@ 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 + -fno-strict-aliasing # Add freetyp2 references through pkgconfig CFLAGS := $(CFLAGS) `pkg-config.exe --cflags freetype2` @@ -547,9 +547,9 @@ CXXFLAGS := $(CFLAGS) ######################################################################### # Create the (final) list of objects to build. # ######################################################################### -MAINOBJ := pc.o config.o random.o timer.o io.o apm.o dma.o nmi.o \ +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) + rom.o device.o nvr.o nvr_at.o nvr_ps2.o sst_flash.o via_vt82c586b.o $(VNCOBJ) $(RDPOBJ) INTELOBJ := intel_flash.o \ intel_sio.o intel_piix.o @@ -563,7 +563,7 @@ CPUOBJ := cpu.o cpu_table.o \ 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 + via_mvp3.o wd76c10.o MCHOBJ := machine.o machine_table_new.o \ m_xt.o m_xt_compaq.o \ @@ -610,7 +610,7 @@ HDDOBJ := hdd.o \ hdc_ide_sff8038i.o CDROMOBJ := cdrom.o \ - cdrom_dosbox.o cdrom_image.o + cdrom_image_backend.o cdrom_image.o ZIPOBJ := zip.o @@ -639,8 +639,8 @@ PRINTOBJ := png.o prt_cpmap.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 \ @@ -684,6 +684,7 @@ VIDOBJ := video.o \ vid_et4000.o vid_sc1502x_ramdac.o \ vid_et4000w32.o vid_stg_ramdac.o \ vid_ht216.o \ + vid_mga.o \ vid_oak_oti.o \ vid_paradise.o \ vid_ti_cf62011.o \ @@ -697,12 +698,8 @@ VIDOBJ := video.o \ PLATOBJ := win.o \ win_dynld.o win_thread.o \ win_cdrom.o win_keyboard.o \ - win_midi.o -ifeq ($(DINPUT), y) - PLATOBJ += win_mouse.o win_joystick.o -else - PLATOBJ += win_mouse_rawinput.o win_joystick.o -endif + win_midi.o \ + win_mouse.o win_joystick.o OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) \ $(DEVOBJ) $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ diff --git a/src/win/resource.h b/src/win/resource.h index 4922df81b..8e11ed62a 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -8,7 +8,7 @@ * * Windows resource defines. * - * Version: @(#)resource.h 1.0.31 2019/12/05 + * Version: @(#)resource.h 1.0.32 2019/12/21 * * Authors: Sarah Walker, * Miran Grca, @@ -54,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: */ @@ -144,12 +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_CHECK_GUSMAX 1080 +#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 @@ -242,6 +243,7 @@ #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 diff --git a/src/win/win.c b/src/win/win.c index 2f421412b..cfbdab264 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -73,6 +73,7 @@ static rc_str_t *lpRCstr2048, *lpRCstr6144, *lpRCstr7168; static int vid_api_inited = 0; +static wchar_t *argbuf; static const struct { @@ -267,6 +268,11 @@ CreateConsole(int init) } } } + + if (fp != NULL) { + fclose(fp); + fp = NULL; + } } @@ -275,7 +281,6 @@ static int ProcessCommandLine(wchar_t ***argw) { WCHAR *cmdline; - wchar_t *argbuf; wchar_t **args; int argc_max; int i, q, argc; @@ -376,6 +381,8 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) if (source_hwnd) PostMessage((HWND) (uintptr_t) source_hwnd, WM_HAS_SHUTDOWN, (WPARAM) 0, (LPARAM) hwndMain); + free(argbuf); + free(argw); return(1); } @@ -386,6 +393,8 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) /* Handle our GUI. */ i = ui_init(nCmdShow); + free(argbuf); + free(argw); return(i); } diff --git a/src/win/win.h b/src/win/win.h index c3717e72b..6c8444a33 100644 --- a/src/win/win.h +++ b/src/win/win.h @@ -88,8 +88,8 @@ extern HICON hIcon[256]; // extern int status_is_open; -extern char openfilestring[260]; -extern WCHAR wopenfilestring[260]; +extern char openfilestring[512]; +extern WCHAR wopenfilestring[512]; extern uint8_t filterindex; diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index a0a1e5018..e5e379d6c 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -108,6 +108,21 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id += 2; break; + case CONFIG_MIDI_IN: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); + + 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; case CONFIG_SPINNER: val_int = config_get_int((char *) config_device.name, (char *) config->name, config->default_int); @@ -205,6 +220,17 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) c = SendMessage(h, CB_GETCURSEL, 0, 0); + 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; @@ -302,6 +328,12 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) 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: @@ -358,6 +390,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; case CONFIG_SELECTION: case CONFIG_MIDI: + case CONFIG_MIDI_IN: case CONFIG_SPINNER: id += 2; break; @@ -478,6 +511,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) case CONFIG_SELECTION: case CONFIG_MIDI: + case CONFIG_MIDI_IN: case CONFIG_HEX16: case CONFIG_HEX20: /*Combo box*/ diff --git a/src/win/win_dialog.c b/src/win/win_dialog.c index 729be881e..bf93b474c 100644 --- a/src/win/win_dialog.c +++ b/src/win/win_dialog.c @@ -34,8 +34,8 @@ #include "win.h" -WCHAR wopenfilestring[260]; -char openfilestring[260]; +WCHAR wopenfilestring[512]; +char openfilestring[512]; uint8_t filterindex = 0; @@ -139,7 +139,7 @@ file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) * not use the contents of szFile to initialize itself. */ memcpy(ofn.lpstrFile, fn, (wcslen(fn) << 1) + 2); - ofn.nMaxFile = 259; + ofn.nMaxFile = sizeof_w(wopenfilestring); ofn.lpstrFilter = f; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; diff --git a/src/win/win_discord.c b/src/win/win_discord.c index b402f10e8..c174413a8 100644 --- a/src/win/win_discord.c +++ b/src/win/win_discord.c @@ -74,6 +74,7 @@ discord_update_activity(int paused) struct DiscordActivity activity; wchar_t config_name_w[1024]; char config_name[128]; + char *temp; if(discord_activities == NULL) return; @@ -90,8 +91,17 @@ discord_update_activity(int paused) } else { - strcpy(activity.details, strchr(machine_getname(), ']') + 2); - strcpy(activity.state, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name); + temp = strchr(machine_getname(), ']') + 2; + + if (strlen(temp) <= 127) + strcpy(activity.details, temp); + else + strncpy(activity.details, temp, 127); + + if (strlen(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name) <= 127) + strcpy(activity.state, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name); + else + strncpy(activity.state, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name, 127); } activity.timestamps.start = time(NULL); diff --git a/src/win/win_dynld.c b/src/win/win_dynld.c index 6043e36d6..e258ebe19 100644 --- a/src/win/win_dynld.c +++ b/src/win/win_dynld.c @@ -65,7 +65,7 @@ dynld_module(const char *name, dllimp_t *table) if (func == NULL) { dynld_log("DynLd(\"%s\"): function '%s' not found!\n", name, imp->name); - CloseHandle(h); + FreeLibrary(h); return(NULL); } diff --git a/src/win/win_joystick.cpp b/src/win/win_joystick.cpp index d073cd37c..499f19903 100644 --- a/src/win/win_joystick.cpp +++ b/src/win/win_joystick.cpp @@ -82,37 +82,54 @@ BOOL CALLBACK DIEnumDeviceObjectsCallback( plat_joystick_t *state = (plat_joystick_t *)pvRef; if (lpddoi->guidType == GUID_XAxis || lpddoi->guidType == GUID_YAxis || lpddoi->guidType == GUID_ZAxis || - lpddoi->guidType == GUID_RxAxis || lpddoi->guidType == GUID_RyAxis || lpddoi->guidType == GUID_RzAxis || - lpddoi->guidType == GUID_Slider) + lpddoi->guidType == GUID_RxAxis || lpddoi->guidType == GUID_RyAxis || lpddoi->guidType == GUID_RzAxis) { - 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; - else if (lpddoi->guidType == GUID_YAxis) - state->axis[state->nr_axes].id = 1; - else if (lpddoi->guidType == GUID_ZAxis) - state->axis[state->nr_axes].id = 2; - else if (lpddoi->guidType == GUID_RxAxis) - state->axis[state->nr_axes].id = 3; - else if (lpddoi->guidType == GUID_RyAxis) - state->axis[state->nr_axes].id = 4; - else if (lpddoi->guidType == GUID_RzAxis) - state->axis[state->nr_axes].id = 5; - state->nr_axes++; + if (state->nr_axes < 8) + {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; + else if (lpddoi->guidType == GUID_YAxis) + state->axis[state->nr_axes].id = 1; + else if (lpddoi->guidType == GUID_ZAxis) + state->axis[state->nr_axes].id = 2; + else if (lpddoi->guidType == GUID_RxAxis) + state->axis[state->nr_axes].id = 3; + else if (lpddoi->guidType == GUID_RyAxis) + state->axis[state->nr_axes].id = 4; + else if (lpddoi->guidType == GUID_RzAxis) + state->axis[state->nr_axes].id = 5; + state->nr_axes++; + } } else if (lpddoi->guidType == GUID_Button) { - 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++; + if (state->nr_buttons < 32) + { + 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) { - 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++; - } + if (state->nr_povs < 4) + { + 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++; + } + } + else if (lpddoi->guidType == GUID_Slider) + { + if (state->nr_sliders < 2) + { + memcpy(state->slider[state->nr_sliders].name, lpddoi->tszName, strlen(lpddoi->tszName) + 1); + state->slider[state->nr_sliders].id = state->nr_sliders | SLIDER; + joystick_log("Slider %i : %s %x %x\n", state->nr_sliders, state->slider[state->nr_sliders].name, lpddoi->dwOfs, lpddoi->dwType); + state->nr_sliders++; + } + } return DIENUM_CONTINUE; } @@ -187,7 +204,11 @@ void joystick_init() lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); joy_axis_range.diph.dwObj = DIJOFS_RZ; lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); - + joy_axis_range.diph.dwObj = DIJOFS_SLIDER(0); + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_SLIDER(1); + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + if (FAILED(lpdi_joystick[c]->Acquire())) fatal("joystick_init : Acquire failed\n"); } @@ -226,6 +247,10 @@ static int joystick_get_axis(int joystick_nr, int mapping) return 0; else return -cos((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else if (mapping & SLIDER) + { + return plat_joystick_state[joystick_nr].s[mapping & 3]; } else return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; @@ -235,7 +260,7 @@ void joystick_process(void) { int c, d; - if (joystick_type == 7) return; + if (joystick_type == JOYSTICK_TYPE_NONE) return; for (c = 0; c < joysticks_present; c++) { @@ -260,6 +285,8 @@ void joystick_process(void) plat_joystick_state[c].a[3] = joystate.lRx; plat_joystick_state[c].a[4] = joystate.lRy; plat_joystick_state[c].a[5] = joystate.lRz; + plat_joystick_state[c].s[0] = joystate.rglSlider[0]; + plat_joystick_state[c].s[1] = joystate.rglSlider[1]; for (b = 0; b < 16; b++) plat_joystick_state[c].b[b] = joystate.rgbButtons[b] & 0x80; diff --git a/src/win/win_joystick_xinput.cpp b/src/win/win_joystick_xinput.cpp index 6be292c13..237cab23c 100644 --- a/src/win/win_joystick_xinput.cpp +++ b/src/win/win_joystick_xinput.cpp @@ -216,7 +216,7 @@ void joystick_process(void) { int c, d; - if (joystick_type == 7) return; + if (joystick_type == JOYSTICK_TYPE_NONE) return; joystick_poll(); diff --git a/src/win/win_jsconf.c b/src/win/win_jsconf.c index 1ca6f5ef8..0d7474f59 100644 --- a/src/win/win_jsconf.c +++ b/src/win/win_jsconf.c @@ -58,6 +58,10 @@ static void rebuild_axis_button_selections(HWND hdlg) SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + } + for (d = 0; d < plat_joystick_state[joystick - 1].nr_sliders; d++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick - 1].slider[d].name); } SendMessage(h, CB_SETCURSEL, sel, 0); EnableWindow(h, TRUE); @@ -122,15 +126,23 @@ static int get_axis(HWND hdlg, int id) HWND h = GetDlgItem(hdlg, id); int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0); int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_axes; - + int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_povs; + int nr_sliders = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_sliders; + if (axis_sel < nr_axes) return axis_sel; axis_sel -= nr_axes; - if (axis_sel & 1) - return POV_Y | (axis_sel >> 1); - else - return POV_X | (axis_sel >> 1); + if (axis_sel < nr_povs * 2) + { + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); + } + axis_sel -= nr_povs; + + return SLIDER | (axis_sel >> 1); } static int get_pov(HWND hdlg, int id) @@ -163,6 +175,7 @@ joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) int joystick; int nr_axes; int nr_povs; + int nr_sliders; int mapping; switch (message) @@ -186,6 +199,8 @@ joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { nr_axes = plat_joystick_state[joystick-1].nr_axes; nr_povs = plat_joystick_state[joystick-1].nr_povs; + nr_sliders = plat_joystick_state[joystick - 1].nr_sliders; + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) { int mapping = joystick_state[joystick_nr].axis_mapping[c]; @@ -195,7 +210,9 @@ joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2, 0); else if (mapping & POV_Y) SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2 + 1, 0); - else + else if (mapping & SLIDER) + SendMessage(h, CB_SETCURSEL, nr_axes + nr_povs * 2 + (mapping & 3), 0); + else SendMessage(h, CB_SETCURSEL, mapping, 0); id += 2; } diff --git a/src/win/win_midi.c b/src/win/win_midi.c index 706db3acb..256ab6a5e 100644 --- a/src/win/win_midi.c +++ b/src/win/win_midi.c @@ -13,16 +13,17 @@ typedef struct { - int midi_id; + int midi_id, midi_input_id; HANDLE m_event; HMIDIOUT midi_out_device; + HMIDIIN midi_in_device; MIDIHDR m_hdr; } plat_midi_t; -plat_midi_t *pm = NULL; +plat_midi_t *pm = NULL, *pm_in = NULL; void @@ -65,7 +66,7 @@ plat_midi_close(void) midiOutClose(pm->midi_out_device); CloseHandle(pm->m_event); } - + free(pm); pm = NULL; } @@ -135,3 +136,117 @@ 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_rawinput.cpp b/src/win/win_mouse.c similarity index 98% rename from src/win/win_mouse_rawinput.cpp rename to src/win/win_mouse.c index fc983d24d..2ca004e9f 100644 --- a/src/win/win_mouse_rawinput.cpp +++ b/src/win/win_mouse.c @@ -63,8 +63,9 @@ win_mouse_handle(LPARAM lParam, int infocus) uint32_t ri_size = 0; UINT size; RAWINPUT *raw; - RAWMOUSE state; - + RAWMOUSE state; + static int x, y; + if (! infocus) return; GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, @@ -109,7 +110,7 @@ win_mouse_handle(LPARAM lParam, int infocus) * seems to work fine for RDP on Windows 10 * Not sure about other environments. */ - static int x=state.lLastX, y=state.lLastY; + x=state.lLastX, y=state.lLastY; mousestate.dx += (state.lLastX - x)/100; mousestate.dy += (state.lLastY - y)/100; x=state.lLastX; diff --git a/src/win/win_mouse.cpp b/src/win/win_mouse.cpp deleted file mode 100644 index a57969196..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 0dff080c9..4bb7b30f9 100644 --- a/src/win/win_new_floppy.c +++ b/src/win/win_new_floppy.c @@ -80,7 +80,7 @@ create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) uint16_t tflags = 0; uint32_t index_hole_pos = 0; uint32_t tarray[512]; - uint32_t array_size, array_size2; + uint32_t array_size; uint32_t track_base, track_size; int i; uint32_t shift = 0; @@ -133,11 +133,6 @@ create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) break; } - array_size2 = (array_size << 3); - array_size = (array_size2 >> 4) << 1; - if (array_size2 & 15) - array_size += 2; - empty = (unsigned char *) malloc(array_size); memset(tarray, 0, 2048); @@ -515,7 +510,7 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, static int fdd_id, sb_part; static int file_type = 0; /* 0 = IMG, 1 = Japanese FDI, 2 = 86F */ -static wchar_t fd_file_name[512]; +static wchar_t fd_file_name[1024]; /* Show a MessageBox dialog. This is nasty, I know. --FvK */ @@ -556,7 +551,7 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: plat_pause(1); - memset(fd_file_name, 0, 512 * sizeof(wchar_t)); + memset(fd_file_name, 0, 1024 * sizeof(wchar_t)); h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); if (is_zip) { zip_types = zip_drives[fdd_id].is_250 ? 2 : 1; @@ -613,6 +608,7 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) new_floppy_msgbox(hdlg, MBX_ERROR, (wchar_t *)IDS_4108); return TRUE; } + /*FALLTHROUGH*/ case IDCANCEL: EndDialog(hdlg, 0); plat_pause(0); diff --git a/src/win/win_settings.c b/src/win/win_settings.c index ed6747d5a..69f054acd 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,7 +8,7 @@ * * Windows 86Box Settings dialog handler. * - * Version: @(#)win_settings.c 1.0.62 2019/11/19 + * Version: @(#)win_settings.c 1.0.63 2019/12/21 * * Authors: Miran Grca, * David HrdliÄka, @@ -55,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" @@ -85,7 +85,7 @@ 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 */ @@ -124,6 +124,7 @@ extern int is486; 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]; @@ -219,11 +220,11 @@ 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 */ @@ -331,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 */ @@ -434,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 */ @@ -538,13 +539,9 @@ win_settings_machine_recalc_cpu(HWND hdlg) h = GetDlgItem(hdlg, IDC_CHECK_FPU); 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; - EnableWindow(h, FALSE); - } else { + else { temp_fpu = 1; EnableWindow(h, FALSE); } @@ -974,6 +971,7 @@ static BOOL CALLBACK win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { wchar_t str[128]; + char *joy_name; HWND h; int c, d; @@ -1003,9 +1001,15 @@ win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); c = 0; - while (joystick_get_name(c)) { - SendMessage(h, CB_ADDSTRING, 0, win_get_string(2105 + c)); + joy_name = joystick_get_name(c); + while (joy_name) + { + mbstowcs(str, joy_name, strlen(joy_name) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)str); + + // SendMessage(h, CB_ADDSTRING, 0, win_get_string(2105 + c)); c++; + joy_name = joystick_get_name(c); } EnableWindow(h, TRUE); SendMessage(h, CB_SETCURSEL, temp_joystick, 0); @@ -1104,19 +1108,19 @@ mpu401_present(void) int mpu401_standalone_allow(void) { - char *md; + char *md, *mdin; md = midi_device_get_internal_name(temp_midi_device); + 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; } - #if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else @@ -1199,25 +1203,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); @@ -1277,6 +1314,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); @@ -1289,6 +1351,18 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) 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; @@ -1299,6 +1373,9 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) 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); @@ -1311,9 +1388,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); @@ -2461,7 +2535,7 @@ static int hdconf_initialize_hdt_combo(HWND hdlg) h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); for (i = 0; i < 127; i++) { - temp_size = hdd_table[i][0] * hdd_table[i][1] * hdd_table[i][2]; + temp_size = ((uint64_t) hdd_table[i][0]) * hdd_table[i][1] * hdd_table[i][2]; size_mb = (uint32_t) (temp_size >> 11LL); wsprintf(szText, plat_get_string(IDS_2116), size_mb, hdd_table[i][0], hdd_table[i][1], hdd_table[i][2]); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); @@ -2779,6 +2853,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM f = _wfopen(wopenfilestring, (existing & 1) ? L"rb" : L"wb"); if (f == NULL) { hdd_add_file_open_error: + fclose(f); settings_msgbox(MBX_ERROR, (existing & 1) ? (wchar_t *)IDS_4107 : (wchar_t *)IDS_4108); return TRUE; } @@ -2809,7 +2884,6 @@ hdd_add_file_open_error: } else { fseeko64(f, 0, SEEK_END); size = ftello64(f); - fclose(f); if (((size % 17) == 0) && (size <= 142606336)) { spt = 17; if (size <= 26738688) @@ -2857,8 +2931,9 @@ hdd_add_file_open_error: chs_enabled = 1; no_update = 0; - } else - fclose(f); + } + + fclose(f); } h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); @@ -3396,7 +3471,7 @@ win_settings_floppy_drives_recalc_list(HWND hwndList) { LVITEM lvI; int i = 0; - char s[256]; + char s[256], *t; WCHAR szText[256]; lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; @@ -3405,7 +3480,11 @@ win_settings_floppy_drives_recalc_list(HWND hwndList) for (i = 0; i < 4; i++) { lvI.iSubItem = 0; if (temp_fdd_types[i] > 0) { - strcpy(s, fdd_getname(temp_fdd_types[i])); + t = fdd_getname(temp_fdd_types[i]); + if (strlen(t) <= 256) + strcpy(s, t); + else + strncpy(s, t, 256); mbstowcs(szText, s, strlen(s) + 1); lvI.pszText = szText; } else @@ -3660,7 +3739,7 @@ static void win_settings_floppy_drives_update_item(HWND hwndList, int i) { LVITEM lvI; - char s[256]; + char s[256], *t; WCHAR szText[256]; lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; @@ -3670,7 +3749,11 @@ win_settings_floppy_drives_update_item(HWND hwndList, int i) lvI.iItem = i; if (temp_fdd_types[i] > 0) { - strcpy(s, fdd_getname(temp_fdd_types[i])); + t = fdd_getname(temp_fdd_types[i]); + if (strlen(t) <= 256) + strcpy(s, t); + else + strncpy(s, t, 256); mbstowcs(szText, s, strlen(s) + 1); lvI.pszText = szText; } else diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 4e99eebb4..a189fa87b 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -59,8 +59,8 @@ int infocus = 1; int rctrl_is_lalt = 0; int user_resize = 0; -char openfilestring[260]; -WCHAR wopenfilestring[260]; +char openfilestring[512]; +WCHAR wopenfilestring[512]; /* Local data. */ @@ -628,8 +628,6 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) plat_vidapi_enable(0); temp_y -= sbar_height; - if (temp_x < 1) - temp_x = 1; if (temp_y < 1) temp_y = 1; @@ -1079,9 +1077,12 @@ wchar_t * ui_window_title(wchar_t *s) { if (! video_fullscreen) { - if (s != NULL) - wcscpy(wTitle, s); - else + if (s != NULL) { + if (wcslen(s) <= 512) + wcscpy(wTitle, s); + else + wcsncpy(wTitle, s, 512); + } else s = wTitle; SetWindowText(hwndMain, s); @@ -1099,7 +1100,7 @@ void plat_pause(int p) { static wchar_t oldtitle[512]; - wchar_t title[512]; + wchar_t title[512], *t; /* If un-pausing, as the renderer if that's OK. */ if (p == 0) @@ -1115,7 +1116,11 @@ plat_pause(int p) } if (p) { - wcscpy(oldtitle, ui_window_title(NULL)); + t = ui_window_title(NULL); + if (wcslen(t) <= 511) + wcscpy(oldtitle, ui_window_title(NULL)); + else + wcsncpy(oldtitle, ui_window_title(NULL), 511); wcscpy(title, oldtitle); wcscat(title, L" - PAUSED -"); ui_window_title(title);